xref: /reactos/sdk/lib/3rdparty/libxml2/buf.c (revision 911153da)
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 "&quot;", 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