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