diff --git a/cop/collection.go b/cop/collection.go new file mode 100644 index 0000000..fb3a0a4 --- /dev/null +++ b/cop/collection.go @@ -0,0 +1,164 @@ +package cop + +import ( + "errors" + "fmt" + "io/fs" + "log" + "os" + "os/user" + "path" + "path/filepath" + "strings" + + "github.com/go-git/go-git/v5" + + "gitea.mmo.to/ppForge/ppforge/protocol" +) + +// ProtocolCollectionList is a list of all databases, with the most simple interface +type ProtocolCollectionList struct { + PCs []COP +} + +// ProtocolCollectionEntry is a single entry in the file database, additionally to the meta data the path is required +type ProtocolCollectionEntry struct { + Path string + Protocol protocol.ProtocolMeta +} + +// Init initializes the databases, opens the default one and checks for others if available +func Init() *ProtocolCollectionList { + // initialize main list + databases := ProtocolCollectionList{[]COP{}} + // initialize default db + user, err := user.Current() + if err != nil { + log.Printf("Current user not obtainable: %s", err) + log.Fatal("Impossible to open default database") + } + pathlist := []string{user.HomeDir, ".config", "ppforge"} + fdb := FileCOP{COP{map[string]ProtocolCollectionEntry{}, false}, path.Join(pathlist...)} + fdb.Open(path.Join(pathlist...)) + fdb.UpdateCollection() + databases.PCs = append(databases.PCs, fdb.COP) + log.Printf("Amount of databases available %d", len(databases.PCs)) + return &databases +} + +// Get a full protocol from a database entry +func (de *ProtocolCollectionEntry) Get() (*protocol.Protocol, error) { + return protocol.LoadNew(de.Path) +} + +// COP represents a Collection of Protocols +type COP struct { + protocols map[string]ProtocolCollectionEntry + closed bool +} + +// FileCOP implements +type FileCOP struct { + COP + Path string +} + +// FileCOPFromGitRemote implements retrieving the latest stuff from an external git remote additionally to the FileDatabase functionality +type FileCOPFromGitRemote struct { + FileCOP + RemoteGitRepository string + gitRepo git.Repository +} + +// Open the database +func (fd *FileCOP) Open(path string) error { + fileinfo, err := os.Stat(path) + if err == os.ErrNotExist { + return err + } + if !fileinfo.IsDir() { + return fmt.Errorf("Path %s is not a directory", path) + } + fd.Path = path + fd.closed = false + return nil +} + +// Close the database and free the data +func (fd *FileCOP) Close() error { + fd.closed = true + return nil +} + +// Protocols returns the map of protocols or an error if the first read failed +func (fd *FileCOP) Protocols() ([]ProtocolCollectionEntry, error) { + if fd.closed { + return nil, errors.New("COP closed, no protocols to deliver") + } + entries := []ProtocolCollectionEntry{} + if !fd.closed && len(fd.protocols) == 0 { + fd.protocols = map[string]ProtocolCollectionEntry{} + err := fd.UpdateCollection() + if err != nil { + return nil, err + } + } + if entries == nil || len(entries) == 0 { + entries = make([]ProtocolCollectionEntry, 0) + for _, v := range fd.protocols { + entries = append(entries, v) + } + } + return entries, nil +} + +// Add puts a new protocol into the path of the file database +func (fd *FileCOP) Add(prot *protocol.Protocol) error { + if fd.closed { + return errors.New("Cannot add, FileCOP is closed") + } + p := path.Join(fd.Path, prot.Metadata.Name, ".protocoljson") + err := prot.Save(p) + if err == nil { + fd.protocols[prot.Metadata.Name] = ProtocolCollectionEntry{p, prot.Metadata} + } + return err +} + +// Update updates an existing entry through saving the contents of the protocol to the file, or just adding it anew +func (fd *FileCOP) Update(prot *protocol.Protocol) error { + if fd.closed { + return errors.New("Cannot update, FileCOP is closed") + } + if v, ok := fd.protocols[prot.Metadata.Name]; ok { + v.Protocol = prot.Metadata + return prot.Save(v.Path) + } + return fd.Add(prot) +} + +// UpdateCollection just rereads all files +func (fd *FileCOP) UpdateCollection() error { + if fd.closed { + return errors.New("Cannot update, FileCOP is closed") + } + // recurse recursively through the path + if fd.protocols == nil { + fd.protocols = make(map[string]ProtocolCollectionEntry) + } + err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error { + if !info.IsDir() && strings.HasSuffix(info.Name(), ".protocoljson") { + prot, err := protocol.LoadNew(path) + if err == nil { + // add to map + // add to map + entry := ProtocolCollectionEntry{path, prot.Metadata} + + fd.protocols[prot.Metadata.Name] = entry + } + return err + } + return nil + }) + return err +} diff --git a/cop/collection_test.go b/cop/collection_test.go new file mode 100644 index 0000000..b9f197d --- /dev/null +++ b/cop/collection_test.go @@ -0,0 +1,59 @@ +package cop + +import ( + "fmt" + "os" + "path" + "testing" +) + +func TestOpen(t *testing.T) { + fcop := FileCOP{} + wd, err := os.Getwd() + if err != nil { + fmt.Printf("Os error: %s", err) + t.Fail() + } + fcop.Open(path.Join(wd, "..", "test", "cop")) + l, err := fcop.Protocols() + if err != nil { + t.Fail() + } + for k, v := range fcop.protocols { + fmt.Printf("%s->%s\n", k, v.Path) + } + for _, pce := range l { + fmt.Printf("%s//%s\n", pce.Path, pce.Protocol.Name) + } +} + +func TestClosed(t *testing.T) { + fcop := FileCOP{} + wd, err := os.Getwd() + if err != nil { + fmt.Printf("Os error: %s", err) + t.Fail() + } + fcop.Open(path.Join(wd, "..", "test", "cop")) + fcop.Close() + l, err := fcop.Protocols() + if err == nil || l != nil { + fmt.Println("Protocols did not deliver error") + t.Fail() + } + err = fcop.Add(nil) + if err == nil { + fmt.Println("Add did not deliver error") + t.Fail() + } + err = fcop.Update(nil) + if err == nil { + fmt.Println("Update did not deliver error") + t.Fail() + } + err = fcop.UpdateCollection() + if err == nil { + fmt.Println("UpdateCollection did not deliver error") + t.Fail() + } +} diff --git a/dop/protocoldictionary.go b/dop/protocoldictionary.go deleted file mode 100644 index 9af71b7..0000000 --- a/dop/protocoldictionary.go +++ /dev/null @@ -1,179 +0,0 @@ -package dop - -import ( - "fmt" - "io/fs" - "log" - "os" - "os/user" - "path" - "path/filepath" - - "github.com/go-git/go-git/v5" - - "gitea.mmo.to/ppForge/ppforge/protocol" - "gitea.mmo.to/ppForge/ppforge/protocolctl" -) - -// ProtocolDictionaryList is a list of all databases, with the most simple interface -type ProtocolDictionaryList struct { - PDs []ProtocolDictionaryProvider -} - -// ProtocolDictionaryProvider is a simple protocol database interface, which only provides open/close and retrieving the contents -type ProtocolDictionaryProvider interface { - // Open opens a new database - Open(path string) error - // Close closes a database (only internal flag set) - Close() error - // Protocols returns the content of the database as map, an error if the first read of the database failed - Protocols() ([]ProtocolDictionaryEntry, error) -} - -// ProtocolDatabaseManager is a complex protocol database interface, which allows adding, updating and refreshing of the content -type ProtocolDatabaseManager interface { - Add(prot *protocol.ProtocolStructure) error - Update(prot *protocol.ProtocolStructure) error - // no remove. - UpdateDatabase() error // scans for new protocols -} - -// ProtocolDictionaryEntry is a single entry in the file database, additionally to the meta data the path is required -type ProtocolDictionaryEntry struct { - Path string - Protocol protocol.DOPMeta -} - -// Init initializes the databases, opens the default one and checks for others if available -func Init() *ProtocolDictionaryList { - // initialize main list - databases := ProtocolDictionaryList{[]ProtocolDictionaryProvider{}} - // initialize default db - user, err := user.Current() - if err != nil { - log.Printf("Current user not obtainable: %s", err) - log.Fatal("Impossible to open default database") - } - pathlist := []string{user.HomeDir, ".config", "ppforge"} - fdb := FileDOP{path.Join(pathlist...), map[string]ProtocolDictionaryEntry{}, false} - fdb.Open(path.Join(pathlist...)) - fdb.UpdateDatabase() - databases.PDs = append(databases.PDs, fdb) - log.Printf("Amount of databases available %d", len(databases.PDs)) - return &databases -} - -// Get Retrieves the full set of databases -func (ppfdb *ProtocolDictionaryList) Get() []ProtocolDictionaryProvider { - return ppfdb.PDs -} - -// Get a full protocol from a database entry -func (de *ProtocolDictionaryEntry) Get() (*protocol.ProtocolStructure, error) { - return protocolctl.LoadNew(de.Path) -} - -// FileDOP implements ProtocolDatabaseProvider and ProtocolDatabaseManager -type FileDOP struct { - Path string - protocols map[string]ProtocolDictionaryEntry - closed bool -} - -// FileDOPFromGitRemote implements retrieving the latest stuff from an external git remote additionally to the FileDatabase functionality -// TODO -type FileDOPFromGitRemote struct { - FileDOP - RemoteGitRepository string - gitRepo git.Repository -} - -// Open the database -func (fd FileDOP) Open(path string) error { - fileinfo, err := os.Stat(path) - if err == os.ErrNotExist { - return err - } - if !fileinfo.IsDir() { - return fmt.Errorf("Path %s is not a directory", path) - } - fd.Path = path - fd.closed = false - return nil -} - -// Close the database and free the data -func (fd FileDOP) Close() error { - for k := range fd.protocols { - delete(fd.protocols, k) - } - fd.closed = true - return nil -} - -// Protocols returns the map of protocols or an error if the first read failed -func (fd FileDOP) Protocols() ([]ProtocolDictionaryEntry, error) { - entries := []ProtocolDictionaryEntry{} - if !fd.closed && len(fd.protocols) == 0 { - fd.protocols = map[string]ProtocolDictionaryEntry{} - // recurse recursively through the path - err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error { - if !info.IsDir() { - prot, err := protocolctl.LoadNew(path) - if err == nil { - // add to map - entry := ProtocolDictionaryEntry{path, prot.Metadata} - - fd.protocols[prot.Metadata.Name] = entry - entries = append(entries, entry) - } - } - return nil - }) - if err != nil { - return nil, err - } - } - if entries == nil || len(entries) == 0 { - entries = make([]ProtocolDictionaryEntry, len(fd.protocols)) - for _, v := range fd.protocols { - entries = append(entries, v) - } - } - return entries, nil -} - -// Add puts a new protocol into the path of the file database -func (fd *FileDOP) Add(prot *protocol.ProtocolStructure) error { - p := path.Join(fd.Path, prot.Metadata.Name, ".protocoljson") - err := protocolctl.Save(prot, p) - if err == nil { - fd.protocols[prot.Metadata.Name] = ProtocolDictionaryEntry{p, prot.Metadata} - } - return err -} - -// Update updates an existing entry through saving the contents of the protocol to the file, or just adding it anew -func (fd *FileDOP) Update(prot *protocol.ProtocolStructure) error { - if v, ok := fd.protocols[prot.Metadata.Name]; ok { - v.Protocol = prot.Metadata - return protocolctl.Save(prot, v.Path) - } - return fd.Add(prot) -} - -// UpdateDatabase just rereads all files -func (fd *FileDOP) UpdateDatabase() error { - // recurse recursively through the path - err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error { - if !info.IsDir() { - prot, err := protocolctl.LoadNew(path) - if err == nil { - // add to map - fd.protocols[prot.Metadata.Name] = ProtocolDictionaryEntry{path, prot.Metadata} - } - } - return nil - }) - return err -} diff --git a/dop/protocoldictionary_test.go b/dop/protocoldictionary_test.go deleted file mode 100644 index 447e2bb..0000000 --- a/dop/protocoldictionary_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package dop - -import ( - "testing" -) - -func Test(t *testing.T) { - -} diff --git a/internal/ui/metadata.go b/internal/ui/metadata.go index fa0c486..cd2b018 100644 --- a/internal/ui/metadata.go +++ b/internal/ui/metadata.go @@ -88,7 +88,7 @@ func NewMetadataProtocol() *ProtocolMetadata { return &md } -func (md *ProtocolMetadata) SetProtocol(prot *protocol.ProtocolStructure) { +func (md *ProtocolMetadata) SetProtocol(prot *protocol.Protocol) { setfunc := func(s string) { protocolctl.UpdateMetaData( prot, @@ -105,7 +105,6 @@ func (md *ProtocolMetadata) SetProtocol(prot *protocol.ProtocolStructure) { md.VersionValue.SetText(prot.Metadata.Version) md.DescValue.SetText(prot.Metadata.Description) md.ExtendsValue.SetText(prot.Metadata.ExtensionTo) - md.OsiLayer.SetSelectedIndex(int(prot.Metadata.OSILayer)) md.TcpIpLayer.SetSelectedIndex(int(prot.Metadata.TCPIPLayer)) md.SetChanged(setfunc) md.Representation.Refresh() @@ -115,7 +114,7 @@ func (md *ProtocolMetadata) Unset() { md.SetChanged(func(s string) {}) } -func (md *PacketMetadata) SetData(pack *packet.Structure) { +func (md *PacketMetadata) SetData(pack *packet.Packet) { } diff --git a/internal/ui/packeteditor.go b/internal/ui/packeteditor.go index c018c4d..b51de2f 100644 --- a/internal/ui/packeteditor.go +++ b/internal/ui/packeteditor.go @@ -17,10 +17,10 @@ type PacketEditor struct { ShowShortHints bool - Reference *packet.Structure + Reference *packet.Packet } -func NewPacketEditor(ref *packet.Structure) *PacketEditor { +func NewPacketEditor(ref *packet.Packet) *PacketEditor { metadata := NewMetadataPacket() fields := container.NewGridWrap(fyne.NewSize(300, 200)) container := container.NewBorder(nil, nil, metadata.Representation, nil, container.NewVScroll(fields)) diff --git a/internal/ui/packetfieldeditor.go b/internal/ui/packetfieldeditor.go index 5f3672a..7d2cd49 100644 --- a/internal/ui/packetfieldeditor.go +++ b/internal/ui/packetfieldeditor.go @@ -39,9 +39,9 @@ func CreatePacketFieldEditor( elements := []fyne.CanvasObject{} - elements = append(elements, widget.NewLabel(ref.GetProtocolField().Name)) + elements = append(elements, widget.NewLabel("TODO")) if ed.ShowShortHints { - elements = append(elements, widget.NewLabel(ref.GetProtocolField().Regex)) // todo: implement real shorthints if feasible + elements = append(elements, widget.NewLabel("TODO")) // todo: implement real shorthints if feasible } // depending on the input stuff, entry for now diff --git a/internal/ui/packetfilehandler.go b/internal/ui/packetfilehandler.go index 647b03a..e3f2aeb 100644 --- a/internal/ui/packetfilehandler.go +++ b/internal/ui/packetfilehandler.go @@ -14,7 +14,7 @@ type PacketFileHandler struct { changed bool tab *container.TabItem - Reference *packet.Structure + Reference *packet.Packet } func NewPacketFileHandler() *PacketFileHandler { diff --git a/internal/ui/protocoleditor.go b/internal/ui/protocoleditor.go index 5005003..420d4ab 100644 --- a/internal/ui/protocoleditor.go +++ b/internal/ui/protocoleditor.go @@ -15,10 +15,10 @@ type ProtocolEditor struct { Metadata *ProtocolMetadata Fields []*FieldEditor - Reference *protocol.ProtocolStructure + Reference *protocol.Protocol } -func NewProtocolEditor(ref *protocol.ProtocolStructure) *ProtocolEditor { +func NewProtocolEditor(ref *protocol.Protocol) *ProtocolEditor { metadata := NewMetadataProtocol() fields := container.NewGridWrap(fyne.NewSize(300, 400)) container := container.NewBorder(nil, nil, metadata.Representation, nil, container.NewVScroll(fields)) diff --git a/internal/ui/protocolfilehandler.go b/internal/ui/protocolfilehandler.go index 9af7360..f168f36 100644 --- a/internal/ui/protocolfilehandler.go +++ b/internal/ui/protocolfilehandler.go @@ -17,7 +17,7 @@ type ProtocolFileHandler struct { changed bool tab *container.TabItem - Reference *protocol.ProtocolStructure + Reference *protocol.Protocol } func NewProtocolFileHandler() *ProtocolFileHandler { diff --git a/packet/fieldvalue.go b/packet/fieldvalue.go deleted file mode 100644 index b8384c9..0000000 --- a/packet/fieldvalue.go +++ /dev/null @@ -1,20 +0,0 @@ -package packet - -import "gitea.mmo.to/ppForge/ppforge/protocol" - -// FieldValue implements protocol.ProtocolFieldReferencer -type FieldValue struct { - fieldReference *protocol.Field - - Value string -} - -// GetProtocolField returns the protocol field -func (fv *FieldValue) GetProtocolField() *protocol.Field { - return fv.fieldReference -} - -// SetProtocolField sets the protocl field -func (fv *FieldValue) SetProtocolField(pf *protocol.Field) { - fv.fieldReference = pf -} diff --git a/packet/packet.go b/packet/packet.go index 220a9eb..432f845 100644 --- a/packet/packet.go +++ b/packet/packet.go @@ -1,26 +1,181 @@ package packet -import "gitea.mmo.to/ppForge/ppforge/protocol" +import ( + "crypto/sha1" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io/fs" + "os" +) + +// FieldValue implements protocol.ProtocolFieldReferencer +type FieldValue struct { + Field string + FieldNum int + + Value string +} + +// GetProtocolField returns the protocol field +func (fv *FieldValue) GetProtocolField() (string, int) { + return fv.Field, fv.FieldNum +} + +// SetProtocolField sets the protocl field +func (fv *FieldValue) SetProtocolField(f string, fn int) { + fv.Field = f + fv.FieldNum = fn +} + +// SetValue sets the value +func (fv *FieldValue) SetValue(v string) { + fv.Value = v +} // Layer implements protocol.ProtocolReferencer type Layer struct { - // needs a reference to a protocol - protocolReference *protocol.ProtocolStructure - ProtocolName string Values []FieldValue } -// Structure contains all layers of a packet -type Structure struct { +// Packet contains all layers of a packet and the data in different formats +type Packet struct { MetaData Metadata + data []byte + Hex string + B64 string + Sha1 string Layers []Layer } -func (pl *Layer) GetProtocol() *protocol.ProtocolStructure { - return pl.protocolReference +func NewPacketStructure() *Packet { + p := Packet{} + return &p +} +func UpdateMetaData( + pack *Packet, +) { + // still empty } -func (pl *Layer) Setprotocol(ps *protocol.ProtocolStructure) { - pl.protocolReference = ps +func NewPacketLayer() *Layer { + p := Layer{} + return &p +} + +func NewEmptyFieldValue() *FieldValue { + f := FieldValue{} + return &f +} + +func NewFieldValue( + field string, + fieldnum int, + value string, +) *FieldValue { + f := FieldValue{ + Value: value, + } + return &f +} + +func (pack *Layer) AppendField(field *FieldValue) int { + i := len(pack.Values) + pack.Values = append(pack.Values, *field) + return i + 1 +} + +func (pack *Layer) AddField(index int, field *FieldValue) { + if len(pack.Values) == index { + pack.AppendField(field) + return + } + ret := make([]FieldValue, 0) + ret = append(ret, pack.Values[:index]...) + ret = append(ret, *field) + ret = append(ret, pack.Values[index:]...) + pack.Values = ret +} + +func (pack *Packet) AppendLayer(layer *Layer) { + pack.Layers = append(pack.Layers, *layer) +} + +func (pack *Packet) AddLayer(index int, layer *Layer) { + if len(pack.Layers) == index { + pack.AppendLayer(layer) + return + } + ret := make([]Layer, 0) + ret = append(ret, pack.Layers[:index]...) + ret = append(ret, *layer) + ret = append(ret, pack.Layers[index:]...) + pack.Layers = ret +} + +func (pack *Layer) UpdateField(e int, field *FieldValue) { + pack.Values[e] = *field +} + +func (pack *Packet) UpdateLayer(e int, layer *Layer) { + pack.Layers[e] = *layer +} + +func (pack *Layer) RemoveField(e int) { + l := len(pack.Values) - 1 + ret := make([]FieldValue, l) + ret = append(ret, pack.Values[:e]...) + ret = append(ret, pack.Values[e+1:]...) + pack.Values = ret +} + +func (pack *Packet) RemoveLayer(e int) { + l := len(pack.Layers) - 1 + ret := make([]Layer, l) + ret = append(ret, pack.Layers[:e]...) + ret = append(ret, pack.Layers[e+1:]...) + pack.Layers = ret +} + +func (pack *Packet) Load(path string) error { + data, err := os.ReadFile(path) + if err != nil { + return err + } + err = json.Unmarshal(data, pack) + pack.data, err = base64.StdEncoding.DecodeString(pack.B64) + if err != nil { + return err + } + if pack.Sha1 != fmt.Sprintf("%x", sha1.Sum(pack.data)) { + return errors.New("sha1sum does not match") + } + return err +} + +func (pack *Packet) UpdateData() { + pack.Hex = fmt.Sprintf("%x", pack.data) + pack.B64 = base64.RawStdEncoding.EncodeToString(pack.data) + pack.Sha1 = fmt.Sprintf("%x", sha1.Sum(pack.data)) +} + +func (pack *Packet) ToJson() string { + pack.UpdateData() + data, err := json.MarshalIndent(*pack, "", " ") + if err != nil { + return "" + } + return string(data) +} + +func (pack *Packet) Save(path string) error { + pack.UpdateData() + data, err := json.MarshalIndent(*pack, "", " ") + if err != nil { + return err + } + err = os.WriteFile(path, data, fs.ModeAppend) + return err } diff --git a/packet/packet_test.go b/packet/packet_test.go new file mode 100644 index 0000000..2c9724f --- /dev/null +++ b/packet/packet_test.go @@ -0,0 +1,28 @@ +package packet + +import ( + "testing" + + "gitea.mmo.to/ppForge/ppforge/protocol" +) + +func GenerateProtocol1() *protocol.Protocol { + + return nil +} +func GenerateProtocol2() *protocol.Protocol { + + return nil +} + +func TestBinaryGeneration(t *testing.T) { + +} + +func TestJsonExport(t *testing.T) { + +} + +func TestJsonImport(t *testing.T) { + +} diff --git a/packet/packetmetadata.go b/packet/packetmetadata.go index 01b604e..576deef 100644 --- a/packet/packetmetadata.go +++ b/packet/packetmetadata.go @@ -2,5 +2,6 @@ package packet // Metadata struct is the absolute minimum of metadata type Metadata struct { - Name string + Name string + Revision int } diff --git a/packetctl/packetctl.go b/packetctl/packetctl.go deleted file mode 100644 index 9f79b82..0000000 --- a/packetctl/packetctl.go +++ /dev/null @@ -1,123 +0,0 @@ -package packetctl - -import ( - "encoding/json" - "io/fs" - "os" - - "gitea.mmo.to/ppForge/ppforge/packet" -) - -func NewPacketStructure() *packet.Structure { - p := packet.Structure{} - return &p -} - -func UpdateMetaData( - pack *packet.Structure, -) { - // still empty -} - -func NewPacketLayer() *packet.Layer { - p := packet.Layer{} - return &p -} - -func NewEmptyFieldValue() *packet.FieldValue { - f := packet.FieldValue{} - return &f -} - -func NewFieldValue( - value string, -) *packet.FieldValue { - f := packet.FieldValue{ - Value: value, - } - return &f -} - -func AppendField(pack *packet.Layer, field *packet.FieldValue) int { - i := len(pack.Values) - pack.Values = append(pack.Values, *field) - return i + 1 -} - -func AddField(pack *packet.Layer, index int, field *packet.FieldValue) { - if len(pack.Values) == index { - AppendField(pack, field) - return - } - ret := make([]packet.FieldValue, 0) - ret = append(ret, pack.Values[:index]...) - ret = append(ret, *field) - ret = append(ret, pack.Values[index:]...) - pack.Values = ret -} - -func AppendLayer(pack *packet.Structure, layer *packet.Layer) { - pack.Layers = append(pack.Layers, *layer) -} - -func Addlayer(pack *packet.Structure, index int, layer *packet.Layer) { - if len(pack.Layers) == index { - AppendLayer(pack, layer) - return - } - ret := make([]packet.Layer, 0) - ret = append(ret, pack.Layers[:index]...) - ret = append(ret, *layer) - ret = append(ret, pack.Layers[index:]...) - pack.Layers = ret -} - -func UpdateField(pack *packet.Layer, e int, field *packet.FieldValue) { - pack.Values[e] = *field -} - -func UpdateLayer(pack *packet.Structure, e int, layer *packet.Layer) { - pack.Layers[e] = *layer -} - -func RemoveField(pack *packet.Layer, e int) { - l := len(pack.Values) - 1 - ret := make([]packet.FieldValue, l) - ret = append(ret, pack.Values[:e]...) - ret = append(ret, pack.Values[e+1:]...) - pack.Values = ret -} - -func RemoveLayer(pack *packet.Structure, e int) { - l := len(pack.Layers) - 1 - ret := make([]packet.Layer, l) - ret = append(ret, pack.Layers[:e]...) - ret = append(ret, pack.Layers[e+1:]...) - pack.Layers = ret -} - -func Load(pack *packet.Structure, path string) error { - data, err := os.ReadFile(path) - if err != nil { - return err - } - err = json.Unmarshal(data, pack) - return err -} - -func ToJson(pack *packet.Structure) string { - data, err := json.MarshalIndent(*pack, "", " ") - if err != nil { - return "" - } - return string(data) -} - -func Save(pack *packet.Structure, path string) error { - data, err := json.MarshalIndent(*pack, "", " ") - if err != nil { - return err - } - err = os.WriteFile(path, data, fs.ModeAppend) - return err -} diff --git a/protocol/dopmeta.go b/protocol/dopmeta.go deleted file mode 100644 index a89e05a..0000000 --- a/protocol/dopmeta.go +++ /dev/null @@ -1,16 +0,0 @@ -package protocol - -const DOPVersion string = "1.0" - -type DOPMeta struct { - // DOP metadata version 1.0 - DOPVersion string - Name string - Version string - TCPIPLayer uint - OSILayer uint - ExtensionTo string - Description string - RequiredJSFunctions []string - LowerLayerIdentification map[string]string -} diff --git a/protocol/field.go b/protocol/field.go index f1f3d5f..a8deded 100644 --- a/protocol/field.go +++ b/protocol/field.go @@ -3,13 +3,14 @@ package protocol import "encoding/json" type Field struct { - Name string // Name of the Field - Desc string // Lengthy description - Regex string // Regex to recognize values - Size int // Size in bits! - SubFields []Field // Possible sub-fields - Optional bool // Is this field required? - Payload bool // Is this field the payload or next protocol level? + Name string // Name of the Field + Desc string // Lengthy description + Regex string // Regex to recognize values + Size int // Size in bits! + SubFields []Field // Possible sub-fields + Optional bool // Is this field required? + Payload bool // Is this field the payload or next protocol level? + JavaScript string } type ProtocolFieldReferencer interface { @@ -24,3 +25,29 @@ func (f *Field) ToJson() string { } return string(b) } + +func NewEmptyField() *Field { + f := Field{} + return &f +} + +func NewField( + name string, + desc string, + regex string, + size int, + subfields []Field, + optional bool, + payload bool, +) *Field { + f := Field{ + Name: name, + Desc: desc, + Regex: regex, + Size: size, + SubFields: subfields, + Optional: optional, + Payload: payload, + } + return &f +} diff --git a/protocol/protocol.go b/protocol/protocol.go index b9721f8..a24602e 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -1,13 +1,107 @@ package protocol -type ProtocolStructure struct { - Metadata DOPMeta +import ( + "encoding/json" + "fmt" + "io/fs" + "os" +) + +type Protocol struct { + Metadata ProtocolMeta Structure []*Field DefaultValues []DefaultValue JavaScript string } -type ProtocolReferencer interface { - GetProtocol() *ProtocolStructure - SetProtocol(prot *ProtocolStructure) +func (p Protocol) ToJson() string { + data, err := json.MarshalIndent(p, "", " ") + if err != nil { + return "" + } + return string(data) +} + +func NewProtocolStructure() *Protocol { + p := Protocol{} + return &p +} +func (prot *Protocol) AppendField(field Field) int { + i := len(prot.Structure) + prot.Structure = append(prot.Structure, &field) + return i + 1 +} +func (prot *Protocol) AddField(index int, field *Field) { + if len(prot.Structure) == index { + prot.AppendField(*field) + return + } + ret := make([]*Field, 0) + ret = append(ret, prot.Structure[:index]...) + ret = append(ret, field) + ret = append(ret, prot.Structure[index:]...) + prot.Structure = ret +} + +func (prot *Protocol) UpdateFieldByName(name string, field *Field) { + var fnd int = -1 + for i, f := range prot.Structure { + if f.Name == name { + fnd = i + } + } + if fnd != -1 { + prot.Structure[fnd] = field + } +} + +func (prot *Protocol) UpdateFieldByElement(element int, field *Field) { + prot.Structure[element] = field +} + +func (prot *Protocol) RemoveFieldByName(name string) { + element := -1 + for i, f := range prot.Structure { + if f.Name == name { + element = i + } + } + if element == -1 { + return + } + prot.RemoveFieldByElement(element) +} + +func (prot *Protocol) RemoveFieldByElement(field int) { + ret := make([]*Field, 0) + for i, f := range prot.Structure { + if i != field { + fmt.Printf("appending %d, %s\n", i, f.ToJson()) + ret = append(ret, f) + } + } + prot.Structure = ret +} + +func (prot *Protocol) Load(path string) error { + data, err := os.ReadFile(path) + if err != nil { + return err + } + err = json.Unmarshal(data, prot) + return err +} +func (prot *Protocol) Save(path string) error { + data, err := json.MarshalIndent(*prot, "", " ") + if err != nil { + return err + } + err = os.WriteFile(path, data, fs.ModeAppend) + return err +} + +func LoadNew(path string) (*Protocol, error) { + prot := NewProtocolStructure() + err := prot.Load(path) + return prot, err } diff --git a/protocolctl/protocolctl_test.go b/protocol/protocol_test.go similarity index 88% rename from protocolctl/protocolctl_test.go rename to protocol/protocol_test.go index db36f13..fc3c464 100644 --- a/protocolctl/protocolctl_test.go +++ b/protocol/protocol_test.go @@ -1,10 +1,8 @@ -package protocolctl +package protocol import ( "fmt" "testing" - - "gitea.mmo.to/ppForge/ppforge/protocol" ) func TestUpdateMetaData(t *testing.T) { @@ -30,7 +28,6 @@ func TestUpdateMetaData(t *testing.T) { if prot.Metadata.Name != name || prot.Metadata.Description != desc || prot.Metadata.ExtensionTo != extensionTo || - prot.Metadata.OSILayer != osilayer || prot.Metadata.TCPIPLayer != tcpiplayer || prot.Metadata.Version != version || prot.Metadata.LowerLayerIdentification != nil || @@ -40,8 +37,8 @@ func TestUpdateMetaData(t *testing.T) { } } -func GenerateFields() []protocol.Field { - slc := make([]protocol.Field, 0) +func GenerateFields() []Field { + slc := make([]Field, 0) for i := 0; i < 10; i++ { field := NewField( fmt.Sprintf("testfield%d", i), @@ -57,11 +54,11 @@ func GenerateFields() []protocol.Field { return slc } -func GenerateStructure() *protocol.ProtocolStructure { +func GenerateStructure() *Protocol { p := NewProtocolStructure() slc := GenerateFields() for i, e := range slc { - AppendField(p, e) + p.AppendField(e) fmt.Printf("%d %s\n", i, e.ToJson()) } for i, e := range p.Structure { @@ -82,7 +79,7 @@ func TestFieldAppend(t *testing.T) { false, ) p := NewProtocolStructure() - AppendField(p, *f) + p.AppendField(*f) if p.Structure[0].Name != "testfield" { t.Log("Append failed.") t.Fail() @@ -110,7 +107,7 @@ func TestUpdateFieldByElement(t *testing.T) { f := NewField( "UpdatedField", "", "", 42, nil, false, true, ) - UpdateFieldByElement(p, 5, f) + p.UpdateFieldByElement(5, f) for i, e := range p.Structure { fmt.Printf("%d %s\n", i, e.ToJson()) } @@ -135,7 +132,7 @@ func TestUpdateFieldByElement(t *testing.T) { */ func TestRemoveFieldByElement(t *testing.T) { p := GenerateStructure() - RemoveFieldByElement(p, 3) + p.RemoveFieldByElement(3) for i, e := range p.Structure { fmt.Printf("%d %s\n", i, e.ToJson()) } @@ -147,5 +144,5 @@ func TestRemoveFieldByElement(t *testing.T) { func TestToJson(t *testing.T) { p := GenerateStructure() - fmt.Print(ToJson(p)) + fmt.Print(p.ToJson()) } diff --git a/protocol/protocolmeta.go b/protocol/protocolmeta.go new file mode 100644 index 0000000..df2a9ae --- /dev/null +++ b/protocol/protocolmeta.go @@ -0,0 +1,28 @@ +package protocol + +type ProtocolMeta struct { + Name string + Revision uint + Version string + TCPIPLayer uint + ExtensionTo string + Description string + RequiredJSFunctions []string + LowerLayerIdentification map[string]string +} + +func UpdateMetaData( + prot *Protocol, + name string, + version string, + tcpiplayer uint, + osilayer uint, + extensionTo string, + desc string, +) { + prot.Metadata.Name = name + prot.Metadata.Description = desc + prot.Metadata.ExtensionTo = extensionTo + prot.Metadata.Version = version + prot.Metadata.TCPIPLayer = tcpiplayer +} diff --git a/protocolctl/protocolctl.go b/protocolctl/protocolctl.go deleted file mode 100644 index 77f9adc..0000000 --- a/protocolctl/protocolctl.go +++ /dev/null @@ -1,147 +0,0 @@ -package protocolctl - -import ( - "encoding/json" - "fmt" - "io/fs" - "os" - - "gitea.mmo.to/ppForge/ppforge/protocol" -) - -func NewProtocolStructure() *protocol.ProtocolStructure { - p := protocol.ProtocolStructure{} - return &p -} - -func UpdateMetaData( - prot *protocol.ProtocolStructure, - name string, - version string, - tcpiplayer uint, - osilayer uint, - extensionTo string, - desc string, -) { - prot.Metadata.Name = name - prot.Metadata.Description = desc - prot.Metadata.ExtensionTo = extensionTo - prot.Metadata.Version = version - prot.Metadata.OSILayer = osilayer - prot.Metadata.TCPIPLayer = tcpiplayer -} - -func NewEmptyField() *protocol.Field { - f := protocol.Field{} - return &f -} - -func NewField( - name string, - desc string, - regex string, - size int, - subfields []protocol.Field, - optional bool, - payload bool, -) *protocol.Field { - f := protocol.Field{ - Name: name, - Desc: desc, - Regex: regex, - Size: size, - SubFields: subfields, - Optional: optional, - Payload: payload, - } - return &f -} - -func AppendField(prot *protocol.ProtocolStructure, field protocol.Field) int { - i := len(prot.Structure) - prot.Structure = append(prot.Structure, &field) - return i + 1 -} -func AddField(prot *protocol.ProtocolStructure, index int, field *protocol.Field) { - if len(prot.Structure) == index { - AppendField(prot, *field) - return - } - ret := make([]*protocol.Field, 0) - ret = append(ret, prot.Structure[:index]...) - ret = append(ret, field) - ret = append(ret, prot.Structure[index:]...) - prot.Structure = ret -} - -func UpdateFieldByName(prot *protocol.ProtocolStructure, name string, field *protocol.Field) { - var fnd int = -1 - for i, f := range prot.Structure { - if f.Name == name { - fnd = i - } - } - if fnd != -1 { - prot.Structure[fnd] = field - } -} - -func UpdateFieldByElement(prot *protocol.ProtocolStructure, element int, field *protocol.Field) { - prot.Structure[element] = field -} - -func RemoveFieldByName(prot *protocol.ProtocolStructure, name string) { - element := -1 - for i, f := range prot.Structure { - if f.Name == name { - element = i - } - } - if element == -1 { - return - } - RemoveFieldByElement(prot, element) -} - -func RemoveFieldByElement(prot *protocol.ProtocolStructure, field int) { - ret := make([]*protocol.Field, 0) - for i, f := range prot.Structure { - if i != field { - fmt.Printf("appending %d, %s\n", i, f.ToJson()) - ret = append(ret, f) - } - } - prot.Structure = ret -} - -func Load(prot *protocol.ProtocolStructure, path string) error { - data, err := os.ReadFile(path) - if err != nil { - return err - } - err = json.Unmarshal(data, prot) - return err -} - -func LoadNew(path string) (*protocol.ProtocolStructure, error) { - prot := NewProtocolStructure() - err := Load(prot, path) - return prot, err -} - -func ToJson(prot *protocol.ProtocolStructure) string { - data, err := json.MarshalIndent(*prot, "", " ") - if err != nil { - return "" - } - return string(data) -} - -func Save(prot *protocol.ProtocolStructure, path string) error { - data, err := json.MarshalIndent(*prot, "", " ") - if err != nil { - return err - } - err = os.WriteFile(path, data, fs.ModeAppend) - return err -} diff --git a/test/cop/blabla.protocoljson b/test/cop/blabla.protocoljson new file mode 100644 index 0000000..022ae3a --- /dev/null +++ b/test/cop/blabla.protocoljson @@ -0,0 +1,34 @@ +{ + "Metadata": { + "Revision": 2, + "Name": "blabla", + "Version": "", + "TCPIPLayer": 0, + "ExtensionTo": "", + "Description": "", + "RequiredJSFunctions": null, + "LowerLayerIdentification": null + }, + "Structure": [ + { + "Name": "asdfasdf", + "Desc": "", + "Regex": "", + "Size": 8, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "asdfasdfasdf", + "Desc": "test", + "Regex": "", + "Size": 24, + "SubFields": null, + "Optional": false, + "Payload": false + } + ], + "DefaultValues": null, + "JavaScript": "" +} \ No newline at end of file diff --git a/test/cop/blah.protocoljson b/test/cop/blah.protocoljson new file mode 100644 index 0000000..13a71f0 --- /dev/null +++ b/test/cop/blah.protocoljson @@ -0,0 +1,61 @@ +{ + "Metadata": { + "Revision": 1, + "Name": "blah", + "Version": "", + "TCPIPLayer": 0, + "ExtensionTo": "", + "Description": "", + "RequiredJSFunctions": null, + "LowerLayerIdentification": null + }, + "Structure": [ + { + "Name": "test", + "Desc": "", + "Regex": "", + "Size": 32, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 32, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 8, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 4, + "SubFields": null, + "Optional": false, + "Payload": false + }, + { + "Name": "", + "Desc": "", + "Regex": "", + "Size": 20, + "SubFields": null, + "Optional": false, + "Payload": false + } + ], + "DefaultValues": null, + "JavaScript": "" +} \ No newline at end of file diff --git a/test/cop/test.protocoljson b/test/cop/test.protocoljson new file mode 100644 index 0000000..06c9f73 --- /dev/null +++ b/test/cop/test.protocoljson @@ -0,0 +1,25 @@ +{ + "Metadata": { + "Revision": 1, + "Name": "test", + "Version": "", + "TCPIPLayer": 0, + "ExtensionTo": "", + "Description": "test", + "RequiredJSFunctions": null, + "LowerLayerIdentification": null + }, + "Structure": [ + { + "Name": "test", + "Desc": "test", + "Regex": "", + "Size": 128, + "SubFields": null, + "Optional": false, + "Payload": false + } + ], + "DefaultValues": null, + "JavaScript": "" +} \ No newline at end of file diff --git a/test/protocoldb/testprotocolempty.protocoljson b/test/cop/testprotocolempty.protocoljson similarity index 100% rename from test/protocoldb/testprotocolempty.protocoljson rename to test/cop/testprotocolempty.protocoljson