--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2025 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <pakfire/buffer.h>
+#include <pakfire/util.h>
+
+// Use chunks of 4k size
+#define CHUNK_SIZE 4096
+
+void pakfire_buffer_free(struct pakfire_buffer* buffer) {
+ if (buffer->data)
+ free(buffer->data);
+}
+
+// Rounds up length to the nearest chunk size
+static size_t pakfire_buffer_align(size_t length) {
+ return ((length + CHUNK_SIZE - 1) / CHUNK_SIZE) * CHUNK_SIZE;
+}
+
+static int pakfire_buffer_resize(struct pakfire_buffer* self, size_t length) {
+ // Check maximum length and refuse to grow
+ if (self->max_length && (length > self->max_length))
+ return -ENOBUFS;
+
+ // Round up to the nearest chunk size
+ length = pakfire_buffer_align(length);
+
+ // Re-allocate the buffer
+ self->data = pakfire_realloc(self->data, length);
+ if (!self->data)
+ return -errno;
+
+ // Adjust the size
+ self->length = length;
+
+ return 0;
+}
+
+// Grows the buffer
+static int pakfire_buffer_grow(struct pakfire_buffer* self, size_t length) {
+ // Check if we actually need to grow
+ if (self->length >= self->used + length)
+ return 0;
+
+ return pakfire_buffer_resize(self, self->length + length);
+}
+
+// Shrinks the buffer to its minimum size
+static int pakfire_buffer_shrink(struct pakfire_buffer* self) {
+ return pakfire_buffer_resize(self, self->length);
+}
+
+int pakfire_buffer_append(struct pakfire_buffer* self, const char* data, size_t length) {
+ int r;
+
+ // Check inputs
+ if (!data)
+ return -EINVAL;
+
+ // Nothing to do if there is no data
+ if (!length)
+ return 0;
+
+ // Grow the buffer
+ r = pakfire_buffer_grow(self, length);
+ if (r < 0)
+ return r;
+
+ // Copy the data
+ memcpy(self->data + self->used, data, length);
+ self->used += length;
+
+ return 0;
+}
+
+int pakfire_buffer_append_from_fd(struct pakfire_buffer* self, int fd) {
+ ssize_t bytes_read = 0;
+ int r;
+
+ // Read for as long as possible
+ for (;;) {
+ // Ensure that we have at least one chunk size available
+ r = pakfire_buffer_grow(self, CHUNK_SIZE);
+ if (r < 0)
+ return r;
+
+ // Read into the buffer
+ bytes_read = read(fd, self->data + self->used, self->length - self->used);
+ if (bytes_read < 0)
+ return bytes_read;
+
+ // We now use more space
+ self->used += bytes_read;
+
+ // If we have not filled the entire space, we have read everything for now
+ if (self->used < self->length)
+ break;
+ }
+
+ return 0;
+}
+
+int pakfire_buffer_consume(struct pakfire_buffer* self, size_t length) {
+ // Check if we actually have enough data
+ if (self->used < length)
+ return -EINVAL;
+
+ memmove(self->data, self->data + length, self->used - length);
+ self->used -= length;
+
+ return 0;
+}
+
+size_t pakfire_buffer_find_line(struct pakfire_buffer* self) {
+ char* p = NULL;
+
+ // Nothing to do if there is no data
+ if (!self->used)
+ return 0;
+
+ // Find the byte
+ p = memchr(self->data, '\n', self->used);
+ if (!p)
+ return 0;
+
+ // Return the length
+ return p - self->data + 1;
+}
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2025 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#ifndef PAKFIRE_BUFFER_H
+#define PAKFIRE_BUFFER_H
+
+struct pakfire_buffer {
+ char* data;
+ size_t length;
+
+ // Actually used data
+ size_t used;
+
+ // Defines the maximum length this buffer can grow to
+ size_t max_length;
+};
+
+void pakfire_buffer_free(struct pakfire_buffer* buffer);
+
+int pakfire_buffer_append(struct pakfire_buffer* self, const char* data, size_t length);
+int pakfire_buffer_append_from_fd(struct pakfire_buffer* self, int fd);
+
+int pakfire_buffer_consume(struct pakfire_buffer* self, size_t length);
+
+size_t pakfire_buffer_find_line(struct pakfire_buffer* self);
+
+#endif /* PAKFIRE_BUFFER_H */