1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
package furgit
import (
"crypto/sha1"
"crypto/sha256"
"encoding/hex"
"hash"
)
// maxHashSize MUST be >= the largest supported algorithm size.
const maxHashSize = sha256.Size
// hashAlgorithm identifies the hash algorithm used for Git object IDs.
type hashAlgorithm uint8
const (
hashAlgoUnknown hashAlgorithm = iota
hashAlgoSHA1
hashAlgoSHA256
)
type hashAlgorithmDetails struct {
name string
size int
sum func([]byte) Hash
new func() hash.Hash
}
var hashAlgorithmTable = [...]hashAlgorithmDetails{
hashAlgoUnknown: {},
hashAlgoSHA1: {
name: "sha1",
size: sha1.Size,
sum: func(data []byte) Hash {
sum := sha1.Sum(data)
var h Hash
copy(h.data[:], sum[:])
h.algo = hashAlgoSHA1
return h
},
new: func() hash.Hash {
return sha1.New()
},
},
hashAlgoSHA256: {
name: "sha256",
size: sha256.Size,
sum: func(data []byte) Hash {
sum := sha256.Sum256(data)
var h Hash
copy(h.data[:], sum[:])
h.algo = hashAlgoSHA256
return h
},
new: func() hash.Hash {
return sha256.New()
},
},
}
func (algo hashAlgorithm) info() hashAlgorithmDetails {
return hashAlgorithmTable[algo]
}
// Size returns the hash size in bytes.
func (algo hashAlgorithm) Size() int {
return algo.info().size
}
// String returns the canonical name of the hash algorithm.
func (algo hashAlgorithm) String() string {
inf := algo.info()
if inf.name == "" {
return "unknown"
}
return inf.name
}
func (algo hashAlgorithm) HexLen() int {
return algo.Size() * 2
}
func (algo hashAlgorithm) Sum(data []byte) Hash {
return algo.info().sum(data)
}
func (algo hashAlgorithm) New() (hash.Hash, error) {
newFn := algo.info().new
if newFn == nil {
return nil, ErrInvalidObject
}
return newFn(), nil
}
// Hash represents a Git object ID.
type Hash struct {
algo hashAlgorithm
data [maxHashSize]byte
}
// String returns a hexadecimal string representation of the hash.
func (hash Hash) String() string {
size := hash.algo.Size()
if size == 0 {
return ""
}
return hex.EncodeToString(hash.data[:size])
}
// Bytes returns a copy of the hash's bytes.
func (hash Hash) Bytes() []byte {
size := hash.algo.Size()
if size == 0 {
return nil
}
return append([]byte(nil), hash.data[:size]...)
}
// Size returns the hash size.
func (hash Hash) Size() int {
return hash.algo.Size()
}
var algoByName = map[string]hashAlgorithm{}
func init() {
for algo, info := range hashAlgorithmTable {
if info.name == "" {
continue
}
algoByName[info.name] = hashAlgorithm(algo)
}
}
func parseHashAlgorithm(s string) (hashAlgorithm, bool) {
algo, ok := algoByName[s]
return algo, ok
}
|