init: dec-music 项目初始化
This commit is contained in:
+105
@@ -0,0 +1,105 @@
|
||||
package mmkv
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
|
||||
"jsuse.com/dev/dec-music/mmkv/internal"
|
||||
)
|
||||
|
||||
type vault map[string][]byte
|
||||
|
||||
func (v vault) keys() []string {
|
||||
keys := make([]string, 0, len(v))
|
||||
for k := range v {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (v vault) Keys() []string {
|
||||
return v.keys()
|
||||
}
|
||||
|
||||
func (v vault) GetRaw(key string) ([]byte, bool) {
|
||||
val, ok := v[key]
|
||||
return val, ok
|
||||
}
|
||||
|
||||
func (v vault) GetBytes(key string) ([]byte, error) {
|
||||
raw, ok := v[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("key not found: %s", key)
|
||||
}
|
||||
|
||||
val, n := internal.ConsumeBytes(raw)
|
||||
if n < 0 {
|
||||
return nil, fmt.Errorf("invalid protobuf bytes")
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (v vault) GetString(key string) (string, error) {
|
||||
val, err := v.GetBytes(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(val), nil
|
||||
}
|
||||
|
||||
func loadVault(src io.Reader, m *metadata, cryptoKey string) (Vault, error) {
|
||||
fileSizeBuf := make([]byte, 4)
|
||||
_, err := io.ReadFull(src, fileSizeBuf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file size: %w", err)
|
||||
}
|
||||
size := binary.LittleEndian.Uint32(fileSizeBuf)
|
||||
|
||||
if m != nil && size != m.actualSize {
|
||||
return nil, fmt.Errorf("metadata and vault payload size mismatch")
|
||||
}
|
||||
|
||||
buf := make([]byte, size)
|
||||
_, err = io.ReadFull(src, buf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
|
||||
if m != nil && m.crc32 != crc32.ChecksumIEEE(buf) {
|
||||
return nil, fmt.Errorf("metadata and vault payload crc32 mismatch")
|
||||
}
|
||||
|
||||
if len(cryptoKey) > 0 {
|
||||
mKey := make([]byte, aes.BlockSize)
|
||||
copy(mKey, cryptoKey)
|
||||
|
||||
block, err := aes.NewCipher(mKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create aes cipher")
|
||||
}
|
||||
stream := cipher.NewCFBDecrypter(block, m.aesVector)
|
||||
stream.XORKeyStream(buf, buf)
|
||||
}
|
||||
|
||||
v := make(vault)
|
||||
rd := internal.NewProtoBuffer(buf[4:])
|
||||
|
||||
for len(rd.Unread()) > 0 {
|
||||
key, err := rd.DecodeStringBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode key: %w", err)
|
||||
}
|
||||
val, err := rd.DecodeRawBytes(false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode value: %w", err)
|
||||
}
|
||||
v[key] = val
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
Reference in New Issue
Block a user