package hash_extend import ( "crypto/sha1" "encoding" "fmt" "hash" "strconv" "github.com/alist-org/alist/v3/pkg/utils" ) var GCID = utils.RegisterHashWithParam("gcid", "GCID", 40, func(a ...any) hash.Hash { var ( size int64 err error ) if len(a) > 0 { size, err = strconv.ParseInt(fmt.Sprint(a[0]), 10, 64) if err != nil { panic(err) } } return NewGcid(size) }) func NewGcid(size int64) hash.Hash { calcBlockSize := func(j int64) int64 { var psize int64 = 0x40000 for float64(j)/float64(psize) > 0x200 && psize < 0x200000 { psize = psize << 1 } return psize } return &gcid{ hash: sha1.New(), hashState: sha1.New(), blockSize: int(calcBlockSize(size)), } } type gcid struct { hash hash.Hash hashState hash.Hash blockSize int offset int } func (h *gcid) Write(p []byte) (n int, err error) { n = len(p) for len(p) > 0 { if h.offset < h.blockSize { var lastSize = h.blockSize - h.offset if lastSize > len(p) { lastSize = len(p) } h.hashState.Write(p[:lastSize]) h.offset += lastSize p = p[lastSize:] } if h.offset >= h.blockSize { h.hash.Write(h.hashState.Sum(nil)) h.hashState.Reset() h.offset = 0 } } return } func (h *gcid) Sum(b []byte) []byte { if h.offset != 0 { if hashm, ok := h.hash.(encoding.BinaryMarshaler); ok { if hashum, ok := h.hash.(encoding.BinaryUnmarshaler); ok { tempData, _ := hashm.MarshalBinary() defer hashum.UnmarshalBinary(tempData) h.hash.Write(h.hashState.Sum(nil)) } } } return h.hash.Sum(b) } func (h *gcid) Reset() { h.hash.Reset() h.hashState.Reset() } func (h *gcid) Size() int { return h.hash.Size() } func (h *gcid) BlockSize() int { return h.blockSize }