Skip to content

Commit 427f1b8

Browse files
committed
[common] GGUF reader from memory
Add new GGUF reader implementation that can read metadata from a memory buffer.
1 parent 677dc49 commit 427f1b8

File tree

2 files changed

+96
-13
lines changed

2 files changed

+96
-13
lines changed

ggml/include/gguf.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ extern "C" {
7878

7979
GGML_API struct gguf_context * gguf_init_empty(void);
8080
GGML_API struct gguf_context * gguf_init_from_file(const char * fname, struct gguf_init_params params);
81-
//GGML_API struct gguf_context * gguf_init_from_buffer(..);
8281

8382
GGML_API void gguf_free(struct gguf_context * ctx);
8483

@@ -200,3 +199,8 @@ extern "C" {
200199
#ifdef __cplusplus
201200
}
202201
#endif
202+
203+
#ifdef __cplusplus
204+
#include <ios>
205+
struct gguf_context * gguf_init_from_buffer(std::basic_streambuf<uint8_t>& streambuf, struct gguf_init_params params);
206+
#endif

ggml/src/gguf.cpp

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -216,14 +216,79 @@ struct gguf_context {
216216
void * data = nullptr;
217217
};
218218

219-
struct gguf_reader {
219+
struct gguf_bytes_reader {
220+
/// @brief Reads up to `count` objects into the array `buffer`.
221+
/// The position of the underlying stream implementation is advanced
222+
/// by the number of characters read.
223+
///
224+
/// @note If an error occurs, the resulting value of the underlying stream
225+
/// position indicator is indeterminate.
226+
virtual size_t read(void * buffer, size_t size, size_t count) = 0;
227+
228+
/// @brief Seeks to a position aligned to the given alignment boundary.
229+
/// @return The current position after alignment, or 0 on error.
230+
virtual size_t align(size_t alignment) = 0;
231+
232+
virtual ~gguf_bytes_reader() = 0;
233+
};
234+
235+
gguf_bytes_reader::~gguf_bytes_reader() {}
236+
237+
struct gguf_bytes_buffer_reader : public gguf_bytes_reader {
238+
gguf_bytes_buffer_reader(std::basic_streambuf<uint8_t> & streambuf) : streambuf(streambuf), offset(0) {}
239+
240+
~gguf_bytes_buffer_reader() {}
241+
242+
size_t read(void * buffer, size_t size, size_t count) override {
243+
size_t total_size = size * count;
244+
auto bytes_read = streambuf.sgetn(static_cast<uint8_t *>(buffer), total_size);
245+
offset += bytes_read;
246+
return bytes_read;
247+
}
248+
249+
size_t align(size_t alignment) override {
250+
size_t new_offset = GGML_PAD(offset, alignment);
251+
size_t seek_offset = new_offset - offset;
252+
253+
auto result = streambuf.pubseekoff(seek_offset, std::ios_base::cur);
254+
if (result == std::streampos(-1)) {
255+
return 0;
256+
}
257+
offset = new_offset;
258+
return offset;
259+
}
260+
261+
private:
262+
std::basic_streambuf<uint8_t> & streambuf;
263+
size_t offset;
264+
};
265+
266+
struct gguf_bytes_file_reader : public gguf_bytes_reader {
267+
gguf_bytes_file_reader(FILE * file) : file(file) {}
268+
269+
~gguf_bytes_file_reader() {}
270+
271+
size_t read(void * buffer, size_t size, size_t count) override { return fread(buffer, 1, size * count, file); }
272+
273+
size_t align(size_t alignment) override {
274+
if (fseek(file, GGML_PAD(ftell(file), alignment), SEEK_SET) != 0) {
275+
return 0;
276+
}
277+
return ftell(file);
278+
}
279+
280+
private:
220281
FILE * file;
282+
};
221283

222-
gguf_reader(FILE * file) : file(file) {}
284+
struct gguf_reader {
285+
gguf_bytes_reader& bytes_reader;
286+
287+
gguf_reader(gguf_bytes_reader& bytes_reader) : bytes_reader(bytes_reader) {}
223288

224289
template <typename T>
225290
bool read(T & dst) const {
226-
return fread(&dst, 1, sizeof(dst), file) == sizeof(dst);
291+
return bytes_reader.read(&dst, 1, sizeof(dst)) == sizeof(dst);
227292
}
228293

229294
template <typename T>
@@ -278,11 +343,11 @@ struct gguf_reader {
278343
return false;
279344
}
280345
dst.resize(size);
281-
return fread(dst.data(), 1, dst.length(), file) == dst.length();
346+
return bytes_reader.read(dst.data(), 1, dst.length()) == dst.length();
282347
}
283348

284349
bool read(void * dst, const size_t size) const {
285-
return fread(dst, 1, size, file) == size;
350+
return bytes_reader.read(dst, 1, size) == size;
286351
}
287352
};
288353

@@ -316,8 +381,8 @@ bool gguf_read_emplace_helper(const struct gguf_reader & gr, std::vector<struct
316381
return true;
317382
}
318383

319-
struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_params params) {
320-
const struct gguf_reader gr(file);
384+
namespace {
385+
struct gguf_context * gguf_init_from_reader_impl(const struct gguf_reader& gr, struct gguf_init_params params) {
321386
struct gguf_context * ctx = new gguf_context;
322387

323388
bool ok = true;
@@ -606,15 +671,14 @@ struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_par
606671
GGML_ASSERT(int64_t(ctx->info.size()) == n_tensors);
607672

608673
// we require the data section to be aligned, so take into account any padding
609-
if (fseek(file, GGML_PAD(ftell(file), ctx->alignment), SEEK_SET) != 0) {
610-
GGML_LOG_ERROR("%s: failed to seek to beginning of data section\n", __func__);
674+
// store the current file offset - this is where the data section starts
675+
ctx->offset = gr.bytes_reader.align(ctx->alignment);
676+
if (ctx->offset == 0) {
677+
GGML_LOG_ERROR("%s: failed to align data section\n", __func__);
611678
gguf_free(ctx);
612679
return nullptr;
613680
}
614681

615-
// store the current file offset - this is where the data section starts
616-
ctx->offset = ftell(file);
617-
618682
// compute the total size of the data section, taking into account the alignment
619683
{
620684
ctx->size = 0;
@@ -718,6 +782,13 @@ struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_par
718782

719783
return ctx;
720784
}
785+
}
786+
787+
struct gguf_context * gguf_init_from_file_impl(FILE * file, struct gguf_init_params params) {
788+
gguf_bytes_file_reader bytes_reader(file);
789+
gguf_reader reader(bytes_reader);
790+
return gguf_init_from_reader_impl(reader, params);
791+
}
721792

722793
struct gguf_context * gguf_init_from_file(const char * fname, struct gguf_init_params params) {
723794
FILE * file = ggml_fopen(fname, "rb");
@@ -732,6 +803,14 @@ struct gguf_context * gguf_init_from_file(const char * fname, struct gguf_init_p
732803
return result;
733804
}
734805

806+
#ifdef __cplusplus
807+
struct gguf_context * gguf_init_from_buffer(std::basic_streambuf<uint8_t> & streambuf, struct gguf_init_params params) {
808+
gguf_bytes_buffer_reader bytes_reader(streambuf);
809+
gguf_reader reader(bytes_reader);
810+
return gguf_init_from_reader_impl(reader, params);
811+
}
812+
#endif
813+
735814
void gguf_free(struct gguf_context * ctx) {
736815
if (ctx == nullptr) {
737816
return;

0 commit comments

Comments
 (0)