add existing code (build system, libs, initial mizucp code)
[mizunara.git] / ucx / buffer.c
1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3  *
4  * Copyright 2017 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  */
28
29 #include "ucx/buffer.h"
30
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) {
36     UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer));
37     if (buffer) {
38         buffer->flags = flags;
39         if (!space) {
40             buffer->space = (char*)malloc(capacity);
41             if (!buffer->space) {
42                 free(buffer);
43                 return NULL;
44             }
45             memset(buffer->space, 0, capacity);
46             buffer->flags |= UCX_BUFFER_AUTOFREE;
47         } else {
48             buffer->space = (char*)space;
49         }
50         buffer->capacity = capacity;
51         buffer->size = 0;
52
53         buffer->pos = 0;
54     }
55
56     return buffer;
57 }
58
59 void ucx_buffer_free(UcxBuffer *buffer) {
60     if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) {
61         free(buffer->space);
62     }
63     free(buffer);
64 }
65
66 UcxBuffer* ucx_buffer_extract(
67         UcxBuffer *src, size_t start, size_t length, int flags) {
68     if (src->size == 0 || length == 0 ||
69         ((size_t)-1) - start < length || start+length > src->capacity)
70     {
71         return NULL;
72     }
73
74     UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer));
75     if (dst) {
76         dst->space = (char*)malloc(length);
77         if (!dst->space) {
78             free(dst);
79             return NULL;
80         }
81         dst->capacity = length;
82         dst->size = length;
83         dst->flags = flags | UCX_BUFFER_AUTOFREE;
84         dst->pos = 0;
85         memcpy(dst->space, src->space+start, length);
86     }
87     return dst;
88 }
89
90 int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) {
91     size_t npos;
92     switch (whence) {
93     case SEEK_CUR:
94         npos = buffer->pos;
95         break;
96     case SEEK_END:
97         npos = buffer->size;
98         break;
99     case SEEK_SET:
100         npos = 0;
101         break;
102     default:
103         return -1;
104     }
105
106     size_t opos = npos;
107     npos += offset;
108     
109     if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
110         return -1;
111     }
112     
113     if (npos >= buffer->size) {
114         return -1;
115     } else {
116         buffer->pos = npos;
117         return 0;
118     }
119
120 }
121
122 int ucx_buffer_eof(UcxBuffer *buffer) {
123     return buffer->pos >= buffer->size;
124 }
125
126 int ucx_buffer_extend(UcxBuffer *buffer, size_t len) {
127     size_t newcap = buffer->capacity;
128     
129     if (buffer->capacity + len < buffer->capacity) {
130         return -1;
131     }
132     
133     while (buffer->capacity + len > newcap) {
134         newcap <<= 1;
135         if (newcap < buffer->capacity) {
136             return -1;
137         }
138     }
139     
140     char *newspace = (char*)realloc(buffer->space, newcap);
141     if (newspace) {
142         memset(newspace+buffer->size, 0, newcap-buffer->size);
143         buffer->space = newspace;
144         buffer->capacity = newcap;
145     } else {
146         return -1;
147     }
148     
149     return 0;
150 }
151
152 size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
153         UcxBuffer *buffer) {
154     size_t len;
155     if(ucx_szmul(size, nitems, &len)) {
156         return 0;
157     }
158     size_t required = buffer->pos + len;
159     if (buffer->pos > required) {
160         return 0;
161     }
162     
163     if (required > buffer->capacity) {
164         if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
165             if (ucx_buffer_extend(buffer, required - buffer->capacity)) {
166                 return 0;
167             }
168         } else {
169             len = buffer->capacity - buffer->pos;
170             if (size > 1) {
171                 len -= len%size;
172             }
173         }
174     }
175     
176     if (len == 0) {
177         return len;
178     }
179     
180     memcpy(buffer->space + buffer->pos, ptr, len);
181     buffer->pos += len;
182     if(buffer->pos > buffer->size) {
183         buffer->size = buffer->pos;
184     }
185     
186     return len / size;
187 }
188
189 size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
190         UcxBuffer *buffer) {
191     size_t len;
192     if(ucx_szmul(size, nitems, &len)) {
193         return 0;
194     }
195     if (buffer->pos + len > buffer->size) {
196         len = buffer->size - buffer->pos;
197         if (size > 1) len -= len%size;
198     }
199     
200     if (len <= 0) {
201         return len;
202     }
203     
204     memcpy(ptr, buffer->space + buffer->pos, len);
205     buffer->pos += len;
206     
207     return len / size;
208 }
209
210 int ucx_buffer_putc(UcxBuffer *buffer, int c) {
211     if(buffer->pos >= buffer->capacity) {
212         if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
213             if(ucx_buffer_extend(buffer, 1)) {
214                 return EOF;
215             }
216         } else {
217             return EOF;
218         }
219     }
220     
221     c &= 0xFF;
222     buffer->space[buffer->pos] = (char) c;
223     buffer->pos++;
224     if(buffer->pos > buffer->size) {
225         buffer->size = buffer->pos;
226     }
227     return c;
228 }
229
230 int ucx_buffer_getc(UcxBuffer *buffer) {
231     if (ucx_buffer_eof(buffer)) {
232         return EOF;
233     } else {
234         int c = ((unsigned char*)buffer->space)[buffer->pos];
235         buffer->pos++;
236         return c;
237     }
238 }
239
240 size_t ucx_buffer_puts(UcxBuffer *buffer, const char *str) {
241     return ucx_buffer_write((const void*)str, 1, strlen(str), buffer);
242 }
243
244 int ucx_buffer_shift_left(UcxBuffer* buffer, size_t shift) {
245     if (shift >= buffer->size) {
246         buffer->pos = buffer->size = 0;
247     } else {
248         memmove(buffer->space, buffer->space + shift, buffer->size - shift);
249         buffer->size -= shift;
250         
251         if (buffer->pos >= shift) {
252             buffer->pos -= shift;
253         } else {
254             buffer->pos = 0;
255         }
256     }
257     return 0;
258 }
259
260 int ucx_buffer_shift_right(UcxBuffer* buffer, size_t shift) {
261     size_t req_capacity = buffer->size + shift;
262     size_t movebytes;
263     
264     // auto extend buffer, if required and enabled
265     if (buffer->capacity < req_capacity) {
266         if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
267             if (ucx_buffer_extend(buffer, req_capacity - buffer->capacity)) {
268                 return 1;
269             }
270             movebytes = buffer->size;
271         } else {
272             movebytes = buffer->capacity - shift;
273         }
274     } else {
275         movebytes = buffer->size;
276     }
277     
278     memmove(buffer->space + shift, buffer->space, movebytes);
279     buffer->size = shift+movebytes;
280     
281     buffer->pos += shift;
282     if (buffer->pos > buffer->size) {
283         buffer->pos = buffer->size;
284     }
285     
286     return 0;
287 }
288
289 int ucx_buffer_shift(UcxBuffer* buffer, off_t shift) {
290     if (shift < 0) {
291         return ucx_buffer_shift_left(buffer, (size_t) (-shift));
292     } else if (shift > 0) {
293         return ucx_buffer_shift_right(buffer, (size_t) shift);
294     } else {
295         return 0;
296     }
297 }