123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- package geosite
- import (
- "io"
- "os"
- E "github.com/sagernet/sing/common/exceptions"
- "github.com/sagernet/sing/common/rw"
- )
- type Reader struct {
- reader io.ReadSeeker
- domainIndex map[string]int
- domainLength map[string]int
- }
- func Open(path string) (*Reader, []string, error) {
- content, err := os.Open(path)
- if err != nil {
- return nil, nil, err
- }
- reader := &Reader{
- reader: content,
- }
- err = reader.readMetadata()
- if err != nil {
- content.Close()
- return nil, nil, err
- }
- codes := make([]string, 0, len(reader.domainIndex))
- for code := range reader.domainIndex {
- codes = append(codes, code)
- }
- return reader, codes, nil
- }
- func (r *Reader) readMetadata() error {
- version, err := rw.ReadByte(r.reader)
- if err != nil {
- return err
- }
- if version != 0 {
- return E.New("unknown version")
- }
- entryLength, err := rw.ReadUVariant(r.reader)
- if err != nil {
- return err
- }
- keys := make([]string, entryLength)
- domainIndex := make(map[string]int)
- domainLength := make(map[string]int)
- for i := 0; i < int(entryLength); i++ {
- var (
- code string
- codeIndex uint64
- codeLength uint64
- )
- code, err = rw.ReadVString(r.reader)
- if err != nil {
- return err
- }
- keys[i] = code
- codeIndex, err = rw.ReadUVariant(r.reader)
- if err != nil {
- return err
- }
- codeLength, err = rw.ReadUVariant(r.reader)
- if err != nil {
- return err
- }
- domainIndex[code] = int(codeIndex)
- domainLength[code] = int(codeLength)
- }
- r.domainIndex = domainIndex
- r.domainLength = domainLength
- return nil
- }
- func (r *Reader) Read(code string) ([]Item, error) {
- index, exists := r.domainIndex[code]
- if !exists {
- return nil, E.New("code ", code, " not exists!")
- }
- _, err := r.reader.Seek(int64(index), io.SeekCurrent)
- if err != nil {
- return nil, err
- }
- counter := &rw.ReadCounter{Reader: r.reader}
- domain := make([]Item, r.domainLength[code])
- for i := range domain {
- var (
- item Item
- err error
- )
- item.Type, err = rw.ReadByte(counter)
- if err != nil {
- return nil, err
- }
- item.Value, err = rw.ReadVString(counter)
- if err != nil {
- return nil, err
- }
- domain[i] = item
- }
- _, err = r.reader.Seek(int64(-index)-counter.Count(), io.SeekCurrent)
- return domain, err
- }
- func (r *Reader) Upstream() any {
- return r.reader
- }
|