Endian-independent binary IO utilities for C

Compare changes

Choose any two refs to compare.

Changed files
+73 -67
+1 -31
bini.c
··· 1 - /* 2 - Bini license: BSD 3-Clause. 3 - 4 - Copyright 2025 Emmeline Coats 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 notice, this 10 - list of conditions and the following disclaimer. 11 - 12 - 2. Redistributions in binary form must reproduce the above copyright notice, 13 - this list of conditions and the following disclaimer in the documentation 14 - and/or other materials provided with the distribution. 15 - 16 - 3. Neither the name of the copyright holder nor the names of its contributors 17 - may be used to endorse or promote products derived from this software 18 - without specific prior written permission. 19 - 20 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND 21 - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 - */ 31 - 32 1 #ifndef bini_impl 33 2 #define bini_impl 34 3 #endif 4 + 35 5 #include <bini.h>
+72 -36
bini.h
··· 1 - #ifndef __bini__ 2 - #define __bini__ 1 + #ifndef __kf_bini__ 2 + #define __kf_bini__ 3 3 4 - /* License at end of file. */ 4 + /* 5 + bini.h: endian-independent binary IO. 6 + License: BSD 3-Clause. See EOF for license text. 7 + 8 + Version: 1.1 9 + 10 + Changelog: 11 + 1.0 (Dec 28, 2025): Initial version. 12 + 1.1 (Dec 30, 2025): Use an offset instead of shifting the 13 + byte buffer so carelessly. _bini_grow will shift the 14 + buffer on-demand instead so as to conserve CPU time. 15 + */ 5 16 6 17 /* Used to add functions for version-specific types. */ 7 18 #define bini_c 1989 ··· 92 103 { 93 104 /* Read mode for the stream. Should be either BINI_STACK or BINI_STREAM. */ 94 105 int mode; 106 + /* Offset from the start of the buffer in bytes. Only used for BINI_STREAM. */ 107 + size_t off; 95 108 size_t cap; 96 109 size_t len; 97 110 uint8_t *buffer; ··· 117 130 buffer, and frees the provided variable as well. */ 118 131 void bini_close(struct bini_stream *bs); 119 132 133 + /* Shift a binary stream, resetting the offset and shifting the array. */ 134 + void bini_shift(struct bini_stream *); 120 135 /* Flush a binary stream, clearing its buffer. */ 121 136 int bini_flush(struct bini_stream *); 122 137 /* Dump the binary stream's buffer to fp. */ ··· 247 262 bs->buffer = calloc(BINI_BUFSIZ, 1); 248 263 if (!bs->buffer) 249 264 return BINI_ERR; 265 + bs->off = 0; 250 266 bs->len = 0; 251 267 bs->cap = BINI_BUFSIZ; 252 268 bs->mode = BINI_STREAM; ··· 270 286 { 271 287 bini_end(bs); 272 288 free(bs); 289 + } 290 + 291 + static 292 + #if bini_c >= 1999 293 + inline 294 + #endif 295 + void _bini_shiftleft(struct bini_stream *bs, size_t n) 296 + { 297 + size_t i; 298 + _bini_dbg("shift %d: (len=%lu)\n", n, bs->len); 299 + for (i = 0 ; i < bs->len ; i++) 300 + { 301 + if (i+n >= bs->len) 302 + { 303 + _bini_dbg(" %d: [%d] (out of bounds) to [%d]\n", n, i+n, i); 304 + bs->buffer[i] = 0; 305 + continue; 306 + } 307 + _bini_dbg(" %d: [%d] (%02x '%c') to [%d]\n", 308 + n, 309 + i+n, 310 + bs->buffer[i+n], 311 + bs->buffer[i+n], 312 + i); 313 + bs->buffer[i] = bs->buffer[i+n]; 314 + } 315 + } 316 + 317 + void bini_shift(struct bini_stream *bs) 318 + { 319 + _bini_shiftleft(bs, bs->off); 320 + bs->off = 0; 273 321 } 274 322 275 323 int bini_flush(struct bini_stream *bs) ··· 299 347 int _bini_grow(struct bini_stream *bs, size_t n) 300 348 { 301 349 uint8_t *newbuf; 350 + 351 + if (bs->off + bs->len + n < bs->cap) 352 + return BINI_OK; 353 + 354 + /* Shifting the array could give enough space to 355 + fit `n`, avoiding the need to realloc. */ 356 + bini_shift(bs); 357 + 302 358 if (bs->len + n < bs->cap) 303 359 return BINI_OK; 360 + 304 361 while (bs->len + n >= bs->cap) 305 362 { 306 363 newbuf = realloc(bs->buffer, bs->cap * 2); ··· 309 366 bs->buffer = newbuf; 310 367 bs->cap *= 2; 311 368 } 369 + 312 370 return BINI_OK; 313 371 } 314 372 ··· 326 384 return fwrite(bs->buffer, size, n, fp); 327 385 } 328 386 329 - static 330 - #if bini_c >= 1999 331 - inline 332 - #endif 333 - void _bini_shiftleft(struct bini_stream *bs, size_t n) 334 - { 335 - size_t i; 336 - _bini_dbg("shift %d: (len=%lu)\n", n, bs->len); 337 - for (i = 0 ; i < bs->len ; i++) 338 - { 339 - if (i+n >= bs->len) 340 - { 341 - _bini_dbg(" %d: [%d] (out of bounds) to [%d]\n", n, i+n, i); 342 - bs->buffer[i] = 0; 343 - continue; 344 - } 345 - _bini_dbg(" %d: [%d] (%02x '%c') to [%d]\n", 346 - n, 347 - i+n, 348 - bs->buffer[i+n], 349 - bs->buffer[i+n], 350 - i); 351 - bs->buffer[i] = bs->buffer[i+n]; 352 - } 353 - } 354 - 355 387 #define _bini_rwx(_type, _name) \ 356 388 void bini_w##_name(struct bini_stream *bs, _type v) \ 357 389 { \ ··· 368 400 l ? sizeof(v)-i-1 : i, \ 369 401 bytes[l ? sizeof(v)-i-1 : i], \ 370 402 bytes[l ? sizeof(v)-i-1 : i], \ 371 - bs->len+i); \ 372 - bs->buffer[bs->len+i] = bytes[l ? sizeof(v)-i-1 : i]; \ 403 + bs->off+bs->len+i); \ 404 + bs->buffer[bs->off+bs->len+i] = bytes[l ? sizeof(v)-i-1 : i]; \ 373 405 } \ 374 406 bs->len += i; \ 375 407 _bini_dbg("-> %s: %d (%lu bytes)\n", __FUNCTION__, *(int *)bytes, sizeof(v)); \ ··· 383 415 int m = bs->mode == BINI_STREAM; \ 384 416 for (i = 0 ; i < sizeof(v) ; i++) \ 385 417 { \ 418 + const size_t p = bs->off + (m ? i : (bs->len-sizeof(v)+i)); \ 386 419 _bini_dbg("%s: byte index [%lu] from buffer index %lu (= %02x '%c')\n", \ 387 420 __FUNCTION__, \ 388 421 l ? sizeof(v)-i-1 : i, \ 389 - m ? i : (bs->len-sizeof(v)+i), \ 390 - bs->buffer[m ? i : (bs->len-sizeof(v)+i)], \ 391 - bs->buffer[m ? i : (bs->len-sizeof(v)+i)]); \ 392 - bytes[l ? sizeof(v)-i-1 : i] = bs->buffer[m ? i : (bs->len-sizeof(v)+i)]; \ 422 + p, \ 423 + bs->buffer[p], \ 424 + bs->buffer[p]); \ 425 + bytes[l ? sizeof(v)-i-1 : i] = bs->buffer[p]; \ 393 426 } \ 394 427 if (m) \ 395 - _bini_shiftleft(bs, i); \ 428 + { \ 429 + bs->off += i; \ 430 + /* _bini_shiftleft(bs, i); */ \ 431 + } \ 396 432 bs->len -= i; \ 397 433 return v; \ 398 434 }