hanayo/vendor/github.com/osuripple/cheesegull/housekeeper/binarystate.go
2019-02-23 13:29:15 +00:00

114 lines
2.3 KiB
Go

package housekeeper
import (
"encoding"
"errors"
"io"
)
const cachedBeatmapBinSize = 8 + 1 + 15 + 15 + 8
func b2i(b bool) byte {
if b {
return 1
}
return 0
}
func marshalBinaryCopy(dst []byte, t encoding.BinaryMarshaler) {
b, _ := t.MarshalBinary()
copy(dst, b)
}
// copied from binary.BigEndian
func putUint64(b []byte, v uint64) {
_ = b[7] // boundary check
b[0] = byte(v >> 56)
b[1] = byte(v >> 48)
b[2] = byte(v >> 40)
b[3] = byte(v >> 32)
b[4] = byte(v >> 24)
b[5] = byte(v >> 16)
b[6] = byte(v >> 8)
b[7] = byte(v)
}
func writeBeatmaps(w io.Writer, c []*CachedBeatmap) error {
_, err := w.Write(append([]byte("CGBIN001"), cachedBeatmapBinSize))
if err != nil {
return err
}
for _, b := range c {
if b == nil || !b.isDownloaded {
continue
}
enc := make([]byte, cachedBeatmapBinSize)
putUint64(enc[:8], uint64(b.ID))
enc[8] = b2i(b.NoVideo)
marshalBinaryCopy(enc[9:24], b.LastUpdate)
marshalBinaryCopy(enc[24:39], b.lastRequested)
putUint64(enc[39:47], b.fileSize)
_, err := w.Write(enc)
if err != nil {
return err
}
}
return nil
}
// copied from binary.BigEndian
func readUint64(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
func readCachedBeatmap(b []byte) *CachedBeatmap {
m := &CachedBeatmap{}
m.ID = int(readUint64(b[:8]))
m.NoVideo = b[8] == 1
(&m.LastUpdate).UnmarshalBinary(b[9:24])
(&m.lastRequested).UnmarshalBinary(b[24:39])
m.fileSize = readUint64(b[39:47])
m.isDownloaded = true
return m
}
func readBeatmaps(r io.Reader) ([]*CachedBeatmap, error) {
b := make([]byte, 8)
_, err := r.Read(b)
if err != nil {
return nil, err
}
if string(b) != "CGBIN001" {
return nil, errors.New("unknown cgbin version")
}
b = make([]byte, 1)
_, err = r.Read(b)
if err != nil {
return nil, err
}
bmLength := b[0]
if bmLength == 0 {
return nil, nil
}
b = make([]byte, bmLength)
beatmaps := make([]*CachedBeatmap, 0, 50)
for {
read, err := r.Read(b)
switch {
case err == io.EOF:
return beatmaps, nil
case err != nil:
return nil, err
case byte(read) != bmLength:
return beatmaps, nil
}
beatmaps = append(beatmaps, readCachedBeatmap(b))
}
}