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