z_mirror/fmm

git clone https://git.raiguard.me/z_mirror/fmm

Caleb HeuerRemove all remaining panicsbde6027

trunk
9.6 KiB486 linesraw
1package fmm
2
3import (
4	"bufio"
5	"encoding/binary"
6	"errors"
7	"fmt"
8	"io"
9	"math"
10)
11
12type AllowedCommands uint8
13
14const (
15	AllowedCommandsInvalid AllowedCommands = iota
16	AllowedCommandsTrue
17	AllowedCommandsFalse
18	AllowedCommandsAdminsOnly
19)
20
21type PropertyTree interface {
22	ptree()
23}
24
25type (
26	PropertyTreeNone            struct{}
27	PropertyTreeBool            bool
28	PropertyTreeNumber          float64
29	PropertyTreeString          string
30	PropertyTreeList            []PropertyTree
31	PropertyTreeDict            map[string]PropertyTree
32	PropertyTreeSignedInteger   int64
33	PropertyTreeUnsignedInteger uint64
34)
35
36func (self *PropertyTreeNone) ptree()            {}
37func (self *PropertyTreeBool) ptree()            {}
38func (self *PropertyTreeNumber) ptree()          {}
39func (self *PropertyTreeString) ptree()          {}
40func (self *PropertyTreeList) ptree()            {}
41func (self *PropertyTreeDict) ptree()            {}
42func (self *PropertyTreeSignedInteger) ptree()   {}
43func (self *PropertyTreeUnsignedInteger) ptree() {}
44
45type ModSettings struct {
46	MapVersion Version
47	Settings   PropertyTree
48}
49
50type DatReader struct {
51	reader *bufio.Reader
52	err    error
53}
54
55func newDatReader(reader io.Reader) DatReader {
56	return DatReader{
57		reader: bufio.NewReader(reader),
58	}
59}
60
61func (r *DatReader) Read(buf []byte) (int, error) {
62	if r.err != nil {
63		return 0, nil
64	}
65	return r.reader.Read(buf)
66}
67
68func (r *DatReader) ReadBool() bool {
69	if r.err != nil {
70		return false
71	}
72	value := false
73	if err := binary.Read(r, binary.LittleEndian, &value); err != nil {
74		r.err = err
75	}
76	return value
77}
78
79func (r *DatReader) ReadUint8() uint8 {
80	if r.err != nil {
81		return 0
82	}
83	value, err := r.reader.ReadByte()
84	if err != nil {
85		r.err = err
86		return 0
87	}
88	return uint8(value)
89}
90
91func (r *DatReader) ReadUint16() uint16 {
92	if r.err != nil {
93		return 0
94	}
95	var value uint16
96	if err := binary.Read(r, binary.LittleEndian, &value); err != nil {
97		r.err = err
98	}
99	return value
100}
101
102func (r *DatReader) ReadUint16Optimized() uint16 {
103	if r.err != nil {
104		return 0
105	}
106	first := r.ReadUint8()
107	if first < math.MaxUint8 {
108		return uint16(first)
109	}
110	return r.ReadUint16()
111}
112
113func (r *DatReader) ReadUint32() uint32 {
114	if r.err != nil {
115		return 0
116	}
117	var val uint32
118	if err := binary.Read(r, binary.LittleEndian, &val); err != nil {
119		r.err = err
120	}
121	return val
122}
123
124func (r *DatReader) ReadUint32Optimized() uint32 {
125	if r.err != nil {
126		return 0
127	}
128	first := r.ReadUint8()
129	if first < math.MaxUint8 {
130		return uint32(first)
131	}
132	return r.ReadUint32()
133}
134
135func (r *DatReader) ReadUint64() uint64 {
136	if r.err != nil {
137		return 0
138	}
139	var val uint64
140	if err := binary.Read(r, binary.LittleEndian, &val); err != nil {
141		r.err = err
142	}
143	return val
144}
145
146func (r *DatReader) ReadInt64() int64 {
147	if r.err != nil {
148		return 0
149	}
150	var val int64
151	if err := binary.Read(r, binary.LittleEndian, &val); err != nil {
152		r.err = err
153	}
154	return val
155}
156
157func (r *DatReader) ReadDouble() float64 {
158	if r.err != nil {
159		return 0
160	}
161	var val float64
162	if err := binary.Read(r, binary.LittleEndian, &val); err != nil {
163		r.err = err
164	}
165	return val
166}
167
168func (r *DatReader) ReadString() string {
169	if r.err != nil {
170		return ""
171	}
172	length := r.ReadUint32Optimized()
173	stringBuf := make([]byte, length)
174	_, err := io.ReadFull(r.reader, stringBuf)
175	if err != nil {
176		r.err = err
177	}
178	return string(stringBuf)
179}
180
181func (r *DatReader) ReadStringOptional() string {
182	if r.err != nil {
183		return ""
184	}
185	empty := r.ReadBool()
186	if empty {
187		return ""
188	}
189	return r.ReadString()
190}
191
192func (r *DatReader) ReadVersionOptimized(withBuild bool) Version {
193	if r.err != nil {
194		return Version{}
195	}
196	ver := Version{
197		r.ReadUint16Optimized(),
198		r.ReadUint16Optimized(),
199		r.ReadUint16Optimized(),
200	}
201	if withBuild {
202		ver[3] = r.ReadUint16Optimized()
203	}
204	return ver
205}
206
207func (r *DatReader) ReadVersionUnoptimized() Version {
208	if r.err != nil {
209		return Version{}
210	}
211	return Version{
212		r.ReadUint16(),
213		r.ReadUint16(),
214		r.ReadUint16(),
215		r.ReadUint16(),
216	}
217}
218
219func (r *DatReader) ReadModWithCRC() ModIdent {
220	if r.err != nil {
221		return ModIdent{}
222	}
223	name := r.ReadString()
224	version := r.ReadVersionOptimized(false)
225	r.ReadUint32() // CRC
226	return ModIdent{name, &version}
227}
228
229func (r *DatReader) ReadPropertyTree() PropertyTree {
230	if r.err != nil {
231		return &PropertyTreeNone{}
232	}
233	kind := r.ReadUint8()
234	r.ReadBool() // Internal flag that we do not care about
235	switch kind {
236	case 0:
237		return &PropertyTreeNone{}
238	case 1:
239		return ptr(PropertyTreeBool(r.ReadBool()))
240	case 2:
241		return ptr(PropertyTreeNumber(r.ReadDouble()))
242	case 3:
243		return ptr(PropertyTreeString(r.ReadStringOptional()))
244	case 4:
245		length := r.ReadUint32()
246		res := []PropertyTree{}
247		for i := uint32(0); i < length; i++ {
248			r.ReadStringOptional()
249			res = append(res, r.ReadPropertyTree())
250		}
251		return ptr(PropertyTreeList(res))
252	case 5:
253		length := r.ReadUint32()
254		res := map[string]PropertyTree{}
255		for i := uint32(0); i < length; i++ {
256			res[r.ReadStringOptional()] = r.ReadPropertyTree()
257		}
258		return ptr(PropertyTreeDict(res))
259	case 6:
260		return ptr(PropertyTreeSignedInteger(r.ReadInt64()))
261	case 7:
262		return ptr(PropertyTreeSignedInteger(r.ReadUint64()))
263	}
264
265	r.err = errors.New(fmt.Sprintf("unknown property tree kind: %d\n", kind))
266	return &PropertyTreeNone{}
267}
268
269func (r *DatReader) ReadModSettings() ModSettings {
270	if r.err != nil {
271		return ModSettings{}
272	}
273	mapVersion := r.ReadVersionUnoptimized()
274	r.ReadBool() // Internal flag, always false
275	settings := r.ReadPropertyTree()
276	return ModSettings{mapVersion, settings}
277}
278
279func (r *DatReader) ReadAllowedCommands() AllowedCommands {
280	result := AllowedCommandsInvalid
281	if r.err != nil {
282		return result
283	}
284	raw := r.ReadUint8()
285	switch raw {
286	case 1:
287		result = AllowedCommandsTrue
288	case 2:
289		result = AllowedCommandsFalse
290	case 3:
291		result = AllowedCommandsAdminsOnly
292	}
293	return result
294}
295
296type DatWriter struct {
297	writer *bufio.Writer
298	err    error
299}
300
301func (w *DatWriter) Write(buf []byte) (int, error) {
302	if w.err != nil {
303		return 0, nil
304	}
305	return w.writer.Write(buf)
306}
307
308func newDatWriter(writer io.Writer) DatWriter {
309	return DatWriter{
310		writer: bufio.NewWriter(writer),
311	}
312}
313
314func (w *DatWriter) WriteBool(value bool) {
315	if w.err != nil {
316		return
317	}
318	binary.Write(w, binary.LittleEndian, value)
319}
320
321func (w *DatWriter) WriteUint8(value uint8) {
322	if w.err != nil {
323		return
324	}
325	binary.Write(w, binary.LittleEndian, value)
326}
327
328func (w *DatWriter) WriteUint16(value uint16) {
329	if w.err != nil {
330		return
331	}
332	binary.Write(w, binary.LittleEndian, value)
333}
334
335func (w *DatWriter) WriteUint16Optimized(value uint16) {
336	if w.err != nil {
337		return
338	}
339	if value < math.MaxUint8 {
340		w.WriteUint8(uint8(value))
341	} else {
342		w.WriteUint16(value)
343	}
344}
345
346func (w *DatWriter) WriteUint32(value uint32) {
347	if w.err != nil {
348		return
349	}
350	binary.Write(w, binary.LittleEndian, value)
351}
352
353func (w *DatWriter) WriteUint32Optimized(value uint32) {
354	if w.err != nil {
355		return
356	}
357	if value < math.MaxUint8 {
358		w.WriteUint8(uint8(value))
359	} else {
360		w.WriteUint32(value)
361	}
362}
363
364func (w *DatWriter) WriteUint64(value uint64) {
365	if w.err != nil {
366		return
367	}
368	binary.Write(w, binary.LittleEndian, value)
369}
370
371func (w *DatWriter) WriteInt64(value int64) {
372	if w.err != nil {
373		return
374	}
375	binary.Write(w, binary.LittleEndian, value)
376}
377
378func (w *DatWriter) WriteDouble(value float64) {
379	if w.err != nil {
380		return
381	}
382	binary.Write(w, binary.LittleEndian, value)
383}
384
385func (w *DatWriter) WriteString(value string) {
386	if w.err != nil {
387		return
388	}
389	length := len(value)
390	if length > math.MaxUint32 {
391		w.err = errors.New(fmt.Sprintf("PropertyTree string is too long: %d", length))
392		return
393	}
394	w.WriteUint32Optimized(uint32(length))
395	_, err := w.writer.WriteString(value)
396	if err != nil {
397		w.err = err
398	}
399}
400
401func (w *DatWriter) WriteStringOptional(value string) {
402	if w.err != nil {
403		return
404	}
405	if value == "" {
406		w.WriteBool(true)
407		return
408	}
409	w.WriteBool(false)
410	w.WriteString(value)
411}
412
413func (w *DatWriter) WriteVersionUnoptimized(version Version) {
414	if w.err != nil {
415		return
416	}
417	w.WriteUint16(version[0])
418	w.WriteUint16(version[1])
419	w.WriteUint16(version[2])
420	w.WriteUint16(version[3])
421}
422
423func (w *DatWriter) WritePropertyTree(pt PropertyTree) {
424	if w.err != nil {
425		return
426	}
427	switch val := pt.(type) {
428	case *PropertyTreeNone:
429		w.WriteUint8(0) // Type
430		w.WriteUint8(0) // Unused internal flag
431	case *PropertyTreeBool:
432		w.WriteUint8(1) // Type
433		w.WriteUint8(0) // Unused internal flag
434		w.WriteBool(bool(*val))
435	case *PropertyTreeNumber:
436		w.WriteUint8(2) // Type
437		w.WriteUint8(0) // Unused internal flag
438		w.WriteDouble(float64(*val))
439	case *PropertyTreeString:
440		w.WriteUint8(3) // Type
441		w.WriteUint8(0) // Unused internal flag
442		w.WriteStringOptional(string(*val))
443	case *PropertyTreeList:
444		w.WriteUint8(4) // Type
445		w.WriteUint8(0) // Unused internal flag
446		list := []PropertyTree(*val)
447		w.WriteUint32(uint32(len(list)))
448		for _, child := range list {
449			w.WriteStringOptional("")
450			w.WritePropertyTree(child)
451		}
452	case *PropertyTreeDict:
453		w.WriteUint8(5) // Type
454		w.WriteUint8(0) // Unused internal flag
455		dict := map[string]PropertyTree(*val)
456		w.WriteUint32(uint32(len(dict)))
457		for key, child := range dict {
458			w.WriteStringOptional(key)
459			w.WritePropertyTree(child)
460		}
461	case *PropertyTreeSignedInteger:
462		w.WriteUint8(6) // Type
463		w.WriteUint8(0) // Unused internal flag
464		w.WriteInt64(int64(*val))
465	case *PropertyTreeUnsignedInteger:
466		w.WriteUint8(7) // Type
467		w.WriteUint8(0) // Unused internal flag
468		w.WriteUint64(uint64(*val))
469	}
470}
471
472func (w *DatWriter) WriteModSettings(input *ModSettings) {
473	if w.err != nil {
474		return
475	}
476	w.WriteVersionUnoptimized(input.MapVersion)
477	w.WriteBool(false) // Internal flag, always false
478	w.WritePropertyTree(input.Settings)
479}
480
481func (w *DatWriter) Flush() {
482	if w.err != nil {
483		return
484	}
485	w.err = w.writer.Flush()
486}