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