From ae879b8cf5a87199802a33d6b15c76afafa8002b Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sat, 21 Feb 2026 05:35:12 +0800 Subject: objectstore/packed: Add initial pack reading support --- objectstore/packed/read_reader.go | 93 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 objectstore/packed/read_reader.go (limited to 'objectstore/packed/read_reader.go') diff --git a/objectstore/packed/read_reader.go b/objectstore/packed/read_reader.go new file mode 100644 index 00000000..4f40792d --- /dev/null +++ b/objectstore/packed/read_reader.go @@ -0,0 +1,93 @@ +package packed + +import ( + "bytes" + "fmt" + "io" + + "codeberg.org/lindenii/furgit/objectheader" + "codeberg.org/lindenii/furgit/objectid" + "codeberg.org/lindenii/furgit/objecttype" +) + +// readCloser proxies reads and closes one underlying closer. +type readCloser struct { + reader io.Reader + closer io.Closer +} + +// Read proxies reads to the underlying reader. +func (reader *readCloser) Read(dst []byte) (int, error) { + return reader.reader.Read(dst) +} + +// Close closes the underlying closer. +func (reader *readCloser) Close() error { + return reader.closer.Close() +} + +// ReadReaderContent reads an object's type, declared content size, and content stream. +// +// The caller must close the returned reader. +func (store *Store) ReadReaderContent(id objectid.ObjectID) (objecttype.Type, int64, io.ReadCloser, error) { + loc, err := store.lookup(id) + if err != nil { + return objecttype.TypeInvalid, 0, nil, err + } + + pack, meta, err := store.entryMetaAt(loc) + if err != nil { + return objecttype.TypeInvalid, 0, nil, err + } + if isBaseObjectType(meta.ty) { + zr, err := zlibReaderAt(pack, meta.dataOffset) + if err != nil { + return objecttype.TypeInvalid, 0, nil, err + } + return meta.ty, meta.size, &readCloser{ + reader: io.LimitReader(zr, meta.size), + closer: zr, + }, nil + } + + ty, content, err := store.deltaResolveContent(loc) + if err != nil { + return objecttype.TypeInvalid, 0, nil, err + } + return ty, int64(len(content)), io.NopCloser(bytes.NewReader(content)), nil +} + +// ReadReaderFull reads a full serialized object stream as "type size\0content". +// +// The caller must close the returned reader. +func (store *Store) ReadReaderFull(id objectid.ObjectID) (io.ReadCloser, error) { + loc, err := store.lookup(id) + if err != nil { + return nil, err + } + + pack, meta, err := store.entryMetaAt(loc) + if err != nil { + return nil, err + } + if isBaseObjectType(meta.ty) { + header, ok := objectheader.Encode(meta.ty, meta.size) + if !ok { + return nil, fmt.Errorf("objectstore/packed: failed to encode object header for type %d", meta.ty) + } + zr, err := zlibReaderAt(pack, meta.dataOffset) + if err != nil { + return nil, err + } + return &readCloser{ + reader: io.MultiReader(bytes.NewReader(header), io.LimitReader(zr, meta.size)), + closer: zr, + }, nil + } + + raw, err := store.ReadBytesFull(id) + if err != nil { + return nil, err + } + return io.NopCloser(bytes.NewReader(raw)), nil +} -- cgit v1.3.1-10-gc9f91