Mainflux.mainflux/vendor/github.com/gopcua/opcua/ua/extension_object.go

146 lines
4.7 KiB
Go

// Copyright 2018-2019 opcua authors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
package ua
import (
"github.com/gopcua/opcua/errors"
"github.com/gopcua/opcua/id"
)
// eotypes contains all known extension objects.
var eotypes = NewTypeRegistry()
// init registers known built-in extension objects.
func init() {
RegisterExtensionObject(NewNumericNodeID(0, id.AnonymousIdentityToken_Encoding_DefaultBinary), new(AnonymousIdentityToken))
RegisterExtensionObject(NewNumericNodeID(0, id.UserNameIdentityToken_Encoding_DefaultBinary), new(UserNameIdentityToken))
RegisterExtensionObject(NewNumericNodeID(0, id.X509IdentityToken_Encoding_DefaultBinary), new(X509IdentityToken))
RegisterExtensionObject(NewNumericNodeID(0, id.IssuedIdentityToken_Encoding_DefaultBinary), new(IssuedIdentityToken))
RegisterExtensionObject(NewNumericNodeID(0, id.ServerStatusDataType_Encoding_DefaultBinary), new(ServerStatusDataType))
RegisterExtensionObject(NewNumericNodeID(0, id.DataChangeNotification_Encoding_DefaultBinary), new(DataChangeNotification))
RegisterExtensionObject(NewNumericNodeID(0, id.ReadRawModifiedDetails_Encoding_DefaultBinary), new(ReadRawModifiedDetails))
RegisterExtensionObject(NewNumericNodeID(0, id.HistoryData_Encoding_DefaultBinary), new(HistoryData))
RegisterExtensionObject(NewNumericNodeID(0, id.SubscriptionDiagnosticsDataType_Encoding_DefaultBinary), new(SubscriptionDiagnosticsDataType))
}
// RegisterExtensionObject registers a new extension object type.
// It panics if the type or the id is already registered.
func RegisterExtensionObject(typeID *NodeID, v interface{}) {
if err := eotypes.Register(typeID.String(), v); err != nil {
panic("Extension object " + err.Error())
}
}
// These flags define the value type of an ExtensionObject.
// They cannot be combined.
const (
ExtensionObjectEmpty = 0
ExtensionObjectBinary = 1
ExtensionObjectXML = 2
)
// ExtensionObject is encoded as sequence of bytes prefixed by the NodeId of its DataTypeEncoding
// and the number of bytes encoded.
//
// Specification: Part 6, 5.2.2.15
type ExtensionObject struct {
EncodingMask uint8
TypeID *ExpandedNodeID
Value interface{}
}
func NewExtensionObject(value interface{}) *ExtensionObject {
e := &ExtensionObject{
TypeID: ExtensionObjectTypeID(value),
Value: value,
}
e.UpdateMask()
return e
}
func (e *ExtensionObject) Decode(b []byte) (int, error) {
buf := NewBuffer(b)
e.TypeID = new(ExpandedNodeID)
buf.ReadStruct(e.TypeID)
e.EncodingMask = buf.ReadByte()
if e.EncodingMask == ExtensionObjectEmpty {
return buf.Pos(), buf.Error()
}
length := buf.ReadUint32()
if length == 0 || length == 0xffffffff || buf.Error() != nil {
return buf.Pos(), buf.Error()
}
body := NewBuffer(buf.ReadN(int(length)))
if buf.Error() != nil {
return buf.Pos(), buf.Error()
}
if e.EncodingMask == ExtensionObjectXML {
e.Value = new(XMLElement)
body.ReadStruct(e.Value)
return buf.Pos(), body.Error()
}
typeID := e.TypeID.NodeID.String()
e.Value = eotypes.New(typeID)
if e.Value == nil {
return buf.Pos(), errors.Errorf("invalid extension object with id %s", typeID)
}
body.ReadStruct(e.Value)
return buf.Pos(), body.Error()
}
func (e *ExtensionObject) Encode() ([]byte, error) {
buf := NewBuffer(nil)
if e == nil {
e = &ExtensionObject{TypeID: NewTwoByteExpandedNodeID(0), EncodingMask: ExtensionObjectEmpty}
}
buf.WriteStruct(e.TypeID)
buf.WriteByte(e.EncodingMask)
if e.EncodingMask == ExtensionObjectEmpty {
return buf.Bytes(), buf.Error()
}
body := NewBuffer(nil)
body.WriteStruct(e.Value)
if body.Error() != nil {
return nil, body.Error()
}
buf.WriteUint32(uint32(body.Len()))
buf.Write(body.Bytes())
return buf.Bytes(), buf.Error()
}
func (e *ExtensionObject) UpdateMask() {
if e.Value == nil {
e.EncodingMask = ExtensionObjectEmpty
} else if _, ok := e.Value.(*XMLElement); ok {
e.EncodingMask = ExtensionObjectXML
} else {
e.EncodingMask = ExtensionObjectBinary
}
}
func ExtensionObjectTypeID(v interface{}) *ExpandedNodeID {
switch v.(type) {
case *AnonymousIdentityToken:
return NewFourByteExpandedNodeID(0, id.AnonymousIdentityToken_Encoding_DefaultBinary)
case *UserNameIdentityToken:
return NewFourByteExpandedNodeID(0, id.UserNameIdentityToken_Encoding_DefaultBinary)
case *X509IdentityToken:
return NewFourByteExpandedNodeID(0, id.X509IdentityToken_Encoding_DefaultBinary)
case *IssuedIdentityToken:
return NewFourByteExpandedNodeID(0, id.IssuedIdentityToken_Encoding_DefaultBinary)
case *ServerStatusDataType:
return NewFourByteExpandedNodeID(0, id.ServerStatusDataType_Encoding_DefaultBinary)
default:
return NewTwoByteExpandedNodeID(0)
}
}