instruction.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package guac
  15. import (
  16. "fmt"
  17. "strconv"
  18. "yunion.io/x/pkg/errors"
  19. )
  20. type Instruction struct {
  21. Opcode string
  22. Args []string
  23. }
  24. func NewInstruction(op string, args ...string) *Instruction {
  25. return &Instruction{
  26. Opcode: op,
  27. Args: args,
  28. }
  29. }
  30. func (i *Instruction) String() string {
  31. ret := fmt.Sprintf("%d.%s", len(i.Opcode), i.Opcode)
  32. for _, value := range i.Args {
  33. ret += fmt.Sprintf(",%d.%s", len(value), value)
  34. }
  35. ret += ";"
  36. return ret
  37. }
  38. func parse(buf []byte) ([]*Instruction, []byte, error) {
  39. ret := []*Instruction{}
  40. if len(buf) == 0 {
  41. return ret, []byte{}, nil
  42. }
  43. start, opcode, args := 0, "", []string{}
  44. begin := 0
  45. for i := 0; i < len(buf); i++ {
  46. switch buf[i] {
  47. case ',':
  48. start = i + 1
  49. case '.':
  50. length, err := strconv.Atoi(string(buf[start:i]))
  51. if err != nil {
  52. return nil, []byte{}, errors.Wrapf(err, "Atoi(%s)", string(buf[start:i]))
  53. }
  54. if i+length+1 > len(buf) {
  55. return ret, buf[begin:], nil
  56. }
  57. str := string(buf[i+1 : i+length+1])
  58. if len(opcode) == 0 {
  59. opcode = str
  60. } else {
  61. args = append(args, str)
  62. }
  63. i += length
  64. case ';':
  65. start = i + 1
  66. begin = i + 1
  67. instruction := NewInstruction(opcode, args...)
  68. ret = append(ret, instruction)
  69. opcode = ""
  70. args = []string{}
  71. }
  72. }
  73. if buf[len(buf)-1] != ';' {
  74. return ret, buf[begin:], nil
  75. }
  76. return ret, []byte{}, nil
  77. }