1 /*
2 * buf.c: memory buffers for libxml2
3 *
4 * new buffer structures and entry points to simplify the maintenance
5 * of libxml2 and ensure we keep good control over memory allocations
6 * and stay 64 bits clean.
7 * The new entry point use the xmlBufPtr opaque structure and
8 * xmlBuf...() counterparts to the old xmlBuf...() functions
9 *
10 * See Copyright for the status of this software.
11 *
12 * [email protected]
13 */
14
15 #define IN_LIBXML
16 #include "libxml.h"
17
18 #include <string.h> /* for memset() only ! */
19 #include <limits.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22
23 #include <libxml/tree.h>
24 #include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
25
26 #include "private/buf.h"
27 #include "private/error.h"
28
29 #ifndef SIZE_MAX
30 #define SIZE_MAX ((size_t) -1)
31 #endif
32
33 #define WITH_BUFFER_COMPAT
34
35 /**
36 * xmlBuf:
37 *
38 * A buffer structure. The base of the structure is somehow compatible
39 * with struct _xmlBuffer to limit risks on application which accessed
40 * directly the input->buf->buffer structures.
41 */
42
43 struct _xmlBuf {
44 xmlChar *content; /* The buffer content UTF8 */
45 unsigned int compat_use; /* for binary compatibility */
46 unsigned int compat_size; /* for binary compatibility */
47 xmlBufferAllocationScheme alloc; /* The realloc method */
48 xmlChar *contentIO; /* in IO mode we may have a different base */
49 size_t use; /* The buffer size used */
50 size_t size; /* The buffer size */
51 xmlBufferPtr buffer; /* wrapper for an old buffer */
52 int error; /* an error code if a failure occurred */
53 };
54
55 #ifdef WITH_BUFFER_COMPAT
56 /*
57 * Macro for compatibility with xmlBuffer to be used after an xmlBuf
58 * is updated. This makes sure the compat fields are updated too.
59 */
60 #define UPDATE_COMPAT(buf) \
61 if (buf->size < INT_MAX) buf->compat_size = buf->size; \
62 else buf->compat_size = INT_MAX; \
63 if (buf->use < INT_MAX) buf->compat_use = buf->use; \
64 else buf->compat_use = INT_MAX;
65
66 /*
67 * Macro for compatibility with xmlBuffer to be used in all the xmlBuf
68 * entry points, it checks that the compat fields have not been modified
69 * by direct call to xmlBuffer function from code compiled before 2.9.0 .
70 */
71 #define CHECK_COMPAT(buf) \
72 if (buf->size != (size_t) buf->compat_size) \
73 if (buf->compat_size < INT_MAX) \
74 buf->size = buf->compat_size; \
75 if (buf->use != (size_t) buf->compat_use) \
76 if (buf->compat_use < INT_MAX) \
77 buf->use = buf->compat_use;
78
79 #else /* ! WITH_BUFFER_COMPAT */
80 #define UPDATE_COMPAT(buf)
81 #define CHECK_COMPAT(buf)
82 #endif /* WITH_BUFFER_COMPAT */
83
84 /**
85 * xmlBufMemoryError:
86 * @extra: extra information
87 *
88 * Handle an out of memory condition
89 * To be improved...
90 */
91 static void
xmlBufMemoryError(xmlBufPtr buf)92 xmlBufMemoryError(xmlBufPtr buf)
93 {
94 if (buf->error == 0)
95 buf->error = XML_ERR_NO_MEMORY;
96 }
97
98 /**
99 * xmlBufOverflowError:
100 * @extra: extra information
101 *
102 * Handle a buffer overflow error
103 * To be improved...
104 */
105 static void
xmlBufOverflowError(xmlBufPtr buf)106 xmlBufOverflowError(xmlBufPtr buf)
107 {
108 if (buf->error == 0)
109 buf->error = XML_BUF_OVERFLOW;
110 }
111
112
113 /**
114 * xmlBufCreate:
115 *
116 * routine to create an XML buffer.
117 * returns the new structure.
118 */
119 xmlBufPtr
xmlBufCreate(void)120 xmlBufCreate(void) {
121 xmlBufPtr ret;
122
123 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
124 if (ret == NULL)
125 return(NULL);
126 ret->use = 0;
127 ret->error = 0;
128 ret->buffer = NULL;
129 ret->size = xmlDefaultBufferSize;
130 UPDATE_COMPAT(ret);
131 ret->alloc = xmlBufferAllocScheme;
132 ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
133 if (ret->content == NULL) {
134 xmlFree(ret);
135 return(NULL);
136 }
137 ret->content[0] = 0;
138 ret->contentIO = NULL;
139 return(ret);
140 }
141
142 /**
143 * xmlBufCreateSize:
144 * @size: initial size of buffer
145 *
146 * routine to create an XML buffer.
147 * returns the new structure.
148 */
149 xmlBufPtr
xmlBufCreateSize(size_t size)150 xmlBufCreateSize(size_t size) {
151 xmlBufPtr ret;
152
153 if (size == SIZE_MAX)
154 return(NULL);
155 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
156 if (ret == NULL)
157 return(NULL);
158 ret->use = 0;
159 ret->error = 0;
160 ret->buffer = NULL;
161 ret->alloc = xmlBufferAllocScheme;
162 ret->size = (size ? size + 1 : 0); /* +1 for ending null */
163 UPDATE_COMPAT(ret);
164 if (ret->size){
165 ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
166 if (ret->content == NULL) {
167 xmlFree(ret);
168 return(NULL);
169 }
170 ret->content[0] = 0;
171 } else
172 ret->content = NULL;
173 ret->contentIO = NULL;
174 return(ret);
175 }
176
177 /**
178 * xmlBufDetach:
179 * @buf: the buffer
180 *
181 * Remove the string contained in a buffer and give it back to the
182 * caller. The buffer is reset to an empty content.
183 * This doesn't work with immutable buffers as they can't be reset.
184 *
185 * Returns the previous string contained by the buffer.
186 */
187 xmlChar *
xmlBufDetach(xmlBufPtr buf)188 xmlBufDetach(xmlBufPtr buf) {
189 xmlChar *ret;
190
191 if (buf == NULL)
192 return(NULL);
193 if (buf->buffer != NULL)
194 return(NULL);
195 if (buf->error)
196 return(NULL);
197
198 ret = buf->content;
199 buf->content = NULL;
200 buf->size = 0;
201 buf->use = 0;
202 UPDATE_COMPAT(buf);
203
204 return ret;
205 }
206
207 /**
208 * xmlBufGetAllocationScheme:
209 * @buf: the buffer
210 *
211 * Get the buffer allocation scheme
212 *
213 * Returns the scheme or -1 in case of error
214 */
215 int
xmlBufGetAllocationScheme(xmlBufPtr buf)216 xmlBufGetAllocationScheme(xmlBufPtr buf) {
217 if (buf == NULL) {
218 return(-1);
219 }
220 return(buf->alloc);
221 }
222
223 /**
224 * xmlBufSetAllocationScheme:
225 * @buf: the buffer to tune
226 * @scheme: allocation scheme to use
227 *
228 * Sets the allocation scheme for this buffer
229 *
230 * returns 0 in case of success and -1 in case of failure
231 */
232 int
xmlBufSetAllocationScheme(xmlBufPtr buf,xmlBufferAllocationScheme scheme)233 xmlBufSetAllocationScheme(xmlBufPtr buf,
234 xmlBufferAllocationScheme scheme) {
235 if ((buf == NULL) || (buf->error != 0)) {
236 return(-1);
237 }
238 if (buf->alloc == XML_BUFFER_ALLOC_IO)
239 return(-1);
240 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
241 (scheme == XML_BUFFER_ALLOC_EXACT) ||
242 (scheme == XML_BUFFER_ALLOC_HYBRID) ||
243 (scheme == XML_BUFFER_ALLOC_BOUNDED)) {
244 buf->alloc = scheme;
245 if (buf->buffer)
246 buf->buffer->alloc = scheme;
247 return(0);
248 }
249 /*
250 * Switching a buffer ALLOC_IO has the side effect of initializing
251 * the contentIO field with the current content
252 */
253 if (scheme == XML_BUFFER_ALLOC_IO) {
254 buf->alloc = XML_BUFFER_ALLOC_IO;
255 buf->contentIO = buf->content;
256 }
257 return(-1);
258 }
259
260 /**
261 * xmlBufFree:
262 * @buf: the buffer to free
263 *
264 * Frees an XML buffer. It frees both the content and the structure which
265 * encapsulate it.
266 */
267 void
xmlBufFree(xmlBufPtr buf)268 xmlBufFree(xmlBufPtr buf) {
269 if (buf == NULL) {
270 return;
271 }
272
273 if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
274 (buf->contentIO != NULL)) {
275 xmlFree(buf->contentIO);
276 } else if (buf->content != NULL) {
277 xmlFree(buf->content);
278 }
279 xmlFree(buf);
280 }
281
282 /**
283 * xmlBufEmpty:
284 * @buf: the buffer
285 *
286 * empty a buffer.
287 */
288 void
xmlBufEmpty(xmlBufPtr buf)289 xmlBufEmpty(xmlBufPtr buf) {
290 if ((buf == NULL) || (buf->error != 0)) return;
291 if (buf->content == NULL) return;
292 CHECK_COMPAT(buf)
293 buf->use = 0;
294 if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
295 (buf->contentIO != NULL)) {
296 size_t start_buf = buf->content - buf->contentIO;
297
298 buf->size += start_buf;
299 buf->content = buf->contentIO;
300 buf->content[0] = 0;
301 } else {
302 buf->content[0] = 0;
303 }
304 UPDATE_COMPAT(buf)
305 }
306
307 /**
308 * xmlBufShrink:
309 * @buf: the buffer to dump
310 * @len: the number of xmlChar to remove
311 *
312 * Remove the beginning of an XML buffer.
313 * NOTE that this routine behaviour differs from xmlBufferShrink()
314 * as it will return 0 on error instead of -1 due to size_t being
315 * used as the return type.
316 *
317 * Returns the number of byte removed or 0 in case of failure
318 */
319 size_t
xmlBufShrink(xmlBufPtr buf,size_t len)320 xmlBufShrink(xmlBufPtr buf, size_t len) {
321 if ((buf == NULL) || (buf->error != 0)) return(0);
322 CHECK_COMPAT(buf)
323 if (len == 0) return(0);
324 if (len > buf->use) return(0);
325
326 buf->use -= len;
327 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
328 /*
329 * we just move the content pointer, but also make sure
330 * the perceived buffer size has shrunk accordingly
331 */
332 buf->content += len;
333 buf->size -= len;
334
335 /*
336 * sometimes though it maybe be better to really shrink
337 * on IO buffers
338 */
339 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
340 size_t start_buf = buf->content - buf->contentIO;
341 if (start_buf >= buf->size) {
342 memmove(buf->contentIO, &buf->content[0], buf->use);
343 buf->content = buf->contentIO;
344 buf->content[buf->use] = 0;
345 buf->size += start_buf;
346 }
347 }
348 } else {
349 memmove(buf->content, &buf->content[len], buf->use);
350 buf->content[buf->use] = 0;
351 }
352 UPDATE_COMPAT(buf)
353 return(len);
354 }
355
356 /**
357 * xmlBufGrowInternal:
358 * @buf: the buffer
359 * @len: the minimum free size to allocate
360 *
361 * Grow the available space of an XML buffer, @len is the target value
362 * Error checking should be done on buf->error since using the return
363 * value doesn't work that well
364 *
365 * Returns 0 in case of error or the length made available otherwise
366 */
367 static size_t
xmlBufGrowInternal(xmlBufPtr buf,size_t len)368 xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
369 size_t size;
370 xmlChar *newbuf;
371
372 if ((buf == NULL) || (buf->error != 0)) return(0);
373 CHECK_COMPAT(buf)
374
375 if (len < buf->size - buf->use)
376 return(buf->size - buf->use - 1);
377 if (len >= SIZE_MAX - buf->use) {
378 xmlBufMemoryError(buf);
379 return(0);
380 }
381
382 if (buf->size > (size_t) len) {
383 size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
384 } else {
385 size = buf->use + len;
386 size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
387 }
388
389 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
390 /*
391 * Used to provide parsing limits
392 */
393 if ((buf->use + len + 1 >= XML_MAX_TEXT_LENGTH) ||
394 (buf->size >= XML_MAX_TEXT_LENGTH)) {
395 xmlBufMemoryError(buf);
396 return(0);
397 }
398 if (size >= XML_MAX_TEXT_LENGTH)
399 size = XML_MAX_TEXT_LENGTH;
400 }
401 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
402 size_t start_buf = buf->content - buf->contentIO;
403
404 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
405 if (newbuf == NULL) {
406 xmlBufMemoryError(buf);
407 return(0);
408 }
409 buf->contentIO = newbuf;
410 buf->content = newbuf + start_buf;
411 } else {
412 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
413 if (newbuf == NULL) {
414 xmlBufMemoryError(buf);
415 return(0);
416 }
417 buf->content = newbuf;
418 }
419 buf->size = size;
420 UPDATE_COMPAT(buf)
421 return(buf->size - buf->use - 1);
422 }
423
424 /**
425 * xmlBufGrow:
426 * @buf: the buffer
427 * @len: the minimum free size to allocate
428 *
429 * Grow the available space of an XML buffer, @len is the target value
430 * This is been kept compatible with xmlBufferGrow() as much as possible
431 *
432 * Returns -1 in case of error or the length made available otherwise
433 */
434 int
xmlBufGrow(xmlBufPtr buf,int len)435 xmlBufGrow(xmlBufPtr buf, int len) {
436 size_t ret;
437
438 if ((buf == NULL) || (len < 0)) return(-1);
439 if (len == 0)
440 return(0);
441 ret = xmlBufGrowInternal(buf, len);
442 if (buf->error != 0)
443 return(-1);
444 return(ret > INT_MAX ? INT_MAX : ret);
445 }
446
447 /**
448 * xmlBufDump:
449 * @file: the file output
450 * @buf: the buffer to dump
451 *
452 * Dumps an XML buffer to a FILE *.
453 * Returns the number of #xmlChar written
454 */
455 size_t
xmlBufDump(FILE * file,xmlBufPtr buf)456 xmlBufDump(FILE *file, xmlBufPtr buf) {
457 size_t ret;
458
459 if ((buf == NULL) || (buf->error != 0)) {
460 return(0);
461 }
462 if (buf->content == NULL) {
463 return(0);
464 }
465 CHECK_COMPAT(buf)
466 if (file == NULL)
467 file = stdout;
468 ret = fwrite(buf->content, 1, buf->use, file);
469 return(ret);
470 }
471
472 /**
473 * xmlBufContent:
474 * @buf: the buffer
475 *
476 * Function to extract the content of a buffer
477 *
478 * Returns the internal content
479 */
480
481 xmlChar *
xmlBufContent(const xmlBuf * buf)482 xmlBufContent(const xmlBuf *buf)
483 {
484 if ((!buf) || (buf->error))
485 return NULL;
486
487 return(buf->content);
488 }
489
490 /**
491 * xmlBufEnd:
492 * @buf: the buffer
493 *
494 * Function to extract the end of the content of a buffer
495 *
496 * Returns the end of the internal content or NULL in case of error
497 */
498
499 xmlChar *
xmlBufEnd(xmlBufPtr buf)500 xmlBufEnd(xmlBufPtr buf)
501 {
502 if ((!buf) || (buf->error))
503 return NULL;
504 CHECK_COMPAT(buf)
505
506 return(&buf->content[buf->use]);
507 }
508
509 /**
510 * xmlBufAddLen:
511 * @buf: the buffer
512 * @len: the size which were added at the end
513 *
514 * Sometime data may be added at the end of the buffer without
515 * using the xmlBuf APIs that is used to expand the used space
516 * and set the zero terminating at the end of the buffer
517 *
518 * Returns -1 in case of error and 0 otherwise
519 */
520 int
xmlBufAddLen(xmlBufPtr buf,size_t len)521 xmlBufAddLen(xmlBufPtr buf, size_t len) {
522 if ((buf == NULL) || (buf->error))
523 return(-1);
524 CHECK_COMPAT(buf)
525 if (len >= (buf->size - buf->use))
526 return(-1);
527 buf->use += len;
528 buf->content[buf->use] = 0;
529 UPDATE_COMPAT(buf)
530 return(0);
531 }
532
533 /**
534 * xmlBufLength:
535 * @buf: the buffer
536 *
537 * Function to get the length of a buffer
538 *
539 * Returns the length of data in the internal content
540 */
541
542 size_t
xmlBufLength(const xmlBufPtr buf)543 xmlBufLength(const xmlBufPtr buf)
544 {
545 if ((!buf) || (buf->error))
546 return 0;
547 CHECK_COMPAT(buf)
548
549 return(buf->use);
550 }
551
552 /**
553 * xmlBufUse:
554 * @buf: the buffer
555 *
556 * Function to get the length of a buffer
557 *
558 * Returns the length of data in the internal content
559 */
560
561 size_t
xmlBufUse(const xmlBufPtr buf)562 xmlBufUse(const xmlBufPtr buf)
563 {
564 if ((!buf) || (buf->error))
565 return 0;
566 CHECK_COMPAT(buf)
567
568 return(buf->use);
569 }
570
571 /**
572 * xmlBufAvail:
573 * @buf: the buffer
574 *
575 * Function to find how much free space is allocated but not
576 * used in the buffer. It reserves one byte for the NUL
577 * terminator character that is usually needed, so there is
578 * no need to subtract 1 from the result anymore.
579 *
580 * Returns the amount, or 0 if none or if an error occurred.
581 */
582
583 size_t
xmlBufAvail(const xmlBufPtr buf)584 xmlBufAvail(const xmlBufPtr buf)
585 {
586 if ((!buf) || (buf->error))
587 return 0;
588 CHECK_COMPAT(buf)
589
590 return((buf->size > buf->use) ? (buf->size - buf->use - 1) : 0);
591 }
592
593 /**
594 * xmlBufIsEmpty:
595 * @buf: the buffer
596 *
597 * Tell if a buffer is empty
598 *
599 * Returns 0 if no, 1 if yes and -1 in case of error
600 */
601 int
xmlBufIsEmpty(const xmlBufPtr buf)602 xmlBufIsEmpty(const xmlBufPtr buf)
603 {
604 if ((!buf) || (buf->error))
605 return(-1);
606 CHECK_COMPAT(buf)
607
608 return(buf->use == 0);
609 }
610
611 /**
612 * xmlBufResize:
613 * @buf: the buffer to resize
614 * @size: the desired size
615 *
616 * Resize a buffer to accommodate minimum size of @size.
617 *
618 * Returns 0 in case of problems, 1 otherwise
619 */
620 int
xmlBufResize(xmlBufPtr buf,size_t size)621 xmlBufResize(xmlBufPtr buf, size_t size)
622 {
623 size_t newSize;
624 xmlChar* rebuf = NULL;
625 size_t start_buf;
626
627 if ((buf == NULL) || (buf->error))
628 return(0);
629 CHECK_COMPAT(buf)
630
631 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
632 /*
633 * Used to provide parsing limits
634 */
635 if (size >= XML_MAX_TEXT_LENGTH) {
636 xmlBufMemoryError(buf);
637 return(0);
638 }
639 }
640
641 /* Don't resize if we don't have to */
642 if (size < buf->size)
643 return 1;
644
645 /* figure out new size */
646 switch (buf->alloc){
647 case XML_BUFFER_ALLOC_IO:
648 case XML_BUFFER_ALLOC_DOUBLEIT:
649 /*take care of empty case*/
650 if (buf->size == 0) {
651 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
652 } else {
653 newSize = buf->size;
654 }
655 while (size > newSize) {
656 if (newSize > SIZE_MAX / 2) {
657 xmlBufMemoryError(buf);
658 return 0;
659 }
660 newSize *= 2;
661 }
662 break;
663 case XML_BUFFER_ALLOC_EXACT:
664 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
665 break;
666 case XML_BUFFER_ALLOC_HYBRID:
667 if (buf->use < BASE_BUFFER_SIZE)
668 newSize = size;
669 else {
670 newSize = buf->size;
671 while (size > newSize) {
672 if (newSize > SIZE_MAX / 2) {
673 xmlBufMemoryError(buf);
674 return 0;
675 }
676 newSize *= 2;
677 }
678 }
679 break;
680
681 default:
682 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
683 break;
684 }
685
686 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
687 start_buf = buf->content - buf->contentIO;
688
689 if (start_buf > newSize) {
690 /* move data back to start */
691 memmove(buf->contentIO, buf->content, buf->use);
692 buf->content = buf->contentIO;
693 buf->content[buf->use] = 0;
694 buf->size += start_buf;
695 } else {
696 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
697 if (rebuf == NULL) {
698 xmlBufMemoryError(buf);
699 return 0;
700 }
701 buf->contentIO = rebuf;
702 buf->content = rebuf + start_buf;
703 }
704 } else {
705 if (buf->content == NULL) {
706 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
707 buf->use = 0;
708 if (rebuf != NULL)
709 rebuf[buf->use] = 0;
710 } else if (buf->size - buf->use < 100) {
711 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
712 } else {
713 /*
714 * if we are reallocating a buffer far from being full, it's
715 * better to make a new allocation and copy only the used range
716 * and free the old one.
717 */
718 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
719 if (rebuf != NULL) {
720 memcpy(rebuf, buf->content, buf->use);
721 xmlFree(buf->content);
722 rebuf[buf->use] = 0;
723 }
724 }
725 if (rebuf == NULL) {
726 xmlBufMemoryError(buf);
727 return 0;
728 }
729 buf->content = rebuf;
730 }
731 buf->size = newSize;
732 UPDATE_COMPAT(buf)
733
734 return 1;
735 }
736
737 /**
738 * xmlBufAdd:
739 * @buf: the buffer to dump
740 * @str: the #xmlChar string
741 * @len: the number of #xmlChar to add
742 *
743 * Add a string range to an XML buffer. if len == -1, the length of
744 * str is recomputed.
745 *
746 * Returns 0 successful, a positive error code number otherwise
747 * and -1 in case of internal or API error.
748 */
749 int
xmlBufAdd(xmlBufPtr buf,const xmlChar * str,int len)750 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
751 size_t needSize;
752
753 if ((str == NULL) || (buf == NULL) || (buf->error))
754 return -1;
755 CHECK_COMPAT(buf)
756
757 if (len < -1) {
758 return -1;
759 }
760 if (len == 0) return 0;
761
762 if (len < 0)
763 len = xmlStrlen(str);
764
765 if (len < 0) return -1;
766 if (len == 0) return 0;
767
768 /* Note that both buf->size and buf->use can be zero here. */
769 if ((size_t) len >= buf->size - buf->use) {
770 if ((size_t) len >= SIZE_MAX - buf->use) {
771 xmlBufMemoryError(buf);
772 return(-1);
773 }
774 needSize = buf->use + len + 1;
775 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
776 /*
777 * Used to provide parsing limits
778 */
779 if (needSize >= XML_MAX_TEXT_LENGTH) {
780 xmlBufMemoryError(buf);
781 return(-1);
782 }
783 }
784 if (!xmlBufResize(buf, needSize)){
785 xmlBufMemoryError(buf);
786 return XML_ERR_NO_MEMORY;
787 }
788 }
789
790 memmove(&buf->content[buf->use], str, len);
791 buf->use += len;
792 buf->content[buf->use] = 0;
793 UPDATE_COMPAT(buf)
794 return 0;
795 }
796
797 /**
798 * xmlBufCat:
799 * @buf: the buffer to add to
800 * @str: the #xmlChar string
801 *
802 * Append a zero terminated string to an XML buffer.
803 *
804 * Returns 0 successful, a positive error code number otherwise
805 * and -1 in case of internal or API error.
806 */
807 int
xmlBufCat(xmlBufPtr buf,const xmlChar * str)808 xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
809 if ((buf == NULL) || (buf->error))
810 return(-1);
811 CHECK_COMPAT(buf)
812 if (str == NULL) return -1;
813 return xmlBufAdd(buf, str, -1);
814 }
815
816 /**
817 * xmlBufCCat:
818 * @buf: the buffer to dump
819 * @str: the C char string
820 *
821 * Append a zero terminated C string to an XML buffer.
822 *
823 * Returns 0 successful, a positive error code number otherwise
824 * and -1 in case of internal or API error.
825 */
826 int
xmlBufCCat(xmlBufPtr buf,const char * str)827 xmlBufCCat(xmlBufPtr buf, const char *str) {
828 return xmlBufCat(buf, (const xmlChar *) str);
829 }
830
831 /**
832 * xmlBufWriteQuotedString:
833 * @buf: the XML buffer output
834 * @string: the string to add
835 *
836 * routine which manage and grows an output buffer. This one writes
837 * a quoted or double quoted #xmlChar string, checking first if it holds
838 * quote or double-quotes internally
839 *
840 * Returns 0 if successful, a positive error code number otherwise
841 * and -1 in case of internal or API error.
842 */
843 int
xmlBufWriteQuotedString(xmlBufPtr buf,const xmlChar * string)844 xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
845 const xmlChar *cur, *base;
846 if ((buf == NULL) || (buf->error))
847 return(-1);
848 CHECK_COMPAT(buf)
849 if (xmlStrchr(string, '\"')) {
850 if (xmlStrchr(string, '\'')) {
851 xmlBufCCat(buf, "\"");
852 base = cur = string;
853 while(*cur != 0){
854 if(*cur == '"'){
855 if (base != cur)
856 xmlBufAdd(buf, base, cur - base);
857 xmlBufAdd(buf, BAD_CAST """, 6);
858 cur++;
859 base = cur;
860 }
861 else {
862 cur++;
863 }
864 }
865 if (base != cur)
866 xmlBufAdd(buf, base, cur - base);
867 xmlBufCCat(buf, "\"");
868 }
869 else{
870 xmlBufCCat(buf, "\'");
871 xmlBufCat(buf, string);
872 xmlBufCCat(buf, "\'");
873 }
874 } else {
875 xmlBufCCat(buf, "\"");
876 xmlBufCat(buf, string);
877 xmlBufCCat(buf, "\"");
878 }
879 return(0);
880 }
881
882 /**
883 * xmlBufFromBuffer:
884 * @buffer: incoming old buffer to convert to a new one
885 *
886 * Helper routine to switch from the old buffer structures in use
887 * in various APIs. It creates a wrapper xmlBufPtr which will be
888 * used for internal processing until the xmlBufBackToBuffer() is
889 * issued.
890 *
891 * Returns a new xmlBufPtr unless the call failed and NULL is returned
892 */
893 xmlBufPtr
xmlBufFromBuffer(xmlBufferPtr buffer)894 xmlBufFromBuffer(xmlBufferPtr buffer) {
895 xmlBufPtr ret;
896
897 if (buffer == NULL)
898 return(NULL);
899
900 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
901 if (ret == NULL) {
902 return(NULL);
903 }
904 ret->use = buffer->use;
905 ret->size = buffer->size;
906 UPDATE_COMPAT(ret);
907 ret->error = 0;
908 ret->buffer = buffer;
909 ret->alloc = buffer->alloc;
910 ret->content = buffer->content;
911 ret->contentIO = buffer->contentIO;
912
913 return(ret);
914 }
915
916 /**
917 * xmlBufBackToBuffer:
918 * @buf: new buffer wrapping the old one
919 *
920 * Function to be called once internal processing had been done to
921 * update back the buffer provided by the user. This can lead to
922 * a failure in case the size accumulated in the xmlBuf is larger
923 * than what an xmlBuffer can support on 64 bits (INT_MAX)
924 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
925 *
926 * Returns the old xmlBufferPtr unless the call failed and NULL is returned
927 */
928 xmlBufferPtr
xmlBufBackToBuffer(xmlBufPtr buf)929 xmlBufBackToBuffer(xmlBufPtr buf) {
930 xmlBufferPtr ret;
931
932 if (buf == NULL)
933 return(NULL);
934 CHECK_COMPAT(buf)
935 if ((buf->error) || (buf->buffer == NULL)) {
936 xmlBufFree(buf);
937 return(NULL);
938 }
939
940 ret = buf->buffer;
941 /*
942 * What to do in case of error in the buffer ???
943 */
944 if (buf->use > INT_MAX) {
945 /*
946 * Worse case, we really allocated and used more than the
947 * maximum allowed memory for an xmlBuffer on this architecture.
948 * Keep the buffer but provide a truncated size value.
949 */
950 xmlBufOverflowError(buf);
951 ret->use = INT_MAX;
952 ret->size = INT_MAX;
953 } else if (buf->size > INT_MAX) {
954 /*
955 * milder case, we allocated more than the maximum allowed memory
956 * for an xmlBuffer on this architecture, but used less than the
957 * limit.
958 * Keep the buffer but provide a truncated size value.
959 */
960 xmlBufOverflowError(buf);
961 ret->use = buf->use;
962 ret->size = INT_MAX;
963 } else {
964 ret->use = buf->use;
965 ret->size = buf->size;
966 }
967 ret->alloc = buf->alloc;
968 ret->content = buf->content;
969 ret->contentIO = buf->contentIO;
970 xmlFree(buf);
971 return(ret);
972 }
973
974 /**
975 * xmlBufResetInput:
976 * @buf: an xmlBufPtr
977 * @input: an xmlParserInputPtr
978 *
979 * Update the input to use the current set of pointers from the buffer.
980 *
981 * Returns -1 in case of error, 0 otherwise
982 */
983 int
xmlBufResetInput(xmlBufPtr buf,xmlParserInputPtr input)984 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
985 return(xmlBufUpdateInput(buf, input, 0));
986 }
987
988 /**
989 * xmlBufUpdateInput:
990 * @buf: an xmlBufPtr
991 * @input: an xmlParserInputPtr
992 * @pos: the cur value relative to the beginning of the buffer
993 *
994 * Update the input to use the base and cur relative to the buffer
995 * after a possible reallocation of its content
996 *
997 * Returns -1 in case of error, 0 otherwise
998 */
999 int
xmlBufUpdateInput(xmlBufPtr buf,xmlParserInputPtr input,size_t pos)1000 xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
1001 if ((buf == NULL) || (input == NULL))
1002 return(-1);
1003 CHECK_COMPAT(buf)
1004 input->base = buf->content;
1005 input->cur = input->base + pos;
1006 input->end = &buf->content[buf->use];
1007 return(0);
1008 }
1009
1010