aboutsummaryrefslogtreecommitdiff
path: root/format/packfile/entry.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-26 09:17:14 +0000
committerGravatar Runxi Yu2026-03-26 09:18:30 +0000
commit3e884f5f3d42cbc4874a04da31dde10314b0cfad (patch)
treef5e1e325fd1a2a0801791c054010213214475d80 /format/packfile/entry.go
parentnetwork/receivepack: Rename from receivepack (diff)
signatureNo signature
format: Move commitgraph and packfile here
Diffstat (limited to 'format/packfile/entry.go')
-rw-r--r--format/packfile/entry.go76
1 files changed, 76 insertions, 0 deletions
diff --git a/format/packfile/entry.go b/format/packfile/entry.go
new file mode 100644
index 00000000..0f9c7c8d
--- /dev/null
+++ b/format/packfile/entry.go
@@ -0,0 +1,76 @@
+package packfile
+
+import (
+ "fmt"
+
+ objecttype "codeberg.org/lindenii/furgit/object/type"
+)
+
+// Entry is one parsed pack entry prefix, including any delta base reference
+// data that appears before the compressed payload.
+type Entry struct {
+ // Type is the pack entry type.
+ Type objecttype.Type
+ // Size is the declared resulting object size.
+ Size int64
+ // DataOffset is the byte offset from the start of the entry to the zlib
+ // payload bytes.
+ DataOffset int
+ // RefBaseID is the referenced base object ID bytes for ref-delta entries.
+ RefBaseID []byte
+ // OfsBaseDistance is the backward distance for ofs-delta entries.
+ OfsBaseDistance uint64
+}
+
+// ParseEntry parses one full pack entry prefix from data.
+//
+// hashSize must match the hash algorithm size used by the pack/index.
+func ParseEntry(data []byte, hashSize int) (Entry, error) {
+ var zero Entry
+
+ header, err := ParseEntryHeader(data)
+ if err != nil {
+ return zero, err
+ }
+
+ entry := Entry{
+ Type: header.Type,
+ Size: header.Size,
+ DataOffset: header.HeaderSize,
+ }
+
+ switch entry.Type {
+ case objecttype.TypeCommit, objecttype.TypeTree, objecttype.TypeBlob, objecttype.TypeTag:
+ // Base object entries have no extra prefix fields.
+ case objecttype.TypeRefDelta:
+ if hashSize <= 0 {
+ return zero, fmt.Errorf("packfile: invalid hash size %d", hashSize)
+ }
+
+ end := entry.DataOffset + hashSize
+ if end > len(data) {
+ return zero, fmt.Errorf("packfile: truncated ref-delta base id")
+ }
+
+ entry.RefBaseID = data[entry.DataOffset:end]
+ entry.DataOffset = end
+ case objecttype.TypeOfsDelta:
+ dist, consumed, err := ParseOfsDeltaDistance(data[entry.DataOffset:])
+ if err != nil {
+ return zero, err
+ }
+
+ entry.OfsBaseDistance = dist
+ entry.DataOffset += consumed
+ case objecttype.TypeInvalid, objecttype.TypeFuture:
+ return zero, fmt.Errorf("packfile: unsupported object type %d", entry.Type)
+ default:
+ return zero, fmt.Errorf("packfile: unsupported object type %d", entry.Type)
+ }
+
+ if entry.DataOffset > len(data) {
+ return zero, fmt.Errorf("packfile: entry data offset out of bounds")
+ }
+
+ return entry, nil
+}