--- /dev/null
+/*
+ * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef BUFFER_H
+#define BUFFER_H
+
+#include <stdlib.h> /* size_t */
+#include <sys/types.h> /* ssize_t */
+
+typedef ssize_t (*buffer_func_t)(void *user_data, void *buf, size_t bufsiz, size_t count);
+
+struct buffer {
+ char *buf;
+ buffer_func_t callback;
+ void *user_data;
+ size_t allocated;
+ size_t length;
+};
+
+void buffer_init (struct buffer *sb, void *buf, size_t bufsiz, buffer_func_t callback, void *user_data);
+
+int buffer_flush (struct buffer *sb);
+ssize_t buffer_write (struct buffer *sb, const void *src, size_t srcsiz);
+int buffer_write_all (struct buffer *sb, const void *src, size_t srcsiz);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2017-2019 Tilman Sauerbeck (tilman at code-monkey de)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+use core::ptr;
+
+pub enum BufferUserData {
+}
+
+#[repr(C)]
+pub struct Buffer {
+ buf: *mut u8,
+ callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize,
+ user_data: *mut BufferUserData,
+ allocated: usize,
+ length: usize,
+}
+
+extern fn dummy_callback(_: *mut BufferUserData, _: *const u8, _: usize, _: usize) -> isize {
+ -1
+}
+
+#[no_mangle]
+pub unsafe extern fn buffer_init(_buffer: *mut Buffer, buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) {
+ let buffer = &mut *_buffer;
+
+ buffer.buf = buf;
+ buffer.allocated = bufsiz;
+ buffer.callback = callback;
+ buffer.user_data = user_data;
+ buffer.length = 0;
+}
+
+unsafe fn buffer_consume(buffer: &mut Buffer, length: usize) {
+ buffer.length -= length;
+
+ ptr::copy(buffer.buf.offset(length as isize), buffer.buf, buffer.length);
+}
+
+#[no_mangle]
+pub unsafe extern fn buffer_flush(_buffer: *mut Buffer) -> i32 {
+ let buffer = &mut *_buffer;
+
+ while buffer.length > 0 {
+ let nwritten = (buffer.callback)(buffer.user_data, buffer.buf, buffer.allocated, buffer.length);
+
+ if nwritten == -1 {
+ return -1;
+ }
+
+ buffer_consume(buffer, nwritten as usize);
+ }
+
+ 0
+}
+
+fn min(a: usize, b: usize) -> usize {
+ if a < b {
+ a
+ } else {
+ b
+ }
+}
+
+#[no_mangle]
+pub unsafe extern fn buffer_write(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize {
+ let buffer = &mut *_buffer;
+
+ if buffer.allocated == buffer.length {
+ if buffer_flush(_buffer) < 0 {
+ return -1;
+ }
+ }
+
+ let nwrite = min(buffer.allocated - buffer.length, srcsiz);
+
+ ptr::copy_nonoverlapping(src, buffer.buf.offset(buffer.length as isize), nwrite);
+
+ buffer.length += nwrite;
+
+ nwrite as isize
+}
+
+#[no_mangle]
+pub unsafe extern fn buffer_write_all(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize {
+ let mut offset = 0;
+ let mut left = srcsiz;
+
+ while left > 0 {
+ let data = src.offset(offset);
+ let nwritten = buffer_write(_buffer, data, left);
+
+ if nwritten < 0 {
+ return -1;
+ }
+
+ left -= nwritten as usize;
+ offset += nwritten;
+ }
+
+ 0
+}
+
+impl Buffer {
+ // Allocates and initializes a buffer.
+ pub fn new(buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) -> Buffer {
+ Buffer {
+ buf: buf,
+ callback: callback,
+ user_data: user_data,
+ allocated: bufsiz,
+ length: 0,
+ }
+ }
+
+ // Allocates a buffer, but does not initialize it.
+ // The buffer won't be usable until the init() function is called on it.
+ pub fn alloc() -> Buffer {
+ Buffer {
+ buf: 0 as *mut u8,
+ callback: dummy_callback,
+ user_data: 0 as *mut BufferUserData,
+ allocated: 0,
+ length: 0,
+ }
+ }
+
+ pub fn init(&mut self, buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) {
+ unsafe {
+ buffer_init(self, buf, bufsiz, callback, user_data);
+ }
+ }
+
+ pub fn write(&mut self, data: &[u8]) {
+ unsafe {
+ buffer_write_all(self, data.as_ptr(), data.len());
+ }
+ }
+
+ pub fn flush(&mut self) -> i32 {
+ unsafe {
+ buffer_flush(self)
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ self.length
+ }
+}