1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
37
  
38
  
39
  
40
  
41
  
42
  
43
  
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
104
  
105
  
106
  
107
  
108
  
109
  
110
  
111
  
112
  
113
  
114
  
115
  
116
  
117
  
118
  
119
  
120
  
121
  
122
  
123
  
124
  
125
  
126
  
127
  
128
  
129
  
130
  
131
  
132
  
133
  
134
  
135
  
136
  
/* 
|| This file is part of Pike. For copyright information see COPYRIGHT. 
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING 
|| for more information. 
*/ 
 
#include "buffer.h" 
#include "stralloc.h" 
#include "svalue.h" 
#include "pike_error.h" 
#include "bignum.h" 
 
PMOD_EXPORT void buffer_free(struct byte_buffer *b) { 
    if (!b->dst) return; 
    free(buffer_ptr(b)); 
    buffer_init(b); 
} 
 
static void *buffer_realloc(struct byte_buffer *b, size_t len) { 
    if (b->flags & BUFFER_GROW_MEXEC) { 
        return mexec_realloc(buffer_ptr(b), len); 
    } else { 
        return realloc(buffer_ptr(b), len); 
    } 
} 
 
PMOD_EXPORT int buffer_grow_nothrow(struct byte_buffer *b, size_t len) { 
    const size_t content_length = buffer_content_length(b); 
    size_t new_length, needed; 
    unsigned INT16 flags = b->flags; 
    void *ptr; 
 
#ifdef PIKE_DEBUG 
    if (buffer_space(b) >= len) Pike_fatal("Misuse of buffer_grow.\n"); 
#endif 
    if (DO_SIZE_T_ADD_OVERFLOW(len, content_length, &needed)) goto OUT_OF_MEMORY_FATAL; 
 
    if (!(flags & BUFFER_GROW_EXACT)) { 
        new_length = b->length; 
        if (new_length < 16) new_length = 16; 
 
        while (new_length < needed) { 
            if (DO_SIZE_T_MUL_OVERFLOW(new_length, 2, &new_length)) goto OUT_OF_MEMORY_FATAL; 
        } 
    } else { 
        new_length = needed; 
    } 
 
#if 0 
    fprintf(stderr, "BUF { left=%llu; length=%llu; dst=%p; }\n", buffer_space(b), b->length, b->dst); 
#endif 
 
    ptr = buffer_realloc(b, new_length); 
 
    if (UNLIKELY(!ptr)) return 0; 
 
#if 0 
    fprintf(stderr, "realloc(%p, %llu) = %p\n", buffer_ptr(b), new_length, ptr); 
    fprintf(stderr, "content_length: %llu\n", content_length); 
#endif 
 
    b->dst = (char*)ptr + content_length; 
    b->end = (char*)ptr + new_length; 
    b->length = new_length; 
    return 1; 
OUT_OF_MEMORY_FATAL: 
    /* This happens on overflow. */ 
#ifdef PIKE_DEBUG 
    Pike_fatal(msg_out_of_mem_2, len); 
#else 
    return 0; 
#endif 
} 
 
PMOD_EXPORT void buffer_grow(struct byte_buffer *b, size_t len) { 
    if (UNLIKELY(!buffer_grow_nothrow(b, len))) Pike_error(msg_out_of_mem_2, len); 
} 
 
PMOD_EXPORT void* buffer_finish(struct byte_buffer *b) { 
    void *ret; 
 
    if (buffer_content_length(b) < buffer_length(b)) { 
        ret = buffer_realloc(b, buffer_content_length(b)); 
        /* we cannot shrink, that does not matter */ 
        if (!ret) ret = buffer_ptr(b); 
    } else ret = buffer_ptr(b); 
 
    buffer_init(b); 
 
    return ret; 
} 
 
PMOD_EXPORT struct pike_string *buffer_finish_pike_string(struct byte_buffer *b) { 
    struct pike_string *ret; 
    size_t len = buffer_content_length(b); 
 
    if (!len) { 
        buffer_free(b); 
        ret = empty_pike_string; 
        add_ref(ret); 
        return ret; 
    } 
 
    /* zero terminate */ 
    buffer_add_char(b, 0); 
 
    return make_shared_malloc_string(buffer_finish(b), len, eightbit); 
} 
 
PMOD_EXPORT const char *buffer_get_string(struct byte_buffer *b) { 
    buffer_ensure_space(b, 1); 
 
    /* zero terminate */ 
    *(char*)buffer_dst(b) = 0; 
 
    return buffer_ptr(b); 
} 
 
#ifdef PIKE_DEBUG 
PMOD_EXPORT void buffer_check_space(struct byte_buffer *b, size_t len) { 
    if (len > buffer_space(b)) 
        Pike_fatal("buffer_check_space failed.\n"); 
} 
PMOD_EXPORT void buffer_check_position(struct byte_buffer *b, size_t pos) { 
    if (pos > b->length) 
        Pike_fatal("buffer_check_position failed.\n"); 
} 
PMOD_EXPORT void buffer_remove(struct byte_buffer *b, size_t len) { 
    if (len > buffer_content_length(b)) 
        Pike_fatal("Bad call to buffer_remove.\n"); 
 
    b->dst = (char*)b->dst - len; 
} 
#endif