1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/cx/buffer.h Mon Dec 27 16:51:10 2021 +0100 1.3 @@ -0,0 +1,377 @@ 1.4 +/* 1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 + * 1.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * 2. Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 + * POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +/** 1.33 + * \file buffer.h 1.34 + * 1.35 + * \brief Advanced buffer implementation. 1.36 + * 1.37 + * Instances of CxBuffer can be used to read from or to write to like one 1.38 + * would do with a stream. 1.39 + * 1.40 + * Some features for convenient use of the buffer 1.41 + * can be enabled. See the documentation of the macro constants for more 1.42 + * information. 1.43 + * 1.44 + * \author Mike Becker 1.45 + * \author Olaf Wintermann 1.46 + * \version 3.0 1.47 + * \copyright 2-Clause BSD License 1.48 + */ 1.49 + 1.50 +#ifndef UCX_BUFFER_H 1.51 +#define UCX_BUFFER_H 1.52 + 1.53 +#include <sys/types.h> 1.54 +#include <stdio.h> 1.55 + 1.56 +#ifdef __cplusplus 1.57 +extern "C" { 1.58 +#endif 1.59 + 1.60 +/** 1.61 + * No buffer features enabled (all flags cleared). 1.62 + */ 1.63 +#define CX_BUFFER_DEFAULT 0x00 1.64 + 1.65 +/** 1.66 + * If this flag is enabled, the buffer will automatically free its contents when destroyed. 1.67 + */ 1.68 +#define CX_BUFFER_FREE_CONTENTS 0x01 1.69 + 1.70 +/** 1.71 + * If this flag is enabled, the buffer will automatically extends its capacity. 1.72 + */ 1.73 +#define CX_BUFFER_AUTO_EXTEND 0x02 1.74 + 1.75 +/** Structure for the UCX buffer data. */ 1.76 +typedef struct { 1.77 + /** A pointer to the buffer contents. */ 1.78 + union { 1.79 + /** 1.80 + * Data is interpreted as text. 1.81 + */ 1.82 + char *space; 1.83 + /** 1.84 + * Data is interpreted as binary. 1.85 + */ 1.86 + unsigned char *bytes; 1.87 + }; 1.88 + /** Current position of the buffer. */ 1.89 + size_t pos; 1.90 + /** Current capacity (i.e. maximum size) of the buffer. */ 1.91 + size_t capacity; 1.92 + /** Current size of the buffer content. */ 1.93 + size_t size; 1.94 + /** 1.95 + * Flag register for buffer features. 1.96 + * \see #CX_BUFFER_DEFAULT 1.97 + * \see #CX_BUFFER_FREE_CONTENTS 1.98 + * \see #CX_BUFFER_AUTO_EXTEND 1.99 + */ 1.100 + int flags; 1.101 +} cx_buffer_s; 1.102 + 1.103 +/** 1.104 + * UCX buffer. 1.105 + */ 1.106 +typedef cx_buffer_s *CxBuffer; 1.107 + 1.108 +/** 1.109 + * Creates a new buffer. 1.110 + * 1.111 + * \note You may provide \c NULL as argument for \p space. 1.112 + * Then this function will allocate the space and enforce 1.113 + * the #CX_BUFFER_FREE_CONTENTS flag. 1.114 + * 1.115 + * \param space pointer to the memory area, or <code>NULL</code> to allocate 1.116 + * new memory 1.117 + * \param capacity the capacity of the buffer 1.118 + * \param flags buffer features (see cx_buffer_s.flags) 1.119 + * \return the new buffer 1.120 + */ 1.121 +CxBuffer cxBufferCreate( 1.122 + void *space, 1.123 + size_t capacity, 1.124 + int flags 1.125 +); 1.126 + 1.127 +/** 1.128 + * Destroys a buffer. 1.129 + * 1.130 + * If the #CX_BUFFER_FREE_CONTENTS feature is enabled, the contents of the buffer 1.131 + * are also freed. 1.132 + * 1.133 + * \param buffer the buffer to destroy 1.134 + */ 1.135 +void cxBufferDestroy(CxBuffer buffer); 1.136 + 1.137 +/** 1.138 + * Creates a new buffer and fills it with content copied from another buffer. 1.139 + * 1.140 + * \note The #CX_BUFFER_FREE_CONTENTS feature is enforced for the new buffer. 1.141 + * 1.142 + * \param src the source buffer 1.143 + * \param start the start position of extraction 1.144 + * \param length the count of bytes to extract (must not be zero) 1.145 + * \param flags features for the new buffer (#CX_BUFFER_FREE_CONTENTS will always be enabled) 1.146 + * \return a new buffer containing the extraction 1.147 + */ 1.148 +CxBuffer cxBufferExtract( 1.149 + CxBuffer src, 1.150 + size_t start, 1.151 + size_t length, 1.152 + int flags 1.153 +); 1.154 + 1.155 +/** 1.156 + * A shorthand macro for copying an entire buffer. 1.157 + * 1.158 + * \param src the source buffer 1.159 + * \param flags features for the new buffer (#CX_BUFFER_FREE_CONTENTS will always be enabled) 1.160 + * \return a new buffer with the copied content 1.161 + */ 1.162 +#define cxBufferClone(src, flags) cxBufferExtract(src, 0, (src)->capacity, flags) 1.163 + 1.164 + 1.165 +/** 1.166 + * Shifts the contents of the buffer by the given offset. 1.167 + * 1.168 + * If the offset is positive, the contents are shifted to the right. 1.169 + * If auto extension is enabled, the buffer grows, if necessary. 1.170 + * In case the auto extension fails, this function returns a non-zero value and 1.171 + * no contents are changed. 1.172 + * If auto extension is disabled, the contents that do not fit into the buffer 1.173 + * are discarded. 1.174 + * 1.175 + * If the offset is negative, the contents are shifted to the left where the 1.176 + * first \p shift bytes are discarded. 1.177 + * The new size of the buffer is the old size minus the absolute shift value. 1.178 + * If this value is larger than the buffer size, the buffer is emptied (but 1.179 + * not cleared, see the security note below). 1.180 + * 1.181 + * The buffer position gets shifted alongside with the content but is kept 1.182 + * within the boundaries of the buffer. 1.183 + * 1.184 + * \note For situations where \c off_t is not large enough, there are specialized cxBufferShiftLeft() and 1.185 + * cxBufferShiftRight() functions using a \c size_t as parameter type. 1.186 + * 1.187 + * \par Security Note 1.188 + * The shifting operation does \em not erase the previously occupied memory cells. 1.189 + * You can easily do that manually, e.g. by calling 1.190 + * <code>memset(buffer->bytes, 0, shift)</code> for a right shift or 1.191 + * <code>memset(buffer->size, 0, buffer->capacity - buffer->size)</code> 1.192 + * for a left shift. 1.193 + * 1.194 + * \param buffer the buffer 1.195 + * \param shift the shift offset (negative means left shift) 1.196 + * \return 0 on success, non-zero if a required auto-extension fails 1.197 + */ 1.198 +int cxBufferShift( 1.199 + CxBuffer buffer, 1.200 + off_t shift 1.201 +); 1.202 + 1.203 +/** 1.204 + * Shifts the buffer to the right. 1.205 + * See cxBufferShift() for details. 1.206 + * 1.207 + * \param buffer the buffer 1.208 + * \param shift the shift offset 1.209 + * \return 0 on success, non-zero if a required auto-extension fails 1.210 + * \see cxBufferShift() 1.211 + */ 1.212 +int cxBufferShiftRight( 1.213 + CxBuffer buffer, 1.214 + size_t shift 1.215 +); 1.216 + 1.217 +/** 1.218 + * Shifts the buffer to the left. 1.219 + * See cxBufferShift() for details. 1.220 + * 1.221 + * \note Since a left shift cannot fail due to memory allocation problems, this 1.222 + * function always returns zero. 1.223 + * 1.224 + * \param buffer the buffer 1.225 + * \param shift the positive shift offset 1.226 + * \return always zero 1.227 + * \see cxBufferShift() 1.228 + */ 1.229 +int cxBufferShiftLeft( 1.230 + CxBuffer buffer, 1.231 + size_t shift 1.232 +); 1.233 + 1.234 + 1.235 +/** 1.236 + * Moves the position of the buffer. 1.237 + * 1.238 + * The new position is relative to the \p whence argument. 1.239 + * 1.240 + * \li \c SEEK_SET marks the start of the buffer. 1.241 + * \li \c SEEK_CUR marks the current position. 1.242 + * \li \c SEEK_END marks the end of the buffer. 1.243 + * 1.244 + * With an offset of zero, this function sets the buffer position to zero 1.245 + * (\c SEEK_SET), the buffer size (\c SEEK_END) or leaves the buffer position 1.246 + * unchanged (\c SEEK_CUR). 1.247 + * 1.248 + * \param buffer the buffer 1.249 + * \param offset position offset relative to \p whence 1.250 + * \param whence one of \c SEEK_SET, \c SEEK_CUR or \c SEEK_END 1.251 + * \return 0 on success, non-zero if the position is invalid 1.252 + * 1.253 + */ 1.254 +int cxBufferSeek( 1.255 + CxBuffer buffer, 1.256 + off_t offset, 1.257 + int whence 1.258 +); 1.259 + 1.260 +/** 1.261 + * Clears the buffer by resetting the position and deleting the data. 1.262 + * 1.263 + * The data is deleted by zeroing it with a call to memset(). 1.264 + * 1.265 + * \param buffer the buffer to be cleared 1.266 + */ 1.267 +#define cxBufferClear(buffer) memset((buffer)->bytes, 0, (buffer)->size); \ 1.268 + (buffer)->size = 0; (buffer)->pos = 0; 1.269 + 1.270 +/** 1.271 + * Tests, if the buffer position has exceeded the buffer capacity. 1.272 + * 1.273 + * \param buffer the buffer to test 1.274 + * \return non-zero, if the current buffer position has exceeded the last 1.275 + * available byte of the buffer. 1.276 + */ 1.277 +int cxBufferEof(CxBuffer buffer); 1.278 + 1.279 + 1.280 +/** 1.281 + * Ensures that the buffer has a minimum capacity. 1.282 + * 1.283 + * If the current capacity is not sufficient, the buffer will be extended. 1.284 + * 1.285 + * \param buffer the buffer 1.286 + * \param capacity the minimum required capacity for this buffer 1.287 + * \return 0 on success or a non-zero value on failure 1.288 + */ 1.289 +int cxBufferMinimumCapacity( 1.290 + CxBuffer buffer, 1.291 + size_t capacity 1.292 +); 1.293 + 1.294 +/** 1.295 + * Writes data to a CxBuffer. 1.296 + * 1.297 + * The position of the buffer is increased by the number of bytes written. 1.298 + * 1.299 + * \note The signature is compatible with the fwrite() family of functions. 1.300 + * 1.301 + * \param ptr a pointer to the memory area containing the bytes to be written 1.302 + * \param size the length of one element 1.303 + * \param nitems the element count 1.304 + * \param buffer the CxBuffer to write to 1.305 + * \return the total count of bytes written 1.306 + */ 1.307 +size_t cxBufferWrite( 1.308 + const void *ptr, 1.309 + size_t size, 1.310 + size_t nitems, 1.311 + CxBuffer buffer 1.312 +); 1.313 + 1.314 +/** 1.315 + * Reads data from a CxBuffer. 1.316 + * 1.317 + * The position of the buffer is increased by the number of bytes read. 1.318 + * 1.319 + * \note The signature is compatible with the fread() family of functions. 1.320 + * 1.321 + * \param ptr a pointer to the memory area where to store the read data 1.322 + * \param size the length of one element 1.323 + * \param nitems the element count 1.324 + * \param buffer the CxBuffer to read from 1.325 + * \return the total number of elements read 1.326 + */ 1.327 +size_t cxBufferRead( 1.328 + void *ptr, 1.329 + size_t size, 1.330 + size_t nitems, 1.331 + CxBuffer buffer 1.332 +); 1.333 + 1.334 +/** 1.335 + * Writes a character to a buffer. 1.336 + * 1.337 + * The least significant byte of the argument is written to the buffer. If the 1.338 + * end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled, 1.339 + * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature is 1.340 + * disabled or buffer extension fails, \c EOF is returned. 1.341 + * 1.342 + * On successful write, the position of the buffer is increased. 1.343 + * 1.344 + * \param buffer the buffer to write to 1.345 + * \param c the character to write 1.346 + * \return the byte that has bean written or \c EOF when the end of the stream is 1.347 + * reached and automatic extension is not enabled or not possible 1.348 + */ 1.349 +int cxBufferPut( 1.350 + CxBuffer buffer, 1.351 + int c 1.352 +); 1.353 + 1.354 +/** 1.355 + * Gets a character from a buffer. 1.356 + * 1.357 + * The current position of the buffer is increased after a successful read. 1.358 + * 1.359 + * \param buffer the buffer to read from 1.360 + * \return the character or \c EOF, if the end of the buffer is reached 1.361 + */ 1.362 +int cxBufferGet(CxBuffer buffer); 1.363 + 1.364 +/** 1.365 + * Writes a string to a buffer. 1.366 + * 1.367 + * \param buffer the buffer 1.368 + * \param str the zero-terminated string 1.369 + * \return the number of bytes written 1.370 + */ 1.371 +size_t cxBufferPutString( 1.372 + CxBuffer buffer, 1.373 + const char *str 1.374 +); 1.375 + 1.376 +#ifdef __cplusplus 1.377 +} 1.378 +#endif 1.379 + 1.380 +#endif /* UCX_BUFFER_H */