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