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  }