Sun, 24 Apr 2022 15:15:39 +0200
#170 first buffer tests
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 additional_bytes
118 ) {
119 size_t newcap = buffer->capacity + additional_bytes;
121 // overflow protection
122 if (newcap < buffer->capacity) {
123 return -1;
124 }
126 unsigned char *newspace = realloc(buffer->bytes, newcap);
127 if (newspace) {
128 memset(newspace + buffer->size, 0, newcap - buffer->size);
129 buffer->bytes = newspace;
130 buffer->capacity = newcap;
131 } else {
132 return -1;
133 }
135 return 0;
136 }
138 size_t cxBufferWrite(
139 void const *ptr,
140 size_t size,
141 size_t nitems,
142 CxBuffer *buffer
143 ) {
144 size_t len;
145 if (cx_szmul(size, nitems, &len)) {
146 return 0;
147 }
148 size_t required = buffer->pos + len;
149 if (buffer->pos > required) {
150 return 0;
151 }
153 if (required > buffer->capacity) {
154 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
155 if (cxBufferMinimumCapacity(buffer, required)) {
156 return 0;
157 }
158 } else {
159 len = buffer->capacity - buffer->pos;
160 if (size > 1) {
161 len -= len % size;
162 }
163 }
164 }
166 if (len == 0) {
167 return len;
168 }
170 memcpy(buffer->bytes + buffer->pos, ptr, len);
171 buffer->pos += len;
172 if (buffer->pos > buffer->size) {
173 buffer->size = buffer->pos;
174 }
176 return len / size;
177 }
179 size_t cxBufferRead(
180 void *ptr,
181 size_t size,
182 size_t nitems,
183 CxBuffer *buffer
184 ) {
185 size_t len;
186 if (cx_szmul(size, nitems, &len)) {
187 return 0;
188 }
189 if (buffer->pos + len > buffer->size) {
190 len = buffer->size - buffer->pos;
191 if (size > 1) len -= len % size;
192 }
194 if (len <= 0) {
195 return len;
196 }
198 memcpy(ptr, buffer->bytes + buffer->pos, len);
199 buffer->pos += len;
201 return len / size;
202 }
204 int cxBufferPut(
205 CxBuffer *buffer,
206 int c
207 ) {
208 if (buffer->pos >= buffer->capacity) {
209 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
210 if (cxBufferMinimumCapacity(buffer, buffer->capacity + 1)) {
211 return EOF;
212 }
213 } else {
214 return EOF;
215 }
216 }
218 c &= 0xFF;
219 buffer->bytes[buffer->pos] = (unsigned char) c;
220 buffer->pos++;
221 if (buffer->pos > buffer->size) {
222 buffer->size = buffer->pos;
223 }
224 return c;
225 }
227 int cxBufferGet(CxBuffer *buffer) {
228 if (cxBufferEof(buffer)) {
229 return EOF;
230 } else {
231 int c = buffer->bytes[buffer->pos];
232 buffer->pos++;
233 return c;
234 }
235 }
237 size_t cxBufferPutString(
238 CxBuffer *buffer,
239 const char *str
240 ) {
241 return cxBufferWrite(str, 1, strlen(str), buffer);
242 }
244 int cxBufferShiftLeft(
245 CxBuffer *buffer,
246 size_t shift
247 ) {
248 if (shift >= buffer->size) {
249 buffer->pos = buffer->size = 0;
250 } else {
251 memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift);
252 buffer->size -= shift;
254 if (buffer->pos >= shift) {
255 buffer->pos -= shift;
256 } else {
257 buffer->pos = 0;
258 }
259 }
260 return 0;
261 }
263 int cxBufferShiftRight(
264 CxBuffer *buffer,
265 size_t shift
266 ) {
267 size_t req_capacity = buffer->size + shift;
268 size_t movebytes;
270 // auto extend buffer, if required and enabled
271 if (buffer->capacity < req_capacity) {
272 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
273 if (cxBufferMinimumCapacity(buffer, req_capacity)) {
274 return 1;
275 }
276 movebytes = buffer->size;
277 } else {
278 movebytes = buffer->capacity - shift;
279 }
280 } else {
281 movebytes = buffer->size;
282 }
284 memmove(buffer->bytes + shift, buffer->bytes, movebytes);
285 buffer->size = shift + movebytes;
287 buffer->pos += shift;
288 if (buffer->pos > buffer->size) {
289 buffer->pos = buffer->size;
290 }
292 return 0;
293 }
295 int cxBufferShift(
296 CxBuffer *buffer,
297 off_t shift
298 ) {
299 if (shift < 0) {
300 return cxBufferShiftLeft(buffer, (size_t) (-shift));
301 } else if (shift > 0) {
302 return cxBufferShiftRight(buffer, (size_t) shift);
303 } else {
304 return 0;
305 }
306 }