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