Imported Upstream version 2.4.2
[scm/test.git] / vendor / github.com / git-lfs / gitobj / pack / index_v2.go
1 package pack
2
3 import (
4         "encoding/binary"
5 )
6
7 // V2 implements IndexVersion for v2 packfiles.
8 type V2 struct{}
9
10 // Name implements IndexVersion.Name by returning the 20 byte SHA-1 object name
11 // for the given entry at offset "at" in the v2 index file "idx".
12 func (v *V2) Name(idx *Index, at int64) ([]byte, error) {
13         var sha [20]byte
14         if _, err := idx.readAt(sha[:], v2ShaOffset(at)); err != nil {
15                 return nil, err
16         }
17
18         return sha[:], nil
19 }
20
21 // Entry implements IndexVersion.Entry for v2 packfiles by parsing and returning
22 // the IndexEntry specified at the offset "at" in the given index file.
23 func (v *V2) Entry(idx *Index, at int64) (*IndexEntry, error) {
24         var offs [4]byte
25         if _, err := idx.readAt(offs[:], v2SmallOffsetOffset(at, int64(idx.Count()))); err != nil {
26                 return nil, err
27         }
28
29         loc := uint64(binary.BigEndian.Uint32(offs[:]))
30         if loc&0x80000000 > 0 {
31                 // If the most significant bit (MSB) of the offset is set, then
32                 // the offset encodes the indexed location for an 8-byte offset.
33                 //
34                 // Mask away (offs&0x7fffffff) the MSB to use as an index to
35                 // find the offset of the 8-byte pack offset.
36                 lo := v2LargeOffsetOffset(int64(loc&0x7fffffff), int64(idx.Count()))
37
38                 var offs [8]byte
39                 if _, err := idx.readAt(offs[:], lo); err != nil {
40                         return nil, err
41                 }
42
43                 loc = binary.BigEndian.Uint64(offs[:])
44         }
45         return &IndexEntry{PackOffset: loc}, nil
46 }
47
48 // Width implements IndexVersion.Width() by returning the number of bytes that
49 // v2 packfile index header occupy.
50 func (v *V2) Width() int64 {
51         return indexV2Width
52 }
53
54 // v2ShaOffset returns the offset of a SHA1 given at "at" in the V2 index file.
55 func v2ShaOffset(at int64) int64 {
56         // Skip the packfile index header and the L1 fanout table.
57         return indexOffsetV2Start +
58                 // Skip until the desired name in the sorted names table.
59                 (indexObjectNameWidth * at)
60 }
61
62 // v2SmallOffsetOffset returns the offset of an object's small (4-byte) offset
63 // given by "at".
64 func v2SmallOffsetOffset(at, total int64) int64 {
65         // Skip the packfile index header and the L1 fanout table.
66         return indexOffsetV2Start +
67                 // Skip the name table.
68                 (indexObjectNameWidth * total) +
69                 // Skip the CRC table.
70                 (indexObjectCRCWidth * total) +
71                 // Skip until the desired index in the small offsets table.
72                 (indexObjectSmallOffsetWidth * at)
73 }
74
75 // v2LargeOffsetOffset returns the offset of an object's large (4-byte) offset,
76 // given by the index "at".
77 func v2LargeOffsetOffset(at, total int64) int64 {
78         // Skip the packfile index header and the L1 fanout table.
79         return indexOffsetV2Start +
80                 // Skip the name table.
81                 (indexObjectNameWidth * total) +
82                 // Skip the CRC table.
83                 (indexObjectCRCWidth * total) +
84                 // Skip the small offsets table.
85                 (indexObjectSmallOffsetWidth * total) +
86                 // Seek to the large offset within the large offset(s) table.
87                 (indexObjectLargeOffsetWidth * at)
88 }