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
139
140
141
|
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package git
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"hash"
"strconv"
"strings"
)
type ObjectID interface {
String() string
IsZero() bool
RawValue() []byte
Type() ObjectFormat
}
type Sha1Hash [20]byte
func (h *Sha1Hash) String() string {
return hex.EncodeToString(h[:])
}
func (h *Sha1Hash) IsZero() bool {
empty := Sha1Hash{}
return bytes.Equal(empty[:], h[:])
}
func (h *Sha1Hash) RawValue() []byte { return h[:] }
func (*Sha1Hash) Type() ObjectFormat { return &Sha1ObjectFormat{} }
func NewSha1() *Sha1Hash {
return &Sha1Hash{}
}
// NewHash is for generic implementations
func NewHash(hash string) (ObjectID, error) {
hash = strings.ToLower(hash)
switch hash {
case "sha1":
return &Sha1Hash{}, nil
}
return nil, errors.New("unsupported hash type")
}
func IDFromRaw(h ObjectFormat, b []byte) (ObjectID, error) {
if len(b) != h.FullLength()/2 {
return h.Empty(), fmt.Errorf("length must be %d: %v", h.FullLength(), b)
}
return h.MustID(b), nil
}
func MustIDFromString(h ObjectFormat, s string) ObjectID {
b, _ := hex.DecodeString(s)
return h.MustID(b)
}
func genericIDFromString(h ObjectFormat, s string) (ObjectID, error) {
s = strings.TrimSpace(s)
if len(s) != h.FullLength() {
return h.Empty(), fmt.Errorf("length must be %d: %s", h.FullLength(), s)
}
b, err := hex.DecodeString(s)
if err != nil {
return h.Empty(), err
}
return h.NewID(b)
}
func IDFromString(hexHash string) (ObjectID, error) {
switch len(hexHash) {
case 40:
hashType := Sha1ObjectFormat{}
h, err := hashType.NewIDFromString(hexHash)
if err != nil {
return nil, err
}
return h, nil
}
return nil, fmt.Errorf("invalid hash hex string: '%s' len: %d", hexHash, len(hexHash))
}
func IsEmptyCommitID(commitID string) bool {
if commitID == "" {
return true
}
id, err := IDFromString(commitID)
if err != nil {
return false
}
return id.IsZero()
}
// HasherInterface is a struct that will generate a Hash
type HasherInterface interface {
hash.Hash
HashSum() ObjectID
}
type Sha1Hasher struct {
hash.Hash
}
// ComputeBlobHash compute the hash for a given blob content
func ComputeBlobHash(hashType ObjectFormat, content []byte) ObjectID {
return ComputeHash(hashType, ObjectBlob, content)
}
// ComputeHash compute the hash for a given ObjectType and content
func ComputeHash(hashType ObjectFormat, t ObjectType, content []byte) ObjectID {
h := hashType.NewHasher()
_, _ = h.Write(t.Bytes())
_, _ = h.Write([]byte(" "))
_, _ = h.Write([]byte(strconv.FormatInt(int64(len(content)), 10)))
_, _ = h.Write([]byte{0})
return h.HashSum()
}
// HashSum generates a SHA1 for the provided hash
func (h *Sha1Hasher) HashSum() ObjectID {
var sha1 Sha1Hash
copy(sha1[:], h.Hash.Sum(nil))
return &sha1
}
type ErrInvalidSHA struct {
SHA string
}
func (err ErrInvalidSHA) Error() string {
return fmt.Sprintf("invalid sha: %s", err.SHA)
}
|