-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.go
86 lines (68 loc) · 1.92 KB
/
parser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package main
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"golang.org/x/text/encoding/unicode"
)
const (
langFileMagic uint32 = 0x89455A12
)
func parseLangFile(r io.Reader) ([]string, error) {
var header struct {
Magic uint32
_ uint32
_ uint32
Entries uint32
}
if err := binary.Read(r, binary.LittleEndian, &header); err != nil {
return nil, fmt.Errorf("reading %d byte header failed: %w", binary.Size(header), err)
}
if header.Magic != langFileMagic {
return nil, fmt.Errorf("magic mismatch; got %#08x, want %#08x", header.Magic, langFileMagic)
}
offsets := make([]uint32, header.Entries)
if err := binary.Read(r, binary.LittleEndian, &offsets); err != nil {
return nil, fmt.Errorf("reading offset list failed: %w", err)
}
textData, err := ioutil.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("reading text data failed: %w", err)
}
var decodedReader *bufio.Reader
var buf strings.Builder
dec := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder()
entries := make([]string, 0, header.Entries)
rawReader := bytes.NewReader(textData)
for _, offset := range offsets {
if _, err := rawReader.Seek(int64(offset*2), os.SEEK_SET); err != nil {
return nil, fmt.Errorf("seeking to entry failed: %w", err)
}
if dr := dec.Reader(rawReader); decodedReader == nil {
decodedReader = bufio.NewReaderSize(dr, 16)
} else {
decodedReader.Reset(dr)
}
buf.Reset()
for {
if r, _, err := decodedReader.ReadRune(); err != nil {
return nil, fmt.Errorf("reading decoded rune failed (buffer=%q): %w", buf.String(), err)
} else if r != 0 {
buf.WriteRune(r)
} else {
// End of string found
break
}
}
entries = append(entries, buf.String())
}
if uint32(len(entries)) != header.Entries {
return nil, fmt.Errorf("header announces %d entries, found %d", header.Entries, len(entries))
}
return entries, nil
}