Sun, 24 Apr 2022 17:14:05 +0200
fix cxBufferMinimumCapacity implementation still using additional_bytes
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
29 #include "cx/buffer.h"
30 #include "cx/utils.h"
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
36 int cxBufferInit(
37 CxBuffer *buffer,
38 void *space,
39 size_t capacity,
40 CxAllocator const *allocator,
41 int flags
42 ) {
43 buffer->allocator = allocator;
44 buffer->flags = flags;
45 if (!space) {
46 buffer->bytes = cxMalloc(allocator, capacity);
47 if (buffer->bytes == NULL) {
48 return 1;
49 }
50 memset(buffer->bytes, 0, capacity);
51 buffer->flags |= CX_BUFFER_FREE_CONTENTS;
52 } else {
53 buffer->bytes = space;
54 }
55 buffer->capacity = capacity;
56 buffer->size = 0;
58 buffer->pos = 0;
60 return 0;
61 }
63 void cxBufferDestroy(CxBuffer *buffer) {
64 if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) {
65 cxFree(buffer->allocator, buffer->bytes);
66 }
67 }
69 int cxBufferSeek(
70 CxBuffer *buffer,
71 off_t offset,
72 int whence
73 ) {
74 size_t npos;
75 switch (whence) {
76 case SEEK_CUR:
77 npos = buffer->pos;
78 break;
79 case SEEK_END:
80 npos = buffer->size;
81 break;
82 case SEEK_SET:
83 npos = 0;
84 break;
85 default:
86 return -1;
87 }
89 size_t opos = npos;
90 npos += offset;
92 if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
93 return -1;
94 }
96 if (npos >= buffer->size) {
97 return -1;
98 } else {
99 buffer->pos = npos;
100 return 0;
101 }
103 }
105 void cxBufferClear(CxBuffer *buffer) {
106 memset(buffer->bytes, 0, buffer->size);
107 buffer->size = 0;
108 buffer->pos = 0;
109 }
111 int cxBufferEof(CxBuffer const *buffer) {
112 return buffer->pos >= buffer->size;
113 }
115 int cxBufferMinimumCapacity(
116 CxBuffer *buffer,
117 size_t newcap
118 ) {
119 if (newcap <= buffer->capacity) {
120 return 0;
121 }
123 unsigned char *newspace = realloc(buffer->bytes, newcap);
124 if (newspace) {
125 memset(newspace + buffer->size, 0, newcap - buffer->size);
126 buffer->bytes = newspace;
127 buffer->capacity = newcap;
128 } else {
129 return -1;
130 }
132 return 0;
133 }
135 size_t cxBufferWrite(
136 void const *ptr,
137 size_t size,
138 size_t nitems,
139 CxBuffer *buffer
140 ) {
141 size_t len;
142 if (cx_szmul(size, nitems, &len)) {
143 return 0;
144 }
145 size_t required = buffer->pos + len;
146 if (buffer->pos > required) {
147 return 0;
148 }
150 if (required > buffer->capacity) {
151 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
152 if (cxBufferMinimumCapacity(buffer, required)) {
153 return 0;
154 }
155 } else {
156 len = buffer->capacity - buffer->pos;
157 if (size > 1) {
158 len -= len % size;
159 }
160 }
161 }
163 if (len == 0) {
164 return len;
165 }
167 memcpy(buffer->bytes + buffer->pos, ptr, len);
168 buffer->pos += len;
169 if (buffer->pos > buffer->size) {
170 buffer->size = buffer->pos;
171 }
173 return len / size;
174 }
176 size_t cxBufferRead(
177 void *ptr,
178 size_t size,
179 size_t nitems,
180 CxBuffer *buffer
181 ) {
182 size_t len;
183 if (cx_szmul(size, nitems, &len)) {
184 return 0;
185 }
186 if (buffer->pos + len > buffer->size) {
187 len = buffer->size - buffer->pos;
188 if (size > 1) len -= len % size;
189 }
191 if (len <= 0) {
192 return len;
193 }
195 memcpy(ptr, buffer->bytes + buffer->pos, len);
196 buffer->pos += len;
198 return len / size;
199 }
201 int cxBufferPut(
202 CxBuffer *buffer,
203 int c
204 ) {
205 if (buffer->pos >= buffer->capacity) {
206 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
207 if (cxBufferMinimumCapacity(buffer, buffer->capacity + 1)) {
208 return EOF;
209 }
210 } else {
211 return EOF;
212 }
213 }
215 c &= 0xFF;
216 buffer->bytes[buffer->pos] = (unsigned char) c;
217 buffer->pos++;
218 if (buffer->pos > buffer->size) {
219 buffer->size = buffer->pos;
220 }
221 return c;
222 }
224 int cxBufferGet(CxBuffer *buffer) {
225 if (cxBufferEof(buffer)) {
226 return EOF;
227 } else {
228 int c = buffer->bytes[buffer->pos];
229 buffer->pos++;
230 return c;
231 }
232 }
234 size_t cxBufferPutString(
235 CxBuffer *buffer,
236 const char *str
237 ) {
238 return cxBufferWrite(str, 1, strlen(str), buffer);
239 }
241 int cxBufferShiftLeft(
242 CxBuffer *buffer,
243 size_t shift
244 ) {
245 if (shift >= buffer->size) {
246 buffer->pos = buffer->size = 0;
247 } else {
248 memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift);
249 buffer->size -= shift;
251 if (buffer->pos >= shift) {
252 buffer->pos -= shift;
253 } else {
254 buffer->pos = 0;
255 }
256 }
257 return 0;
258 }
260 int cxBufferShiftRight(
261 CxBuffer *buffer,
262 size_t shift
263 ) {
264 size_t req_capacity = buffer->size + shift;
265 size_t movebytes;
267 // auto extend buffer, if required and enabled
268 if (buffer->capacity < req_capacity) {
269 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
270 if (cxBufferMinimumCapacity(buffer, req_capacity)) {
271 return 1;
272 }
273 movebytes = buffer->size;
274 } else {
275 movebytes = buffer->capacity - shift;
276 }
277 } else {
278 movebytes = buffer->size;
279 }
281 memmove(buffer->bytes + shift, buffer->bytes, movebytes);
282 buffer->size = shift + movebytes;
284 buffer->pos += shift;
285 if (buffer->pos > buffer->size) {
286 buffer->pos = buffer->size;
287 }
289 return 0;
290 }
292 int cxBufferShift(
293 CxBuffer *buffer,
294 off_t shift
295 ) {
296 if (shift < 0) {
297 return cxBufferShiftLeft(buffer, (size_t) (-shift));
298 } else if (shift > 0) {
299 return cxBufferShiftRight(buffer, (size_t) shift);
300 } else {
301 return 0;
302 }
303 }