decode.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package memconservative
  2. import (
  3. "errors"
  4. "io"
  5. "strings"
  6. "google.golang.org/protobuf/encoding/protowire"
  7. "github.com/v2fly/v2ray-core/v5/common/platform/filesystem"
  8. )
  9. var (
  10. errFailedToReadBytes = errors.New("failed to read bytes")
  11. errFailedToReadExpectedLenBytes = errors.New("failed to read expected length of bytes")
  12. errInvalidGeodataFile = errors.New("invalid geodata file")
  13. errInvalidGeodataVarintLength = errors.New("invalid geodata varint length")
  14. errCodeNotFound = errors.New("code not found")
  15. )
  16. func emitBytes(f io.ReadSeeker, code string) ([]byte, error) {
  17. count := 1
  18. isInner := false
  19. tempContainer := make([]byte, 0, 5)
  20. var result []byte
  21. var advancedN uint64 = 1
  22. var geoDataVarintLength, codeVarintLength, varintLenByteLen uint64 = 0, 0, 0
  23. Loop:
  24. for {
  25. container := make([]byte, advancedN)
  26. bytesRead, err := f.Read(container)
  27. if err == io.EOF {
  28. return nil, errCodeNotFound
  29. }
  30. if err != nil {
  31. return nil, errFailedToReadBytes
  32. }
  33. if bytesRead != len(container) {
  34. return nil, errFailedToReadExpectedLenBytes
  35. }
  36. switch count {
  37. case 1, 3: // data type ((field_number << 3) | wire_type)
  38. if container[0] != 10 { // byte `0A` equals to `10` in decimal
  39. return nil, errInvalidGeodataFile
  40. }
  41. advancedN = 1
  42. count++
  43. case 2, 4: // data length
  44. tempContainer = append(tempContainer, container...)
  45. if container[0] > 127 { // max one-byte-length byte `7F`(0FFF FFFF) equals to `127` in decimal
  46. advancedN = 1
  47. goto Loop
  48. }
  49. lenVarint, n := protowire.ConsumeVarint(tempContainer)
  50. if n < 0 {
  51. return nil, errInvalidGeodataVarintLength
  52. }
  53. tempContainer = nil
  54. if !isInner {
  55. isInner = true
  56. geoDataVarintLength = lenVarint
  57. advancedN = 1
  58. } else {
  59. isInner = false
  60. codeVarintLength = lenVarint
  61. varintLenByteLen = uint64(n)
  62. advancedN = codeVarintLength
  63. }
  64. count++
  65. case 5: // data value
  66. if strings.EqualFold(string(container), code) {
  67. count++
  68. offset := -(1 + int64(varintLenByteLen) + int64(codeVarintLength))
  69. f.Seek(offset, 1) // back to the start of GeoIP or GeoSite varint
  70. advancedN = geoDataVarintLength // the number of bytes to be read in next round
  71. } else {
  72. count = 1
  73. offset := int64(geoDataVarintLength) - int64(codeVarintLength) - int64(varintLenByteLen) - 1
  74. f.Seek(offset, 1) // skip the unmatched GeoIP or GeoSite varint
  75. advancedN = 1 // the next round will be the start of another GeoIPList or GeoSiteList
  76. }
  77. case 6: // matched GeoIP or GeoSite varint
  78. result = container
  79. break Loop
  80. }
  81. }
  82. return result, nil
  83. }
  84. func Decode(filename, code string) ([]byte, error) {
  85. f, err := filesystem.NewFileSeeker(filename)
  86. if err != nil {
  87. return nil, newError("failed to open file: ", filename).Base(err)
  88. }
  89. defer f.Close()
  90. geoBytes, err := emitBytes(f, code)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return geoBytes, nil
  95. }