aboutsummaryrefslogtreecommitdiff
path: root/format/pack/entry.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-02-21 19:00:01 +0800
committerGravatar Runxi Yu2026-02-21 19:18:45 +0800
commitd951176970f646b1cc2e586f8b5fda31c93365c5 (patch)
treed2248307ae4b4b964f1661648964ac65f946e658 /format/pack/entry.go
parentformat/pack: Extract general constants and such from objectstore/packed (diff)
signatureNo signature
objectstore/packed: Use constants/functions from format/pack
Diffstat (limited to 'format/pack/entry.go')
-rw-r--r--format/pack/entry.go64
1 files changed, 64 insertions, 0 deletions
diff --git a/format/pack/entry.go b/format/pack/entry.go
index 512b45f8..b95ad0ac 100644
--- a/format/pack/entry.go
+++ b/format/pack/entry.go
@@ -46,3 +46,67 @@ func ParseEntryHeader(data []byte) (EntryHeader, error) {
}
return header, nil
}
+
+// 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("format/pack: invalid hash size %d", hashSize)
+ }
+ end := entry.DataOffset + hashSize
+ if end > len(data) {
+ return zero, fmt.Errorf("format/pack: 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("format/pack: unsupported object type %d", entry.Type)
+ default:
+ return zero, fmt.Errorf("format/pack: unsupported object type %d", entry.Type)
+ }
+
+ if entry.DataOffset > len(data) {
+ return zero, fmt.Errorf("format/pack: entry data offset out of bounds")
+ }
+ return entry, nil
+}