Skip to content

Commit 8455dab

Browse files
committed
Add Header.Version field
1 parent 1aff508 commit 8455dab

File tree

4 files changed

+47
-26
lines changed

4 files changed

+47
-26
lines changed

cmd/screp/screp.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
/*
2-
32
A simple CLI app to parse and display information about
43
a StarCraft: Brood War replay passed as a CLI argument.
5-
64
*/
75
package main
86

@@ -26,7 +24,7 @@ import (
2624

2725
const (
2826
appName = "screp"
29-
appVersion = "v1.7.2"
27+
appVersion = "v1.7.3"
3028
appAuthor = "Andras Belicza"
3129
appHome = "https://github.com/icza/screp"
3230
)

rep/header.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ type Header struct {
1515
// Engine used to play the game and save the replay
1616
Engine *repcore.Engine
1717

18+
// Version contains information about the replay version.
19+
// Since version is not stored in replays, this only designates certain version ranges deducted from replay format.
20+
// Current possible values are:
21+
// - "-1.16": version is 1.16 or older
22+
// - "1.18-1.20": version is 1.18..1.20
23+
// - "1.21+": version is 1.21 or newer
24+
Version string
25+
1826
// Frames is the number of frames. There are approximately ~23.81 frames in
1927
// a second. (1 frame = 0.042 second to be exact).
2028
Frames repcore.Frame

repparser/repdecoder/repdecoder.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ var (
2828

2929
// Decoder wraps a Section method for decoding a section of a given size.
3030
type Decoder interface {
31+
// RepFormat returns the replay format
32+
RepFormat() RepFormat
33+
3134
// NewSection must be called between sections.
3235
// ErrNoMoreSections is returned if the replay has no more sections.
3336
NewSection() error
@@ -63,7 +66,7 @@ func NewFromFile(name string) (d Decoder, err error) {
6366
return nil, fmt.Errorf("not a file: %s", name)
6467
}
6568

66-
var rf repFormat
69+
var rf RepFormat
6770
if stat.Size() >= 30 {
6871
fileHeader := make([]byte, 30)
6972
if _, err = io.ReadFull(f, fileHeader); err != nil {
@@ -81,23 +84,23 @@ func NewFromFile(name string) (d Decoder, err error) {
8184
// New creates a new Decoder that reads and decompresses data from the
8285
// given byte slice.
8386
func New(repData []byte) Decoder {
84-
rf := repFormatUnknown
87+
rf := RepFormatUnknown
8588
if len(repData) >= 30 {
8689
rf = detectRepFormat(repData[:30])
8790
}
8891

8992
return newDecoder(bytes.NewBuffer(repData), rf)
9093
}
9194

92-
// repFormat identifies the replay format
93-
type repFormat int
95+
// RepFormat identifies the replay format
96+
type RepFormat int
9497

9598
// Possible values of repFormat
9699
const (
97-
repFormatUnknown repFormat = iota // Unknown replay format
98-
repFormatLegacy // Legacy replay format (pre 1.18)
99-
repFormatModern // Modern replay format (1.18 - 1.20)
100-
repFormatModern121 // Modern 1.21 replay format (starting from 1.21)
100+
RepFormatUnknown RepFormat = iota // Unknown replay format
101+
RepFormatLegacy // Legacy replay format (pre 1.18)
102+
RepFormatModern // Modern replay format (1.18 - 1.20)
103+
RepFormatModern121 // Modern 1.21 replay format (starting from 1.21)
101104
)
102105

103106
// detectRepFormat detects the replay format based on the file header
@@ -107,15 +110,15 @@ const (
107110
// data block of the Header section (which starts at offset 28).
108111
// If the compressed data block starts with the magic of the valid zlib header,
109112
// it is modern. If it is modern, the replay ID data decides which version.
110-
func detectRepFormat(fileHeader []byte) repFormat {
113+
func detectRepFormat(fileHeader []byte) RepFormat {
111114
if len(fileHeader) < 30 {
112-
return repFormatUnknown
115+
return RepFormatUnknown
113116
}
114117

115118
// legacy and pre 1.21 modern replays have replay ID data "reRS".
116119
// Starting from 1.21, replay ID data is "seRS".
117120
if fileHeader[12] == 's' {
118-
return repFormatModern121
121+
return RepFormatModern121
119122
}
120123

121124
// It's pre 1.21, check if legacy:
@@ -127,16 +130,16 @@ func detectRepFormat(fileHeader []byte) repFormat {
127130
// 0x9C level 6 (default compression?)
128131
// 0xDA level 7..9
129132
if fileHeader[28] != 0x78 {
130-
return repFormatLegacy
133+
return RepFormatLegacy
131134
}
132135

133-
return repFormatModern
136+
return RepFormatModern
134137
}
135138

136139
// newDecoder creates a new Decoder that reads and decompresses data from the given Reader.
137140
// The source is treated as a modern replay if modern is true, else as a
138141
// legacy replay.
139-
func newDecoder(r io.Reader, rf repFormat) Decoder {
142+
func newDecoder(r io.Reader, rf RepFormat) Decoder {
140143
dec := decoder{
141144
r: r,
142145
rf: rf,
@@ -145,7 +148,7 @@ func newDecoder(r io.Reader, rf repFormat) Decoder {
145148
}
146149

147150
switch rf {
148-
case repFormatModern, repFormatModern121:
151+
case RepFormatModern, RepFormatModern121:
149152
return &modernDecoder{
150153
decoder: dec,
151154
}
@@ -163,7 +166,7 @@ type decoder struct {
163166
r io.Reader
164167

165168
// rf identifiers the rep format
166-
rf repFormat
169+
rf RepFormat
167170

168171
// sectionsCounter tells how many sections have been read
169172
sectionsCounter int
@@ -175,6 +178,10 @@ type decoder struct {
175178
buf []byte
176179
}
177180

181+
func (d *decoder) RepFormat() RepFormat {
182+
return d.rf
183+
}
184+
178185
// readInt32 reads an int32 from the underlying Reader.
179186
func (d *decoder) readInt32() (n int32, err error) {
180187
if _, err = io.ReadFull(d.r, d.int32Buf); err != nil {
@@ -191,11 +198,11 @@ func (d *decoder) NewSection() (err error) {
191198
d.sectionsCounter++
192199

193200
switch d.rf {
194-
case repFormatLegacy:
201+
case RepFormatLegacy:
195202
if d.sectionsCounter == 5 {
196203
return ErrNoMoreSections // Legacy replays only have 4 sections
197204
}
198-
case repFormatModern121:
205+
case RepFormatModern121:
199206
// There is a 4-byte encoded length between sections:
200207
if d.sectionsCounter == 2 {
201208
if _, err = d.readInt32(); err != nil {

repparser/repparser.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
/*
2-
32
Package repparser implements StarCraft: Brood War replay parsing.
43
54
The package is safe for concurrent use.
@@ -24,7 +23,6 @@ https://github.com/icza/bwhf/blob/master/src/hu/belicza/andras/bwhf/model/Action
2423
2524
https://github.com/bwapi/bwapi/tree/master/bwapi/libReplayTool
2625
27-
2826
jssuh replay parser:
2927
3028
https://github.com/neivv/jssuh
@@ -36,7 +34,6 @@ https://www.starcraftai.com/wiki/CHK_Format
3634
http://www.staredit.net/wiki/index.php/Scenario.chk
3735
3836
http://blog.naver.com/PostView.nhn?blogId=wisdomswrap&logNo=60119755717&parentCategoryNo=&categoryNo=19&viewDate=&isShowPopularPosts=false&from=postView
39-
4037
*/
4138
package repparser
4239

@@ -61,7 +58,7 @@ import (
6158

6259
const (
6360
// Version is a Semver2 compatible version of the parser.
64-
Version = "v1.8.2"
61+
Version = "v1.8.3"
6562
)
6663

6764
var (
@@ -240,6 +237,17 @@ func parse(dec repdecoder.Decoder, cfg Config) (*rep.Replay, error) {
240237
if err = s.ParseFunc(data, r, cfg); err != nil {
241238
return nil, fmt.Errorf("ParseFunc() error (sectionID: %d): %v", s.ID, err)
242239
}
240+
if s == SectionHeader {
241+
// Fill Version:
242+
switch dec.RepFormat() {
243+
case repdecoder.RepFormatModern121:
244+
r.Header.Version = "1.21+"
245+
case repdecoder.RepFormatLegacy:
246+
r.Header.Version = "-1.16"
247+
case repdecoder.RepFormatModern:
248+
r.Header.Version = "1.18-1.20"
249+
}
250+
}
243251
}
244252
}
245253

@@ -249,7 +257,7 @@ func parse(dec repdecoder.Decoder, cfg Config) (*rep.Replay, error) {
249257
// repIDs is the possible valid content of the Replay ID section
250258
var repIDs = [][]byte{
251259
[]byte("seRS"), // Starting from 1.21
252-
[]byte("reRS"), // Up until 1.20. Abbreviation for replay ReSource?
260+
[]byte("reRS"), // Up until 1.20.
253261
}
254262

255263
// parseReplayID processes the replay ID data.

0 commit comments

Comments
 (0)