VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/buf.c@ 102340

Last change on this file since 102340 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • Property svn:eol-style set to native
File size: 33.0 KB
Line 
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
47struct _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 */
95static void
96xmlBufMemoryError(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 */
110static void
111xmlBufOverflowError(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 */
125xmlBufPtr
126xmlBufCreate(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 */
159xmlBufPtr
160xmlBufCreateSize(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 */
201xmlChar *
202xmlBufDetach(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 */
236xmlBufPtr
237xmlBufCreateStatic(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 */
272int
273xmlBufGetAllocationScheme(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 */
293int
294xmlBufSetAllocationScheme(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 */
334void
335xmlBufFree(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 */
360void
361xmlBufEmpty(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 */
393size_t
394xmlBufShrink(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 */
442static size_t
443xmlBufGrowInternal(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 if (len > SIZE_MAX - buf->use)
454 return(0);
455
456 if (buf->size > (size_t) len) {
457 size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
458 } else {
459 size = buf->use + len;
460 size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
461 }
462
463 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
464 /*
465 * Used to provide parsing limits
466 */
467 if ((buf->use + len >= XML_MAX_TEXT_LENGTH) ||
468 (buf->size >= XML_MAX_TEXT_LENGTH)) {
469 xmlBufMemoryError(buf, "buffer error: text too long\n");
470 return(0);
471 }
472 if (size >= XML_MAX_TEXT_LENGTH)
473 size = XML_MAX_TEXT_LENGTH;
474 }
475 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
476 size_t start_buf = buf->content - buf->contentIO;
477
478 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
479 if (newbuf == NULL) {
480 xmlBufMemoryError(buf, "growing buffer");
481 return(0);
482 }
483 buf->contentIO = newbuf;
484 buf->content = newbuf + start_buf;
485 } else {
486 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
487 if (newbuf == NULL) {
488 xmlBufMemoryError(buf, "growing buffer");
489 return(0);
490 }
491 buf->content = newbuf;
492 }
493 buf->size = size;
494 UPDATE_COMPAT(buf)
495 return(buf->size - buf->use);
496}
497
498/**
499 * xmlBufGrow:
500 * @buf: the buffer
501 * @len: the minimum free size to allocate
502 *
503 * Grow the available space of an XML buffer, @len is the target value
504 * This is been kept compatible with xmlBufferGrow() as much as possible
505 *
506 * Returns -1 in case of error or the length made available otherwise
507 */
508int
509xmlBufGrow(xmlBufPtr buf, int len) {
510 size_t ret;
511
512 if ((buf == NULL) || (len < 0)) return(-1);
513 if (len == 0)
514 return(0);
515 ret = xmlBufGrowInternal(buf, len);
516 if (buf->error != 0)
517 return(-1);
518 return((int) ret);
519}
520
521/**
522 * xmlBufInflate:
523 * @buf: the buffer
524 * @len: the minimum extra free size to allocate
525 *
526 * Grow the available space of an XML buffer, adding at least @len bytes
527 *
528 * Returns 0 if successful or -1 in case of error
529 */
530int
531xmlBufInflate(xmlBufPtr buf, size_t len) {
532 if (buf == NULL) return(-1);
533 xmlBufGrowInternal(buf, len + buf->size);
534 if (buf->error)
535 return(-1);
536 return(0);
537}
538
539/**
540 * xmlBufDump:
541 * @file: the file output
542 * @buf: the buffer to dump
543 *
544 * Dumps an XML buffer to a FILE *.
545 * Returns the number of #xmlChar written
546 */
547size_t
548xmlBufDump(FILE *file, xmlBufPtr buf) {
549 size_t ret;
550
551 if ((buf == NULL) || (buf->error != 0)) {
552#ifdef DEBUG_BUFFER
553 xmlGenericError(xmlGenericErrorContext,
554 "xmlBufDump: buf == NULL or in error\n");
555#endif
556 return(0);
557 }
558 if (buf->content == NULL) {
559#ifdef DEBUG_BUFFER
560 xmlGenericError(xmlGenericErrorContext,
561 "xmlBufDump: buf->content == NULL\n");
562#endif
563 return(0);
564 }
565 CHECK_COMPAT(buf)
566 if (file == NULL)
567 file = stdout;
568 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
569 return(ret);
570}
571
572/**
573 * xmlBufContent:
574 * @buf: the buffer
575 *
576 * Function to extract the content of a buffer
577 *
578 * Returns the internal content
579 */
580
581xmlChar *
582xmlBufContent(const xmlBuf *buf)
583{
584 if ((!buf) || (buf->error))
585 return NULL;
586
587 return(buf->content);
588}
589
590/**
591 * xmlBufEnd:
592 * @buf: the buffer
593 *
594 * Function to extract the end of the content of a buffer
595 *
596 * Returns the end of the internal content or NULL in case of error
597 */
598
599xmlChar *
600xmlBufEnd(xmlBufPtr buf)
601{
602 if ((!buf) || (buf->error))
603 return NULL;
604 CHECK_COMPAT(buf)
605
606 return(&buf->content[buf->use]);
607}
608
609/**
610 * xmlBufAddLen:
611 * @buf: the buffer
612 * @len: the size which were added at the end
613 *
614 * Sometime data may be added at the end of the buffer without
615 * using the xmlBuf APIs that is used to expand the used space
616 * and set the zero terminating at the end of the buffer
617 *
618 * Returns -1 in case of error and 0 otherwise
619 */
620int
621xmlBufAddLen(xmlBufPtr buf, size_t len) {
622 if ((buf == NULL) || (buf->error))
623 return(-1);
624 CHECK_COMPAT(buf)
625 if (len > (buf->size - buf->use))
626 return(-1);
627 buf->use += len;
628 UPDATE_COMPAT(buf)
629 if (buf->size > buf->use)
630 buf->content[buf->use] = 0;
631 else
632 return(-1);
633 return(0);
634}
635
636/**
637 * xmlBufErase:
638 * @buf: the buffer
639 * @len: the size to erase at the end
640 *
641 * Sometime data need to be erased at the end of the buffer
642 *
643 * Returns -1 in case of error and 0 otherwise
644 */
645int
646xmlBufErase(xmlBufPtr buf, size_t len) {
647 if ((buf == NULL) || (buf->error))
648 return(-1);
649 CHECK_COMPAT(buf)
650 if (len > buf->use)
651 return(-1);
652 buf->use -= len;
653 buf->content[buf->use] = 0;
654 UPDATE_COMPAT(buf)
655 return(0);
656}
657
658/**
659 * xmlBufLength:
660 * @buf: the buffer
661 *
662 * Function to get the length of a buffer
663 *
664 * Returns the length of data in the internal content
665 */
666
667size_t
668xmlBufLength(const xmlBufPtr buf)
669{
670 if ((!buf) || (buf->error))
671 return 0;
672 CHECK_COMPAT(buf)
673
674 return(buf->use);
675}
676
677/**
678 * xmlBufUse:
679 * @buf: the buffer
680 *
681 * Function to get the length of a buffer
682 *
683 * Returns the length of data in the internal content
684 */
685
686size_t
687xmlBufUse(const xmlBufPtr buf)
688{
689 if ((!buf) || (buf->error))
690 return 0;
691 CHECK_COMPAT(buf)
692
693 return(buf->use);
694}
695
696/**
697 * xmlBufAvail:
698 * @buf: the buffer
699 *
700 * Function to find how much free space is allocated but not
701 * used in the buffer. It does not account for the terminating zero
702 * usually needed
703 *
704 * Returns the amount or 0 if none or an error occurred
705 */
706
707size_t
708xmlBufAvail(const xmlBufPtr buf)
709{
710 if ((!buf) || (buf->error))
711 return 0;
712 CHECK_COMPAT(buf)
713
714 return(buf->size - buf->use);
715}
716
717/**
718 * xmlBufIsEmpty:
719 * @buf: the buffer
720 *
721 * Tell if a buffer is empty
722 *
723 * Returns 0 if no, 1 if yes and -1 in case of error
724 */
725int
726xmlBufIsEmpty(const xmlBufPtr buf)
727{
728 if ((!buf) || (buf->error))
729 return(-1);
730 CHECK_COMPAT(buf)
731
732 return(buf->use == 0);
733}
734
735/**
736 * xmlBufResize:
737 * @buf: the buffer to resize
738 * @size: the desired size
739 *
740 * Resize a buffer to accommodate minimum size of @size.
741 *
742 * Returns 0 in case of problems, 1 otherwise
743 */
744int
745xmlBufResize(xmlBufPtr buf, size_t size)
746{
747 size_t newSize;
748 xmlChar* rebuf = NULL;
749 size_t start_buf;
750
751 if ((buf == NULL) || (buf->error))
752 return(0);
753 CHECK_COMPAT(buf)
754
755 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
756 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
757 /*
758 * Used to provide parsing limits
759 */
760 if (size >= XML_MAX_TEXT_LENGTH) {
761 xmlBufMemoryError(buf, "buffer error: text too long\n");
762 return(0);
763 }
764 }
765
766 /* Don't resize if we don't have to */
767 if (size < buf->size)
768 return 1;
769
770 /* figure out new size */
771 switch (buf->alloc){
772 case XML_BUFFER_ALLOC_IO:
773 case XML_BUFFER_ALLOC_DOUBLEIT:
774 /*take care of empty case*/
775 if (buf->size == 0) {
776 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
777 } else {
778 newSize = buf->size;
779 }
780 while (size > newSize) {
781 if (newSize > SIZE_MAX / 2) {
782 xmlBufMemoryError(buf, "growing buffer");
783 return 0;
784 }
785 newSize *= 2;
786 }
787 break;
788 case XML_BUFFER_ALLOC_EXACT:
789 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
790 break;
791 case XML_BUFFER_ALLOC_HYBRID:
792 if (buf->use < BASE_BUFFER_SIZE)
793 newSize = size;
794 else {
795 newSize = buf->size;
796 while (size > newSize) {
797 if (newSize > SIZE_MAX / 2) {
798 xmlBufMemoryError(buf, "growing buffer");
799 return 0;
800 }
801 newSize *= 2;
802 }
803 }
804 break;
805
806 default:
807 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
808 break;
809 }
810
811 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
812 start_buf = buf->content - buf->contentIO;
813
814 if (start_buf > newSize) {
815 /* move data back to start */
816 memmove(buf->contentIO, buf->content, buf->use);
817 buf->content = buf->contentIO;
818 buf->content[buf->use] = 0;
819 buf->size += start_buf;
820 } else {
821 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
822 if (rebuf == NULL) {
823 xmlBufMemoryError(buf, "growing buffer");
824 return 0;
825 }
826 buf->contentIO = rebuf;
827 buf->content = rebuf + start_buf;
828 }
829 } else {
830 if (buf->content == NULL) {
831 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
832 } else if (buf->size - buf->use < 100) {
833 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
834 } else {
835 /*
836 * if we are reallocating a buffer far from being full, it's
837 * better to make a new allocation and copy only the used range
838 * and free the old one.
839 */
840 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
841 if (rebuf != NULL) {
842 memcpy(rebuf, buf->content, buf->use);
843 xmlFree(buf->content);
844 rebuf[buf->use] = 0;
845 }
846 }
847 if (rebuf == NULL) {
848 xmlBufMemoryError(buf, "growing buffer");
849 return 0;
850 }
851 buf->content = rebuf;
852 }
853 buf->size = newSize;
854 UPDATE_COMPAT(buf)
855
856 return 1;
857}
858
859/**
860 * xmlBufAdd:
861 * @buf: the buffer to dump
862 * @str: the #xmlChar string
863 * @len: the number of #xmlChar to add
864 *
865 * Add a string range to an XML buffer. if len == -1, the length of
866 * str is recomputed.
867 *
868 * Returns 0 successful, a positive error code number otherwise
869 * and -1 in case of internal or API error.
870 */
871int
872xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
873 size_t needSize;
874
875 if ((str == NULL) || (buf == NULL) || (buf->error))
876 return -1;
877 CHECK_COMPAT(buf)
878
879 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
880 if (len < -1) {
881#ifdef DEBUG_BUFFER
882 xmlGenericError(xmlGenericErrorContext,
883 "xmlBufAdd: len < 0\n");
884#endif
885 return -1;
886 }
887 if (len == 0) return 0;
888
889 if (len < 0)
890 len = xmlStrlen(str);
891
892 if (len < 0) return -1;
893 if (len == 0) return 0;
894
895 if ((size_t) len >= buf->size - buf->use) {
896 if ((size_t) len >= SIZE_MAX - buf->use)
897 return(-1);
898 needSize = buf->use + len + 1;
899 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
900 /*
901 * Used to provide parsing limits
902 */
903 if (needSize >= XML_MAX_TEXT_LENGTH) {
904 xmlBufMemoryError(buf, "buffer error: text too long\n");
905 return(-1);
906 }
907 }
908 if (!xmlBufResize(buf, needSize)){
909 xmlBufMemoryError(buf, "growing buffer");
910 return XML_ERR_NO_MEMORY;
911 }
912 }
913
914 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
915 buf->use += len;
916 buf->content[buf->use] = 0;
917 UPDATE_COMPAT(buf)
918 return 0;
919}
920
921/**
922 * xmlBufAddHead:
923 * @buf: the buffer
924 * @str: the #xmlChar string
925 * @len: the number of #xmlChar to add
926 *
927 * Add a string range to the beginning of an XML buffer.
928 * if len == -1, the length of @str is recomputed.
929 *
930 * Returns 0 successful, a positive error code number otherwise
931 * and -1 in case of internal or API error.
932 */
933int
934xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
935 unsigned int needSize;
936
937 if ((buf == NULL) || (buf->error))
938 return(-1);
939 CHECK_COMPAT(buf)
940 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
941 if (str == NULL) {
942#ifdef DEBUG_BUFFER
943 xmlGenericError(xmlGenericErrorContext,
944 "xmlBufAddHead: str == NULL\n");
945#endif
946 return -1;
947 }
948 if (len < -1) {
949#ifdef DEBUG_BUFFER
950 xmlGenericError(xmlGenericErrorContext,
951 "xmlBufAddHead: len < 0\n");
952#endif
953 return -1;
954 }
955 if (len == 0) return 0;
956
957 if (len < 0)
958 len = xmlStrlen(str);
959
960 if (len <= 0) return -1;
961
962 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
963 size_t start_buf = buf->content - buf->contentIO;
964
965 if (start_buf > (unsigned int) len) {
966 /*
967 * We can add it in the space previously shrunk
968 */
969 buf->content -= len;
970 memmove(&buf->content[0], str, len);
971 buf->use += len;
972 buf->size += len;
973 UPDATE_COMPAT(buf)
974 return(0);
975 }
976 }
977 needSize = buf->use + len + 2;
978 if (needSize > buf->size){
979 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
980 /*
981 * Used to provide parsing limits
982 */
983 if (needSize >= XML_MAX_TEXT_LENGTH) {
984 xmlBufMemoryError(buf, "buffer error: text too long\n");
985 return(-1);
986 }
987 }
988 if (!xmlBufResize(buf, needSize)){
989 xmlBufMemoryError(buf, "growing buffer");
990 return XML_ERR_NO_MEMORY;
991 }
992 }
993
994 memmove(&buf->content[len], &buf->content[0], buf->use);
995 memmove(&buf->content[0], str, len);
996 buf->use += len;
997 buf->content[buf->use] = 0;
998 UPDATE_COMPAT(buf)
999 return 0;
1000}
1001
1002/**
1003 * xmlBufCat:
1004 * @buf: the buffer to add to
1005 * @str: the #xmlChar string
1006 *
1007 * Append a zero terminated string to an XML buffer.
1008 *
1009 * Returns 0 successful, a positive error code number otherwise
1010 * and -1 in case of internal or API error.
1011 */
1012int
1013xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
1014 if ((buf == NULL) || (buf->error))
1015 return(-1);
1016 CHECK_COMPAT(buf)
1017 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1018 if (str == NULL) return -1;
1019 return xmlBufAdd(buf, str, -1);
1020}
1021
1022/**
1023 * xmlBufCCat:
1024 * @buf: the buffer to dump
1025 * @str: the C char string
1026 *
1027 * Append a zero terminated C string to an XML buffer.
1028 *
1029 * Returns 0 successful, a positive error code number otherwise
1030 * and -1 in case of internal or API error.
1031 */
1032int
1033xmlBufCCat(xmlBufPtr buf, const char *str) {
1034 return xmlBufCat(buf, (const xmlChar *) str);
1035}
1036
1037/**
1038 * xmlBufWriteCHAR:
1039 * @buf: the XML buffer
1040 * @string: the string to add
1041 *
1042 * routine which manages and grows an output buffer. This one adds
1043 * xmlChars at the end of the buffer.
1044 *
1045 * Returns 0 if successful, a positive error code number otherwise
1046 * and -1 in case of internal or API error.
1047 */
1048int
1049xmlBufWriteCHAR(xmlBufPtr buf, const xmlChar *string) {
1050 if ((buf == NULL) || (buf->error))
1051 return(-1);
1052 CHECK_COMPAT(buf)
1053 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1054 return(-1);
1055 return(xmlBufCat(buf, string));
1056}
1057
1058/**
1059 * xmlBufWriteChar:
1060 * @buf: the XML buffer output
1061 * @string: the string to add
1062 *
1063 * routine which manage and grows an output buffer. This one add
1064 * C chars at the end of the array.
1065 *
1066 * Returns 0 if successful, a positive error code number otherwise
1067 * and -1 in case of internal or API error.
1068 */
1069int
1070xmlBufWriteChar(xmlBufPtr buf, const char *string) {
1071 if ((buf == NULL) || (buf->error))
1072 return(-1);
1073 CHECK_COMPAT(buf)
1074 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1075 return(-1);
1076 return(xmlBufCCat(buf, string));
1077}
1078
1079
1080/**
1081 * xmlBufWriteQuotedString:
1082 * @buf: the XML buffer output
1083 * @string: the string to add
1084 *
1085 * routine which manage and grows an output buffer. This one writes
1086 * a quoted or double quoted #xmlChar string, checking first if it holds
1087 * quote or double-quotes internally
1088 *
1089 * Returns 0 if successful, a positive error code number otherwise
1090 * and -1 in case of internal or API error.
1091 */
1092int
1093xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
1094 const xmlChar *cur, *base;
1095 if ((buf == NULL) || (buf->error))
1096 return(-1);
1097 CHECK_COMPAT(buf)
1098 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1099 return(-1);
1100 if (xmlStrchr(string, '\"')) {
1101 if (xmlStrchr(string, '\'')) {
1102#ifdef DEBUG_BUFFER
1103 xmlGenericError(xmlGenericErrorContext,
1104 "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
1105#endif
1106 xmlBufCCat(buf, "\"");
1107 base = cur = string;
1108 while(*cur != 0){
1109 if(*cur == '"'){
1110 if (base != cur)
1111 xmlBufAdd(buf, base, cur - base);
1112 xmlBufAdd(buf, BAD_CAST "&quot;", 6);
1113 cur++;
1114 base = cur;
1115 }
1116 else {
1117 cur++;
1118 }
1119 }
1120 if (base != cur)
1121 xmlBufAdd(buf, base, cur - base);
1122 xmlBufCCat(buf, "\"");
1123 }
1124 else{
1125 xmlBufCCat(buf, "\'");
1126 xmlBufCat(buf, string);
1127 xmlBufCCat(buf, "\'");
1128 }
1129 } else {
1130 xmlBufCCat(buf, "\"");
1131 xmlBufCat(buf, string);
1132 xmlBufCCat(buf, "\"");
1133 }
1134 return(0);
1135}
1136
1137/**
1138 * xmlBufFromBuffer:
1139 * @buffer: incoming old buffer to convert to a new one
1140 *
1141 * Helper routine to switch from the old buffer structures in use
1142 * in various APIs. It creates a wrapper xmlBufPtr which will be
1143 * used for internal processing until the xmlBufBackToBuffer() is
1144 * issued.
1145 *
1146 * Returns a new xmlBufPtr unless the call failed and NULL is returned
1147 */
1148xmlBufPtr
1149xmlBufFromBuffer(xmlBufferPtr buffer) {
1150 xmlBufPtr ret;
1151
1152 if (buffer == NULL)
1153 return(NULL);
1154
1155 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
1156 if (ret == NULL) {
1157 xmlBufMemoryError(NULL, "creating buffer");
1158 return(NULL);
1159 }
1160 ret->use = buffer->use;
1161 ret->size = buffer->size;
1162 ret->compat_use = buffer->use;
1163 ret->compat_size = buffer->size;
1164 ret->error = 0;
1165 ret->buffer = buffer;
1166 ret->alloc = buffer->alloc;
1167 ret->content = buffer->content;
1168 ret->contentIO = buffer->contentIO;
1169
1170 return(ret);
1171}
1172
1173/**
1174 * xmlBufBackToBuffer:
1175 * @buf: new buffer wrapping the old one
1176 *
1177 * Function to be called once internal processing had been done to
1178 * update back the buffer provided by the user. This can lead to
1179 * a failure in case the size accumulated in the xmlBuf is larger
1180 * than what an xmlBuffer can support on 64 bits (INT_MAX)
1181 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
1182 *
1183 * Returns the old xmlBufferPtr unless the call failed and NULL is returned
1184 */
1185xmlBufferPtr
1186xmlBufBackToBuffer(xmlBufPtr buf) {
1187 xmlBufferPtr ret;
1188
1189 if (buf == NULL)
1190 return(NULL);
1191 CHECK_COMPAT(buf)
1192 if ((buf->error) || (buf->buffer == NULL)) {
1193 xmlBufFree(buf);
1194 return(NULL);
1195 }
1196
1197 ret = buf->buffer;
1198 /*
1199 * What to do in case of error in the buffer ???
1200 */
1201 if (buf->use > INT_MAX) {
1202 /*
1203 * Worse case, we really allocated and used more than the
1204 * maximum allowed memory for an xmlBuffer on this architecture.
1205 * Keep the buffer but provide a truncated size value.
1206 */
1207 xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
1208 ret->use = INT_MAX;
1209 ret->size = INT_MAX;
1210 } else if (buf->size > INT_MAX) {
1211 /*
1212 * milder case, we allocated more than the maximum allowed memory
1213 * for an xmlBuffer on this architecture, but used less than the
1214 * limit.
1215 * Keep the buffer but provide a truncated size value.
1216 */
1217 xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
1218 ret->use = (int) buf->use;
1219 ret->size = INT_MAX;
1220 } else {
1221 ret->use = (int) buf->use;
1222 ret->size = (int) buf->size;
1223 }
1224 ret->alloc = buf->alloc;
1225 ret->content = buf->content;
1226 ret->contentIO = buf->contentIO;
1227 xmlFree(buf);
1228 return(ret);
1229}
1230
1231/**
1232 * xmlBufMergeBuffer:
1233 * @buf: an xmlBufPtr
1234 * @buffer: the buffer to consume into @buf
1235 *
1236 * The content of @buffer is appended to @buf and @buffer is freed
1237 *
1238 * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
1239 */
1240int
1241xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
1242 int ret = 0;
1243
1244 if ((buf == NULL) || (buf->error)) {
1245 xmlBufferFree(buffer);
1246 return(-1);
1247 }
1248 CHECK_COMPAT(buf)
1249 if ((buffer != NULL) && (buffer->content != NULL) &&
1250 (buffer->use > 0)) {
1251 ret = xmlBufAdd(buf, buffer->content, buffer->use);
1252 }
1253 xmlBufferFree(buffer);
1254 return(ret);
1255}
1256
1257/**
1258 * xmlBufResetInput:
1259 * @buf: an xmlBufPtr
1260 * @input: an xmlParserInputPtr
1261 *
1262 * Update the input to use the current set of pointers from the buffer.
1263 *
1264 * Returns -1 in case of error, 0 otherwise
1265 */
1266int
1267xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
1268 if ((input == NULL) || (buf == NULL) || (buf->error))
1269 return(-1);
1270 CHECK_COMPAT(buf)
1271 input->base = input->cur = buf->content;
1272 input->end = &buf->content[buf->use];
1273 return(0);
1274}
1275
1276/**
1277 * xmlBufGetInputBase:
1278 * @buf: an xmlBufPtr
1279 * @input: an xmlParserInputPtr
1280 *
1281 * Get the base of the @input relative to the beginning of the buffer
1282 *
1283 * Returns the size_t corresponding to the displacement
1284 */
1285size_t
1286xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
1287 size_t base;
1288
1289 if ((input == NULL) || (buf == NULL) || (buf->error))
1290 return(-1);
1291 CHECK_COMPAT(buf)
1292 base = input->base - buf->content;
1293 /*
1294 * We could do some pointer arithmetic checks but that's probably
1295 * sufficient.
1296 */
1297 if (base > buf->size) {
1298 xmlBufOverflowError(buf, "Input reference outside of the buffer");
1299 base = 0;
1300 }
1301 return(base);
1302}
1303
1304/**
1305 * xmlBufSetInputBaseCur:
1306 * @buf: an xmlBufPtr
1307 * @input: an xmlParserInputPtr
1308 * @base: the base value relative to the beginning of the buffer
1309 * @cur: the cur value relative to the beginning of the buffer
1310 *
1311 * Update the input to use the base and cur relative to the buffer
1312 * after a possible reallocation of its content
1313 *
1314 * Returns -1 in case of error, 0 otherwise
1315 */
1316int
1317xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
1318 size_t base, size_t cur) {
1319 if (input == NULL)
1320 return(-1);
1321 if ((buf == NULL) || (buf->error)) {
1322 input->base = input->cur = input->end = BAD_CAST "";
1323 return(-1);
1324 }
1325 CHECK_COMPAT(buf)
1326 input->base = &buf->content[base];
1327 input->cur = input->base + cur;
1328 input->end = &buf->content[buf->use];
1329 return(0);
1330}
1331
1332#define bottom_buf
1333#include "elfgcchack.h"
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use