JCS-pub/common/types/filehash.go

92 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package jcstypes
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
)
// 文件的哈希值,格式:[前缀: 4个字符][哈希值: 64个字符]
// 前缀用于区分哈希值的类型:
//
// - "Full":完整文件的哈希值
//
// - "Comp"将文件拆分成多个分片每一个分片计算Hash之后再合并的哈希值
//
// 哈希值SHA256哈希值全大写的16进制字符串格式
type FileHash string
const (
FullHashPrefix = "Full"
CompositeHashPrefix = "Comp"
EmptyHash = FileHash("Full0000000000000000000000000000000000000000000000000000000000000000")
)
func (h *FileHash) GetPrefix() string {
return string((*h)[:4])
}
func (h *FileHash) GetHash() string {
return string((*h)[4:])
}
// 由调用者保证Hash值有效
func (h *FileHash) GetHashBytes() []byte {
bytes, _ := hex.DecodeString(h.GetHash())
return bytes
}
func (h *FileHash) GetHashPrefix(len int) string {
return string((*h)[4 : 4+len])
}
func (h *FileHash) IsFullHash() bool {
return (*h)[:4] == FullHashPrefix
}
func (h *FileHash) IsCompositeHash() bool {
return (*h)[:4] == CompositeHashPrefix
}
func ParseHash(hashStr string) (FileHash, error) {
if len(hashStr) != 4+64 {
return "", fmt.Errorf("hash string length should be 4+64, but got %d", len(hashStr))
}
prefix := hashStr[:4]
hash := hashStr[4:]
if prefix != FullHashPrefix && prefix != CompositeHashPrefix {
return "", fmt.Errorf("invalid hash prefix: %s", prefix)
}
if len(hash) != 64 {
return "", fmt.Errorf("invalid hash length: %d", len(hash))
}
for _, c := range hash {
if (c < '0' || c > '9') && (c < 'A' || c > 'F') {
return "", fmt.Errorf("invalid hash character: %c", c)
}
}
return FileHash(hashStr), nil
}
func NewFullHash(hash []byte) FileHash {
return FileHash(FullHashPrefix + strings.ToUpper(hex.EncodeToString(hash)))
}
func NewFullHashFromString(hashStr string) FileHash {
return FileHash(FullHashPrefix + strings.ToUpper(hashStr))
}
func CalculateCompositeHash(segmentHashes [][]byte) FileHash {
data := make([]byte, len(segmentHashes)*32)
for i, segmentHash := range segmentHashes {
copy(data[i*32:], segmentHash)
}
hash := sha256.Sum256(data)
return FileHash(CompositeHashPrefix + strings.ToUpper(hex.EncodeToString(hash[:])))
}