aboutsummaryrefslogtreecommitdiff
path: root/object/storer/packed/entry_parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'object/storer/packed/entry_parse.go')
-rw-r--r--object/storer/packed/entry_parse.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/object/storer/packed/entry_parse.go b/object/storer/packed/entry_parse.go
new file mode 100644
index 00000000..bbbbc469
--- /dev/null
+++ b/object/storer/packed/entry_parse.go
@@ -0,0 +1,71 @@
+package packed
+
+import (
+ "fmt"
+
+ "codeberg.org/lindenii/furgit/internal/intconv"
+ objectid "codeberg.org/lindenii/furgit/object/id"
+ objecttype "codeberg.org/lindenii/furgit/object/type"
+ packfmt "codeberg.org/lindenii/furgit/packfile"
+)
+
+// entryMeta describes one parsed pack entry header.
+type entryMeta struct {
+ // ty is the pack entry type tag.
+ ty objecttype.Type
+ // size is the declared resulting content size.
+ size int64
+ // dataOffset points to the zlib payload start.
+ dataOffset int
+ // baseRefID is set for ref-delta entries.
+ baseRefID objectid.ObjectID
+ // baseOfs is set for ofs-delta entries.
+ baseOfs uint64
+}
+
+// parseEntryMeta parses one pack entry header at offset.
+func parseEntryMeta(pack *packFile, algo objectid.Algorithm, offset uint64) (entryMeta, error) {
+ var zero entryMeta
+ if offset >= uint64(len(pack.data)) {
+ return zero, fmt.Errorf("objectstorer/packed: pack %q offset %d out of bounds", pack.name, offset)
+ }
+
+ pos, err := intconv.Uint64ToInt(offset)
+ if err != nil {
+ return zero, fmt.Errorf("objectstorer/packed: pack %q offset conversion: %w", pack.name, err)
+ }
+
+ entry, err := packfmt.ParseEntry(pack.data[pos:], algo.Size())
+ if err != nil {
+ return zero, fmt.Errorf("objectstorer/packed: pack %q: %w", pack.name, err)
+ }
+
+ meta := entryMeta{
+ ty: entry.Type,
+ size: entry.Size,
+ dataOffset: pos + entry.DataOffset,
+ }
+ switch meta.ty {
+ case objecttype.TypeRefDelta:
+ baseID, err := objectid.FromBytes(algo, entry.RefBaseID)
+ if err != nil {
+ return zero, fmt.Errorf("objectstorer/packed: pack %q invalid ref-delta base id: %w", pack.name, err)
+ }
+
+ meta.baseRefID = baseID
+ case objecttype.TypeOfsDelta:
+ if offset <= entry.OfsBaseDistance {
+ return zero, fmt.Errorf("objectstorer/packed: pack %q has invalid ofs-delta base", pack.name)
+ }
+
+ meta.baseOfs = offset - entry.OfsBaseDistance
+ case objecttype.TypeCommit, objecttype.TypeTree, objecttype.TypeBlob, objecttype.TypeTag:
+ // Base object types do not have delta base metadata.
+ case objecttype.TypeInvalid, objecttype.TypeFuture:
+ return zero, fmt.Errorf("objectstorer/packed: pack %q has unsupported entry type %d", pack.name, meta.ty)
+ default:
+ return zero, fmt.Errorf("objectstorer/packed: pack %q has unsupported entry type %d", pack.name, meta.ty)
+ }
+
+ return meta, nil
+}