github.com/sagernet/sing@v0.2.6/common/abx/reader.go (about) 1 package abx 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "encoding/binary" 7 "encoding/hex" 8 "encoding/xml" 9 "io" 10 "strconv" 11 12 . "github.com/sagernet/sing/common/abx/internal" 13 E "github.com/sagernet/sing/common/exceptions" 14 ) 15 16 var _ xml.TokenReader = (*Reader)(nil) 17 18 type Reader struct { 19 reader *bytes.Reader 20 stringRefs []string 21 attrs []xml.Attr 22 } 23 24 func NewReader(content []byte) (xml.TokenReader, bool) { 25 if len(content) < 4 || !bytes.Equal(content[:4], ProtocolMagicVersion0) { 26 return nil, false 27 } 28 return &Reader{reader: bytes.NewReader(content[4:])}, true 29 } 30 31 func (r *Reader) Token() (token xml.Token, err error) { 32 event, err := r.reader.ReadByte() 33 if err != nil { 34 return 35 } 36 tokenType := event & 0x0f 37 eventType := event & 0xf0 38 switch tokenType { 39 case StartDocument: 40 return 41 case EndDocument: 42 return nil, io.EOF 43 case StartTag: 44 var name string 45 name, err = r.readInternedUTF() 46 if err != nil { 47 return 48 } 49 var attrs []xml.Attr 50 attrs, err = r.pullAttributes() 51 if err != nil { 52 return 53 } 54 return xml.StartElement{Name: xml.Name{Local: name}, Attr: attrs}, nil 55 case EndTag: 56 var name string 57 name, err = r.readInternedUTF() 58 if err != nil { 59 return 60 } 61 return xml.EndElement{Name: xml.Name{Local: name}}, nil 62 case TEXT: 63 var data string 64 data, err = r.readUTF() 65 if err != nil { 66 return 67 } 68 return xml.CharData(data), nil 69 case CDSECT: 70 var data string 71 data, err = r.readUTF() 72 if err != nil { 73 return 74 } 75 return xml.Directive("<![CDATA[" + data + "]]>"), nil 76 case ProcessingInstruction: 77 _, err = r.readUTF() 78 return 79 case COMMENT: 80 var data string 81 data, err = r.readUTF() 82 if err != nil { 83 return 84 } 85 return xml.Comment(data), nil 86 case DOCDECL: 87 _, err = r.readUTF() 88 return 89 case IgnorableWhitespace: 90 _, err = r.readUTF() 91 return 92 case EntityRef: 93 _, err = r.readUTF() 94 return 95 case ATTRIBUTE: 96 return nil, E.New("unexpected attribute") 97 } 98 return nil, E.New("unknown token type ", tokenType, " with type ", eventType) 99 } 100 101 func (r *Reader) pullAttributes() ([]xml.Attr, error) { 102 err := r.pullAttribute() 103 if err != nil { 104 return nil, err 105 } 106 attrs := r.attrs 107 r.attrs = nil 108 return attrs, nil 109 } 110 111 func (r *Reader) pullAttribute() error { 112 event, err := r.reader.ReadByte() 113 if err != nil { 114 return nil 115 } 116 tokenType := event & 0x0f 117 eventType := event & 0xf0 118 if tokenType != ATTRIBUTE { 119 return r.reader.UnreadByte() 120 } 121 var name string 122 name, err = r.readInternedUTF() 123 if err != nil { 124 return err 125 } 126 var value string 127 switch eventType { 128 case TypeNull: 129 value = "" 130 case TypeBooleanTrue: 131 value = "true" 132 case TypeBooleanFalse: 133 value = "false" 134 case TypeString: 135 value, err = r.readUTF() 136 if err != nil { 137 return err 138 } 139 case TypeStringInterned: 140 value, err = r.readInternedUTF() 141 if err != nil { 142 return err 143 } 144 case TypeBytesHex: 145 var data []byte 146 data, err = r.readBytes() 147 if err != nil { 148 return err 149 } 150 value = hex.EncodeToString(data) 151 case TypeBytesBase64: 152 var data []byte 153 data, err = r.readBytes() 154 if err != nil { 155 return err 156 } 157 value = base64.StdEncoding.EncodeToString(data) 158 case TypeInt: 159 var data int32 160 err = binary.Read(r.reader, binary.BigEndian, &data) 161 if err != nil { 162 return err 163 } 164 value = strconv.FormatInt(int64(data), 10) 165 case TypeIntHex: 166 var data int32 167 err = binary.Read(r.reader, binary.BigEndian, &data) 168 if err != nil { 169 return err 170 } 171 value = "0x" + strconv.FormatInt(int64(data), 16) 172 case TypeLong: 173 var data int64 174 err = binary.Read(r.reader, binary.BigEndian, &data) 175 if err != nil { 176 return err 177 } 178 value = strconv.FormatInt(data, 10) 179 case TypeLongHex: 180 var data int64 181 err = binary.Read(r.reader, binary.BigEndian, &data) 182 if err != nil { 183 return err 184 } 185 value = "0x" + strconv.FormatInt(data, 16) 186 case TypeFloat: 187 var data float32 188 err = binary.Read(r.reader, binary.BigEndian, &data) 189 if err != nil { 190 return err 191 } 192 value = strconv.FormatFloat(float64(data), 'g', -1, 32) 193 case TypeDouble: 194 var data float64 195 err = binary.Read(r.reader, binary.BigEndian, &data) 196 if err != nil { 197 return err 198 } 199 value = strconv.FormatFloat(data, 'g', -1, 64) 200 default: 201 return E.New("unexpected attribute type, ", eventType) 202 } 203 r.attrs = append(r.attrs, xml.Attr{Name: xml.Name{Local: name}, Value: value}) 204 return r.pullAttribute() 205 } 206 207 func (r *Reader) readUnsignedShort() (uint16, error) { 208 var value uint16 209 err := binary.Read(r.reader, binary.BigEndian, &value) 210 return value, err 211 } 212 213 func (r *Reader) readInternedUTF() (utf string, err error) { 214 ref, err := r.readUnsignedShort() 215 if err != nil { 216 return 217 } 218 if ref == MaxUnsignedShort { 219 utf, err = r.readUTF() 220 if err != nil { 221 return 222 } 223 if len(r.stringRefs) < MaxUnsignedShort { 224 r.stringRefs = append(r.stringRefs, utf) 225 } 226 return 227 } 228 if int(ref) >= len(r.stringRefs) { 229 err = E.New("invalid interned reference: ", ref, ", exists: ", len(r.stringRefs)) 230 return 231 } 232 utf = r.stringRefs[ref] 233 return 234 } 235 236 func (r *Reader) readUTF() (utf string, err error) { 237 data, err := r.readBytes() 238 if err != nil { 239 return 240 } 241 utf = string(data) 242 return 243 } 244 245 func (r *Reader) readBytes() (data []byte, err error) { 246 length, err := r.readUnsignedShort() 247 if err != nil { 248 return 249 } 250 data = make([]byte, length) 251 _, err = io.ReadFull(r.reader, data) 252 return 253 }