76 lines
2.1 KiB
Go
76 lines
2.1 KiB
Go
package onvif
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"errors"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
var ErrInvalidResponse = errors.New("ONVIF 返回内容无法识别")
|
|
|
|
type profileEnvelope struct {
|
|
Profiles []struct {
|
|
Token string `xml:"token,attr"`
|
|
Name string `xml:"Name"`
|
|
Encoder struct {
|
|
Encoding string `xml:"Encoding"`
|
|
Resolution struct {
|
|
Width int `xml:"Width"`
|
|
Height int `xml:"Height"`
|
|
} `xml:"Resolution"`
|
|
} `xml:"VideoEncoderConfiguration"`
|
|
} `xml:"Body>GetProfilesResponse>Profiles"`
|
|
}
|
|
|
|
func parseProfiles(data []byte) ([]Profile, error) {
|
|
var envelope profileEnvelope
|
|
if err := xml.Unmarshal(data, &envelope); err != nil || len(envelope.Profiles) == 0 || len(envelope.Profiles) > 128 {
|
|
return nil, ErrInvalidResponse
|
|
}
|
|
result := make([]Profile, 0, len(envelope.Profiles))
|
|
for _, p := range envelope.Profiles {
|
|
if strings.TrimSpace(p.Token) == "" || len(p.Token) > 255 || len([]rune(p.Name)) > 255 || p.Encoder.Resolution.Width <= 0 || p.Encoder.Resolution.Width > 32768 || p.Encoder.Resolution.Height <= 0 || p.Encoder.Resolution.Height > 32768 || len(p.Encoder.Encoding) > 32 {
|
|
continue
|
|
}
|
|
result = append(result, Profile{Token: p.Token, Name: p.Name, Width: p.Encoder.Resolution.Width, Height: p.Encoder.Resolution.Height, Encoding: p.Encoder.Encoding})
|
|
}
|
|
if len(result) == 0 {
|
|
return nil, ErrInvalidResponse
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func parseElement(data []byte, parent, name string) (string, error) {
|
|
decoder := xml.NewDecoder(strings.NewReader(string(data)))
|
|
depth := 0
|
|
for {
|
|
token, err := decoder.Token()
|
|
if err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
return "", ErrInvalidResponse
|
|
}
|
|
return "", ErrInvalidResponse
|
|
}
|
|
switch value := token.(type) {
|
|
case xml.StartElement:
|
|
if parent == "" || value.Name.Local == parent {
|
|
if value.Name.Local == parent {
|
|
depth++
|
|
}
|
|
}
|
|
if (parent == "" || depth > 0) && value.Name.Local == name {
|
|
var text string
|
|
if err := decoder.DecodeElement(&text, &value); err != nil {
|
|
return "", ErrInvalidResponse
|
|
}
|
|
return strings.TrimSpace(text), nil
|
|
}
|
|
case xml.EndElement:
|
|
if value.Name.Local == parent && depth > 0 {
|
|
depth--
|
|
}
|
|
}
|
|
}
|
|
}
|