| 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 | |
| } | |