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  }