Skip to content

Commit

Permalink
feat: operation deep freeze support
Browse files Browse the repository at this point in the history
  • Loading branch information
redraskal committed Nov 16, 2023
1 parent 24f513e commit 6582698
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 32 deletions.
16 changes: 16 additions & 0 deletions dissect/header.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dissect

import (
"bufio"
"bytes"
"encoding/json"
"strconv"
Expand Down Expand Up @@ -107,6 +108,7 @@ const (
StadiumBravo Map = 270063334510
NighthavenLabs Map = 378595635123
Consulate Map = 379218689149
Lair Map = 388073319671

KilledOpponents WinCondition = "KilledOpponents"
SecuredArea WinCondition = "SecuredArea" // TODO
Expand Down Expand Up @@ -188,6 +190,7 @@ const (
Clash Operator = 104189662280
Fenrir Operator = 288200867339
Ram Operator = 395943091136
Tubarao Operator = 288200867549
)

// duplicated code here could be avoided by defining a generic function accepting any Number type.
Expand Down Expand Up @@ -266,6 +269,19 @@ func (h Header) RecordingPlayer() Player {
return Player{}
}

func testFileCompression(in *bufio.Reader) (chunkedCompression bool, err error) {
magic, err := in.Peek(4)
if err != nil {
return false, err
}
if bytes.Equal(magic, []byte{0x28, 0xB5, 0x2F, 0xFD}) {
return false, nil
} else if bytes.Equal(magic, []byte{0x64, 0x69, 0x73, 0x73}) {
return true, nil
}
return false, ErrInvalidFile
}

// readHeaderMagic reads the header magic of the reader
// and validates the dissect format.
// If there is an error, it will be of type *ErrInvalidFile.
Expand Down
4 changes: 3 additions & 1 deletion dissect/map_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dissect/operator_roles.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 13 additions & 11 deletions dissect/operator_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 88 additions & 20 deletions dissect/reader.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dissect

import (
"bufio"
"bytes"
"encoding/binary"
"errors"
Expand All @@ -17,8 +18,6 @@ import (
var strSep = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}

type Reader struct {
reader *io.Reader
compressed *zstd.Decoder
b []byte
offset int
queries [][]byte
Expand All @@ -36,41 +35,110 @@ type Reader struct {
// NewReader decompresses in using zstd and
// validates the dissect header.
func NewReader(in io.Reader) (r *Reader, err error) {
compressed, err := zstd.NewReader(in)
internalReader := bufio.NewReader(in)
chunkedCompression, err := testFileCompression(internalReader)
if err != nil {
return
return nil, err
}
log.Debug().Bool("chunkedCompression (>=Y8S4)", chunkedCompression).Send()
r = &Reader{
compressed: compressed,
reader: &in,
readPartial: false,
}
b, err := io.ReadAll(r.compressed)
if err != nil && !(len(b) > 0 && errors.Is(err, zstd.ErrMagicMismatch)) {
return
if chunkedCompression {
log.Debug().Msg("creating header buffer")
headerBuffer := make([]byte, 2000)
n, err := internalReader.Read(headerBuffer)
if err != nil {
return nil, err
}
if n != 2000 {
return nil, ErrInvalidFile
}
r.b = headerBuffer
log.Debug().Msg("reading header magic")
if err = r.readHeaderMagic(); err != nil {
return nil, err
}
log.Debug().Msg("reading header")
h, err := r.readHeader()
r.Header = h
if err != nil {
return nil, err
}
pattern := []byte{0x32, 0x30, 0x30, 0x56, 0x52, 0x50, 0x4D, 0x43}
i := 0
r.b = []byte{}
zstdReader, _ := zstd.NewReader(internalReader)
for !errors.Is(err, io.EOF) {
log.Debug().Msg("scanning for dissect frame")
for i != 8 {
b, scanErr := internalReader.ReadByte()
if errors.Is(scanErr, io.EOF) {
err = scanErr
break
}
if scanErr != nil {
return nil, scanErr
}
if b == pattern[i] {
i++
} else {
i = 0
}
}
if errors.Is(err, io.EOF) {
break
}
i = 0
_, err := internalReader.Discard(8)
if err != nil {
return nil, err
}
log.Debug().Msg("reading zstd frame")
if err = zstdReader.Reset(internalReader); err != nil {
return nil, err
}
decompressed, err := io.ReadAll(zstdReader)
if err != nil && !(len(decompressed) > 0 && errors.Is(err, zstd.ErrMagicMismatch)) {
return nil, err
}
log.Debug().Msg("writing decompressed frame")
for _, b := range decompressed {
r.b = append(r.b, b)
}
}
} else {
zstdReader, err := zstd.NewReader(internalReader)
if err != nil {
return nil, err
}
decompressed, err := io.ReadAll(zstdReader)
if err != nil && !(len(decompressed) > 0 && errors.Is(err, zstd.ErrMagicMismatch)) {
return nil, err
}
r.b = decompressed
if err = r.readHeaderMagic(); err != nil {
return nil, err
}
h, err := r.readHeader()
r.Header = h
if err != nil {
return nil, err
}
}
r.b = b
log.Debug().Int("size", len(r.b)).Send()
if err = r.readHeaderMagic(); err != nil {
return
}
h, err := r.readHeader()
r.Header = h
if err != nil {
return
}
log.Debug().Str("season", r.Header.GameVersion).Int("code", r.Header.CodeVersion).Send()
r.Listen([]byte{0x22, 0x07, 0x94, 0x9B, 0xDC}, readPlayer)
r.Listen([]byte{0x22, 0xA9, 0x26, 0x0B, 0xE4}, readAtkOpSwap)
r.Listen([]byte{0xAF, 0x98, 0x99, 0xCA}, readSpawn)
if h.CodeVersion >= Y8S1 {
if r.Header.CodeVersion >= Y8S1 {
r.Listen([]byte{0x1F, 0x07, 0xEF, 0xC9}, readTime)
} else {
r.Listen([]byte{0x1E, 0xF1, 0x11, 0xAB}, readY7Time)
}
r.Listen([]byte{0x59, 0x34, 0xE5, 0x8B, 0x04}, readMatchFeedback)
r.Listen([]byte{0x22, 0xA9, 0xC8, 0x58, 0xD9}, readDefuserTimer)
return
return r, err
}

type match struct {
Expand Down
1 change: 1 addition & 0 deletions dissect/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ const (
Y8S1 int = 7408213
Y8S2 int = 7601998
Y8S3 int = 7762708
Y8S4 int = 7921866
)

0 comments on commit 6582698

Please sign in to comment.