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