1
1
package geosite
2
2
3
3
import (
4
+ "bufio"
5
+ "encoding/binary"
4
6
"io"
5
7
"os"
8
+ "sync"
9
+ "sync/atomic"
6
10
7
11
E "github.com/sagernet/sing/common/exceptions"
8
- "github.com/sagernet/sing/common/rw "
12
+ "github.com/sagernet/sing/common/varbin "
9
13
)
10
14
11
15
type Reader struct {
12
- reader io.ReadSeeker
13
- domainIndex map [string ]int
14
- domainLength map [string ]int
16
+ access sync.Mutex
17
+ reader io.ReadSeeker
18
+ bufferedReader * bufio.Reader
19
+ metadataIndex int64
20
+ domainIndex map [string ]int
21
+ domainLength map [string ]int
15
22
}
16
23
17
24
func Open (path string ) (* Reader , []string , error ) {
@@ -34,15 +41,23 @@ func Open(path string) (*Reader, []string, error) {
34
41
return reader , codes , nil
35
42
}
36
43
44
+ type geositeMetadata struct {
45
+ Code string
46
+ Index uint64
47
+ Length uint64
48
+ }
49
+
37
50
func (r * Reader ) readMetadata () error {
38
- version , err := rw .ReadByte (r .reader )
51
+ counter := & readCounter {Reader : r .reader }
52
+ reader := bufio .NewReader (counter )
53
+ version , err := reader .ReadByte ()
39
54
if err != nil {
40
55
return err
41
56
}
42
57
if version != 0 {
43
58
return E .New ("unknown version" )
44
59
}
45
- entryLength , err := rw . ReadUVariant ( r . reader )
60
+ entryLength , err := binary . ReadUvarint ( reader )
46
61
if err != nil {
47
62
return err
48
63
}
@@ -55,16 +70,16 @@ func (r *Reader) readMetadata() error {
55
70
codeIndex uint64
56
71
codeLength uint64
57
72
)
58
- code , err = rw . ReadVString ( r . reader )
73
+ code , err = varbin . ReadValue [ string ]( reader , binary . BigEndian )
59
74
if err != nil {
60
75
return err
61
76
}
62
77
keys [i ] = code
63
- codeIndex , err = rw . ReadUVariant ( r . reader )
78
+ codeIndex , err = binary . ReadUvarint ( reader )
64
79
if err != nil {
65
80
return err
66
81
}
67
- codeLength , err = rw . ReadUVariant ( r . reader )
82
+ codeLength , err = binary . ReadUvarint ( reader )
68
83
if err != nil {
69
84
return err
70
85
}
@@ -73,6 +88,8 @@ func (r *Reader) readMetadata() error {
73
88
}
74
89
r .domainIndex = domainIndex
75
90
r .domainLength = domainLength
91
+ r .metadataIndex = counter .count - int64 (reader .Buffered ())
92
+ r .bufferedReader = reader
76
93
return nil
77
94
}
78
95
@@ -81,31 +98,32 @@ func (r *Reader) Read(code string) ([]Item, error) {
81
98
if ! exists {
82
99
return nil , E .New ("code " , code , " not exists!" )
83
100
}
84
- _ , err := r .reader .Seek (int64 (index ), io .SeekCurrent )
101
+ _ , err := r .reader .Seek (r . metadataIndex + int64 (index ), io .SeekStart )
85
102
if err != nil {
86
103
return nil , err
87
104
}
88
- counter := & rw.ReadCounter {Reader : r .reader }
89
- domain := make ([]Item , r .domainLength [code ])
90
- for i := range domain {
91
- var (
92
- item Item
93
- err error
94
- )
95
- item .Type , err = rw .ReadByte (counter )
96
- if err != nil {
97
- return nil , err
98
- }
99
- item .Value , err = rw .ReadVString (counter )
100
- if err != nil {
101
- return nil , err
102
- }
103
- domain [i ] = item
105
+ r .bufferedReader .Reset (r .reader )
106
+ itemList := make ([]Item , r .domainLength [code ])
107
+ err = varbin .Read (r .bufferedReader , binary .BigEndian , & itemList )
108
+ if err != nil {
109
+ return nil , err
104
110
}
105
- _ , err = r .reader .Seek (int64 (- index )- counter .Count (), io .SeekCurrent )
106
- return domain , err
111
+ return itemList , nil
107
112
}
108
113
109
114
func (r * Reader ) Upstream () any {
110
115
return r .reader
111
116
}
117
+
118
+ type readCounter struct {
119
+ io.Reader
120
+ count int64
121
+ }
122
+
123
+ func (r * readCounter ) Read (p []byte ) (n int , err error ) {
124
+ n , err = r .Reader .Read (p )
125
+ if n > 0 {
126
+ atomic .AddInt64 (& r .count , int64 (n ))
127
+ }
128
+ return
129
+ }
0 commit comments