refactor: use io.Reader instead of custom method

This commit is contained in:
Unlock Music Dev
2022-11-19 07:25:43 +08:00
parent 4365628bff
commit 67ff0c44cd
17 changed files with 420 additions and 460 deletions

View File

@@ -1,7 +1,6 @@
package kgm
import (
"bytes"
"fmt"
"io"
@@ -9,64 +8,48 @@ import (
)
type Decoder struct {
header Header
initializer kgmCryptoInitializer
header header
cipher common.StreamDecoder
file []byte
audio []byte
rd io.ReadSeeker
offset int
}
type kgmCryptoInitializer func(header *Header, body io.Reader) (io.Reader, error)
func NewDecoder(rd io.ReadSeeker) common.Decoder {
return &Decoder{rd: rd}
}
var kgmCryptoInitializers = map[uint32]kgmCryptoInitializer{
var kgmCryptoInitializers = map[uint32]func(header *header) (common.StreamDecoder, error){
3: newKgmCryptoV3,
}
func NewDecoder(file []byte) common.Decoder {
return &Decoder{
file: file,
}
}
func (d *Decoder) GetAudioData() []byte {
return d.audio
}
func (d *Decoder) GetAudioExt() string {
return "" // use sniffer
}
func (d *Decoder) GetMeta() common.Meta {
return nil
}
func (d *Decoder) Validate() error {
if err := d.header.FromBytes(d.file); err != nil {
if err := d.header.FromFile(d.rd); err != nil {
return err
}
// TODO; validate crypto version
var ok bool
d.initializer, ok = kgmCryptoInitializers[d.header.CryptoVersion]
initializer, ok := kgmCryptoInitializers[d.header.CryptoVersion]
if !ok {
return fmt.Errorf("kgm: unsupported crypto version %d", d.header.CryptoVersion)
}
var err error
d.cipher, err = initializer(&d.header)
if err != nil {
return fmt.Errorf("kgm: failed to initialize crypto: %w", err)
}
return nil
}
func (d *Decoder) Decode() error {
d.audio = d.file[d.header.AudioOffset:]
r, err := d.initializer(&d.header, bytes.NewReader(d.audio))
if err != nil {
return fmt.Errorf("kgm: failed to initialize crypto: %w", err)
func (d *Decoder) Read(buf []byte) (int, error) {
n, err := d.rd.Read(buf)
if n > 0 {
d.cipher.Decrypt(buf[:n], d.offset)
d.offset += n
}
d.audio, err = io.ReadAll(r)
if err != nil {
return fmt.Errorf("kgm: failed to decrypt audio: %w", err)
}
return nil
return n, err
}
func init() {

View File

@@ -21,8 +21,8 @@ var (
ErrKgmMagicHeader = errors.New("kgm magic header not matched")
)
// Header is the header of a KGM file.
type Header struct {
// header is the header of a KGM file.
type header struct {
MagicHeader []byte // 0x00-0x0f: magic header
AudioOffset uint32 // 0x10-0x13: offset of audio data
CryptoVersion uint32 // 0x14-0x17: crypto version
@@ -31,7 +31,7 @@ type Header struct {
CryptoKey []byte // 0x2c-0x3b: crypto key
}
func (h *Header) FromFile(rd io.ReadSeeker) error {
func (h *header) FromFile(rd io.ReadSeeker) error {
if _, err := rd.Seek(0, io.SeekStart); err != nil {
return fmt.Errorf("kgm seek start: %w", err)
}
@@ -44,7 +44,7 @@ func (h *Header) FromFile(rd io.ReadSeeker) error {
return h.FromBytes(buf)
}
func (h *Header) FromBytes(buf []byte) error {
func (h *header) FromBytes(buf []byte) error {
if len(buf) < 0x3c {
return errors.New("invalid kgm header length")
}

View File

@@ -3,24 +3,22 @@ package kgm
import (
"crypto/md5"
"fmt"
"io"
"github.com/unlock-music/cli/algo/common"
)
// kgmCryptoV3 is kgm file crypto v3
type kgmCryptoV3 struct {
slotBox []byte
fileBox []byte
rd io.Reader
offset int
}
var kgmV3Slot2Key = map[uint32][]byte{
1: {0x6C, 0x2C, 0x2F, 0x27},
}
func newKgmCryptoV3(header *Header, body io.Reader) (io.Reader, error) {
c := &kgmCryptoV3{rd: body}
func newKgmCryptoV3(header *header) (common.StreamDecoder, error) {
c := &kgmCryptoV3{}
slotKey, ok := kgmV3Slot2Key[header.CryptoSlot]
if !ok {
@@ -33,16 +31,7 @@ func newKgmCryptoV3(header *Header, body io.Reader) (io.Reader, error) {
return c, nil
}
func (d *kgmCryptoV3) Read(buf []byte) (int, error) {
n, err := d.rd.Read(buf)
if n > 0 {
d.decrypt(buf[:n], d.offset)
d.offset += n
}
return n, err
}
func (d *kgmCryptoV3) decrypt(b []byte, offset int) {
func (d *kgmCryptoV3) Decrypt(b []byte, offset int) {
for i := 0; i < len(b); i++ {
b[i] ^= d.fileBox[(offset+i)%len(d.fileBox)]
b[i] ^= b[i] << 4