diff options
Diffstat (limited to 'modules/git/object_format.go')
-rw-r--r-- | modules/git/object_format.go | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/modules/git/object_format.go b/modules/git/object_format.go new file mode 100644 index 00000000..db9120d8 --- /dev/null +++ b/modules/git/object_format.go @@ -0,0 +1,143 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "crypto/sha1" + "crypto/sha256" + "hash" + "regexp" + "strconv" +) + +// sha1Pattern can be used to determine if a string is an valid sha +var sha1Pattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`) + +// sha256Pattern can be used to determine if a string is an valid sha +var sha256Pattern = regexp.MustCompile(`^[0-9a-f]{4,64}$`) + +type ObjectFormat interface { + // Name returns the name of the object format + Name() string + // EmptyObjectID creates a new empty ObjectID from an object format hash name + EmptyObjectID() ObjectID + // EmptyTree is the hash of an empty tree + EmptyTree() ObjectID + // FullLength is the length of the hash's hex string + FullLength() int + // IsValid returns true if the input is a valid hash + IsValid(input string) bool + // MustID creates a new ObjectID from a byte slice + MustID(b []byte) ObjectID + // ComputeHash compute the hash for a given ObjectType and content + ComputeHash(t ObjectType, content []byte) ObjectID +} + +func computeHash(dst []byte, hasher hash.Hash, t ObjectType, content []byte) { + _, _ = hasher.Write(t.Bytes()) + _, _ = hasher.Write([]byte(" ")) + _, _ = hasher.Write([]byte(strconv.Itoa(len(content)))) + _, _ = hasher.Write([]byte{0}) + _, _ = hasher.Write(content) + hasher.Sum(dst) +} + +/* SHA1 Type */ +type Sha1ObjectFormatImpl struct{} + +var ( + emptySha1ObjectID = &Sha1Hash{} + emptySha1Tree = &Sha1Hash{ + 0x4b, 0x82, 0x5d, 0xc6, 0x42, 0xcb, 0x6e, 0xb9, 0xa0, 0x60, + 0xe5, 0x4b, 0xf8, 0xd6, 0x92, 0x88, 0xfb, 0xee, 0x49, 0x04, + } +) + +func (Sha1ObjectFormatImpl) Name() string { return "sha1" } +func (Sha1ObjectFormatImpl) EmptyObjectID() ObjectID { + return emptySha1ObjectID +} + +func (Sha1ObjectFormatImpl) EmptyTree() ObjectID { + return emptySha1Tree +} +func (Sha1ObjectFormatImpl) FullLength() int { return 40 } +func (Sha1ObjectFormatImpl) IsValid(input string) bool { + return sha1Pattern.MatchString(input) +} + +func (Sha1ObjectFormatImpl) MustID(b []byte) ObjectID { + var id Sha1Hash + copy(id[0:20], b) + return &id +} + +// ComputeHash compute the hash for a given ObjectType and content +func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID { + var obj Sha1Hash + computeHash(obj[:0], sha1.New(), t, content) + return &obj +} + +/* SHA256 Type */ +type Sha256ObjectFormatImpl struct{} + +var ( + emptySha256ObjectID = &Sha256Hash{} + emptySha256Tree = &Sha256Hash{ + 0x6e, 0xf1, 0x9b, 0x41, 0x22, 0x5c, 0x53, 0x69, 0xf1, 0xc1, + 0x04, 0xd4, 0x5d, 0x8d, 0x85, 0xef, 0xa9, 0xb0, 0x57, 0xb5, + 0x3b, 0x14, 0xb4, 0xb9, 0xb9, 0x39, 0xdd, 0x74, 0xde, 0xcc, + 0x53, 0x21, + } +) + +func (Sha256ObjectFormatImpl) Name() string { return "sha256" } +func (Sha256ObjectFormatImpl) EmptyObjectID() ObjectID { + return emptySha256ObjectID +} + +func (Sha256ObjectFormatImpl) EmptyTree() ObjectID { + return emptySha256Tree +} +func (Sha256ObjectFormatImpl) FullLength() int { return 64 } +func (Sha256ObjectFormatImpl) IsValid(input string) bool { + return sha256Pattern.MatchString(input) +} + +func (Sha256ObjectFormatImpl) MustID(b []byte) ObjectID { + var id Sha256Hash + copy(id[0:32], b) + return &id +} + +// ComputeHash compute the hash for a given ObjectType and content +func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID { + var obj Sha256Hash + computeHash(obj[:0], sha256.New(), t, content) + return &obj +} + +var ( + Sha1ObjectFormat ObjectFormat = Sha1ObjectFormatImpl{} + Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{} + // any addition must be reflected in IsEmptyCommitID +) + +var SupportedObjectFormats = []ObjectFormat{ + Sha1ObjectFormat, +} + +func ObjectFormatFromName(name string) ObjectFormat { + for _, objectFormat := range SupportedObjectFormats { + if name == objectFormat.Name() { + return objectFormat + } + } + return nil +} + +func IsValidObjectFormat(name string) bool { + return ObjectFormatFromName(name) != nil +} |