steamd 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +4 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +6 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +21 -0
  9. data/README.md +51 -0
  10. data/Rakefile +22 -0
  11. data/bin/console +6 -0
  12. data/bin/setup +6 -0
  13. data/bin/steamd +6 -0
  14. data/grammar/class.treetop +63 -0
  15. data/grammar/enums.treetop +44 -0
  16. data/grammar/import.treetop +11 -0
  17. data/grammar/shared.treetop +62 -0
  18. data/grammar/steamd.treetop +15 -0
  19. data/language/emsg.steamd +1802 -0
  20. data/language/enums.steamd +989 -0
  21. data/language/eresult.steamd +119 -0
  22. data/language/gamecoordinator.steamd +17 -0
  23. data/language/header.steamd +37 -0
  24. data/language/netheader.steamd +62 -0
  25. data/language/steammsg.steamd +357 -0
  26. data/lib/ext/string.rb +33 -0
  27. data/lib/steamd.rb +40 -0
  28. data/lib/steamd/cli.rb +24 -0
  29. data/lib/steamd/cli_options.rb +58 -0
  30. data/lib/steamd/code_generator.rb +41 -0
  31. data/lib/steamd/generated/emsg.rb +3464 -0
  32. data/lib/steamd/generated/enums.rb +1750 -0
  33. data/lib/steamd/generated/eresult.rb +236 -0
  34. data/lib/steamd/generated/gamecoordinator.rb +119 -0
  35. data/lib/steamd/generated/header.rb +261 -0
  36. data/lib/steamd/generated/netheader.rb +315 -0
  37. data/lib/steamd/generated/steammsg.rb +2527 -0
  38. data/lib/steamd/generator.rb +6 -0
  39. data/lib/steamd/generator/generated_class.rb +128 -0
  40. data/lib/steamd/generator/generated_enum.rb +60 -0
  41. data/lib/steamd/generator/generated_import.rb +21 -0
  42. data/lib/steamd/generator/implementation.rb +83 -0
  43. data/lib/steamd/generator/ruby/class.erb +39 -0
  44. data/lib/steamd/generator/ruby/enum.erb +14 -0
  45. data/lib/steamd/generator/ruby/import.erb +1 -0
  46. data/lib/steamd/generator/ruby/ruby.rb +54 -0
  47. data/lib/steamd/generator/ruby/serializable_constant.rb +20 -0
  48. data/lib/steamd/generator/ruby/serializable_type.rb +93 -0
  49. data/lib/steamd/generator/ruby/serializable_variable.rb +85 -0
  50. data/lib/steamd/generator/ruby/steam_serializable.rb +89 -0
  51. data/lib/steamd/nodes/block_node.rb +14 -0
  52. data/lib/steamd/nodes/class_statement_node.rb +46 -0
  53. data/lib/steamd/nodes/class_type_node.rb +12 -0
  54. data/lib/steamd/nodes/enum_statement_node.rb +50 -0
  55. data/lib/steamd/nodes/enum_variable_node.rb +24 -0
  56. data/lib/steamd/nodes/import_statement_node.rb +26 -0
  57. data/lib/steamd/nodes/node.rb +3 -0
  58. data/lib/steamd/nodes/nodes.rb +10 -0
  59. data/lib/steamd/nodes/variable_node.rb +106 -0
  60. data/lib/steamd/parser.rb +157 -0
  61. data/lib/steamd/version.rb +14 -0
  62. data/steamd.gemspec +38 -0
  63. data/tasks/language.rake +11 -0
  64. metadata +220 -0
@@ -0,0 +1,85 @@
1
+
2
+ # frozen_string_literal: true
3
+ # Represents a Serialized var
4
+ class SerizableVariable
5
+ attr_reader :name, :type, :size, :modifier, :modifier_size, :value
6
+ attr_accessor :flag
7
+
8
+ # Initialize a SteamSerializable from a hash
9
+ def initialize(var)
10
+ @name = var[:name]
11
+ @value = var[:value]
12
+ @modifier = var[:modifier]
13
+ @modifier_size = var[:modifier_size]
14
+ @type = Type.new(var[:type])
15
+ end
16
+
17
+ # Serialize the object
18
+ def serialize
19
+ if type.primitive?
20
+ serialize_primitive
21
+ elsif type.encodable?
22
+ serialize_encodable
23
+ else
24
+ serialize_object
25
+ end
26
+ end
27
+
28
+ # Serialize the object
29
+ #
30
+ # @param io [:read]
31
+ def deserialize(io)
32
+ @value = if type.primitive?
33
+ deserialize_primitive(io)
34
+ elsif type.encodable?
35
+ deserialize_encodable(io)
36
+ else
37
+ deserialize_object(io)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # @api private
44
+ def deserialize_object(io)
45
+ type = Type.new(self.type.klass::DATA_TYPE)
46
+ io.read(type.bytesize).unpack(type.bytedirective).first
47
+ end
48
+
49
+ # @api private
50
+ def deserialize_encodable(io)
51
+ raise NotImplementedError if flag.nil? || modifier_size.nil?
52
+ type.klass.decode(io.read(flag.value))
53
+ end
54
+
55
+ # @api private
56
+ def deserialize_primitive(io)
57
+ io.read(type.bytesize).unpack(type.bytedirective).first
58
+ end
59
+
60
+ # @api private
61
+ def serialize_object
62
+ type = Type.new(self.type.klass::DATA_TYPE)
63
+ [value].pack(type.bytedirective)
64
+ end
65
+
66
+ # @api private
67
+ def serialize_encodable
68
+ raise NotImplementedError unless value.respond_to?(:encode)
69
+ value.encode
70
+ end
71
+
72
+ # @api private
73
+ def serialize_primitive
74
+ if flag
75
+ [flag.value.encode.length].pack('<l')
76
+ else
77
+ [value].pack(type.bytedirective)
78
+ end
79
+ end
80
+
81
+ # @api private
82
+ def validate
83
+ raise NotImplementedError unless @var[:size].nil?
84
+ end
85
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+ require 'steamd/generator/ruby/serializable_type'
3
+ require 'steamd/generator/ruby/serializable_variable'
4
+ require 'steamd/generator/ruby/serializable_constant'
5
+
6
+ # Included in each Generated Ruby class. Provides access to methods on the class
7
+ # as well as serialization options.
8
+ module SteamSerializable
9
+ # Variables in this class
10
+ attr_reader :variables
11
+
12
+ # Variables in this class
13
+ attr_reader :constants
14
+
15
+ # Sets the variables and constants of this Steam object
16
+ def initialize(vars, consts = [])
17
+ @variables = vars.each_with_object({}) { |v, m| m[v[:name]] = v }
18
+ @constants = consts.each_with_object({}) { |v, m| m[v[:name]] = v }
19
+ end
20
+
21
+ # Encode to a given IO stream
22
+ #
23
+ # @param io [:read]
24
+ def encode_to(io)
25
+ io.write(serialize)
26
+ end
27
+
28
+ # Serialize the constants and variables into a stream
29
+ #
30
+ # @return [String] the byte representation
31
+ def serialize
32
+ stream = StringIO.new
33
+ stream.set_encoding('BINARY')
34
+ stream.write((consts + vars).map(&:serialize).join)
35
+ stream.string
36
+ end
37
+ alias encode serialize
38
+
39
+ # Deserialize the object using an IO stream
40
+ #
41
+ # @param io [:read] The io stream to deserialize
42
+ def deserialize(io)
43
+ (consts + vars).each { |v| send("#{v.name}=", v.deserialize(io)) }
44
+ self
45
+ end
46
+ alias decode deserialize
47
+ alias decode_from deserialize
48
+
49
+ # Returns a list of SerizableConstant objects. Allowing you to
50
+ # serialize each constant
51
+ #
52
+ # @return [Array<SerizableConstant>] the constants
53
+ def consts
54
+ constants.values.map { |const| SerizableConstant.new(const) }
55
+ end
56
+
57
+ # Returns a list of SerializedVariable objects. Allowing you to
58
+ # serialize each constant
59
+ #
60
+ # @return [Array<SerializedVariable>] the constants
61
+ def vars
62
+ vars = variables.values.map do |v|
63
+ SerizableVariable.new(v)
64
+ end
65
+
66
+ vars.map do |var|
67
+ var.flag = flag(vars, var)
68
+ var
69
+ end
70
+ end
71
+
72
+ # Looks up the variable flag. This is used for when variables
73
+ # are of a defined length
74
+ #
75
+ # ie:
76
+ # int header_len;
77
+ # proto<header_len> ProtoBuf name;
78
+ #
79
+ # The flag in the case of serialization would be the "name" variable as it
80
+ # would need to write that before it can write header len.
81
+ #
82
+ # The flag in the case of deserialization would be the "header_len" variable
83
+ # because it defines how many bytes to read so we can read the "name"
84
+ # variable
85
+ def flag(vars, var)
86
+ (vars.select { |v| v.modifier_size == var.name } +
87
+ vars.select { |v| v.name == var.modifier_size }).first
88
+ end
89
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ # The root of the parsed tree
3
+ class Block < Node
4
+ # Gets the statements in a Steam Language block
5
+ #
6
+ # @see ClassStatement
7
+ # @see ImportStatement
8
+ # @see EnumStatement
9
+ #
10
+ # @return Array
11
+ def statements
12
+ elements.map(&:statement)
13
+ end
14
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ # A parsed class statement
3
+ #
4
+ # @example A class
5
+ # class Test { }
6
+ #
7
+ # Contains the variables, class name, type
8
+ class ClassStatement < Node
9
+ # Returns the class object as a hash
10
+ #
11
+ # @return [Hash] hash representation of the class
12
+ def to_hash
13
+ {
14
+ name: name,
15
+ type: type,
16
+ variables: variables
17
+ }
18
+ end
19
+
20
+ # The name of the class
21
+ def name
22
+ class_name.text_value
23
+ end
24
+
25
+ # The class type
26
+ #
27
+ # ie class Test<EMsg::Blah> {}
28
+ def type
29
+ types = elements.select { |el| el.is_a?(ClassType) }
30
+ type = types.first
31
+ type&.value
32
+ end
33
+
34
+ # Returns a list of variables
35
+ #
36
+ # @return [Array] variables
37
+ def variables
38
+ declerations = [first_var] + other.elements.map(&:decleration)
39
+
40
+ variables = declerations.select do |node|
41
+ node.is_a?(Variable)
42
+ end
43
+
44
+ variables.map!(&:to_hash)
45
+ end
46
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ # Holds a class type, if it exists
3
+ # This node may not always be in the tree
4
+ class ClassType < Node
5
+ # The type of the class
6
+ #
7
+ # @return [String]
8
+ def value
9
+ type = text_value.strip
10
+ type.empty? ? nil : type
11
+ end
12
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+ # Represents an Enum statement
3
+ #
4
+ # @example Enum Statement
5
+ # enum Test { Invalid = 1; }
6
+ class EnumStatement < Node
7
+ # The name of the enum
8
+ #
9
+ # @return [String]
10
+ def name
11
+ enum_name.text_value
12
+ end
13
+
14
+ # The type of the enum
15
+ #
16
+ # @return [String]
17
+ def type
18
+ enum_type.type.text_value if enum_type.respond_to?(:type)
19
+ end
20
+
21
+ # Returns true if this enum uses bitmask flags
22
+ #
23
+ # @return [Bool]
24
+ def flags?
25
+ type == 'flags'
26
+ end
27
+
28
+ # Returns a list of EnumVariable objects
29
+ #
30
+ # @return Array
31
+ def variables
32
+ declerations = [first_var] + other.elements.map(&:enum_decleration)
33
+
34
+ variables = declerations.select do |node|
35
+ node.is_a?(EnumVariable)
36
+ end
37
+
38
+ variables.map!(&:to_hash)
39
+ end
40
+
41
+ # Hash representation of this Enum
42
+ def to_hash
43
+ {
44
+ name: name,
45
+ type: type,
46
+ flags: flags?,
47
+ variables: variables
48
+ }
49
+ end
50
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ # Represents a variable declared in an Enum
3
+ #
4
+ # @example
5
+ # Invalid = 0
6
+ class EnumVariable < Node
7
+ # The name of the EnumVariable
8
+ def name
9
+ enum_variable_name.text_value
10
+ end
11
+
12
+ # The value of the EnumVariable
13
+ def value
14
+ enum_variable_value.value
15
+ end
16
+
17
+ # Hash representation of the EnumVariable
18
+ def to_hash
19
+ {
20
+ name: name,
21
+ value: value
22
+ }
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # Represents an import statement
3
+ #
4
+ # ie: #import "test.steamd"
5
+ class ImportStatement < Node
6
+ # The full name including the extension of the import file
7
+ #
8
+ # @return [String]
9
+ def name
10
+ filename.text_value
11
+ end
12
+
13
+ # The name not including the extension of the import file
14
+ #
15
+ # @return [String]
16
+ def filename_no_ext
17
+ File.basename(name, '.*')
18
+ end
19
+
20
+ # The hash representation
21
+ #
22
+ # @return [Hash]
23
+ def to_hash
24
+ { filename: filename_no_ext }
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+ # Wrapper around a treetop node
3
+ Node = Class.new(Treetop::Runtime::SyntaxNode)
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'steamd/nodes/node'
4
+ require 'steamd/nodes/block_node'
5
+ require 'steamd/nodes/class_type_node'
6
+ require 'steamd/nodes/class_statement_node'
7
+ require 'steamd/nodes/variable_node'
8
+ require 'steamd/nodes/enum_variable_node'
9
+ require 'steamd/nodes/enum_statement_node'
10
+ require 'steamd/nodes/import_statement_node'
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+ # Base variable, each variable has a type and a name at the very least.
3
+ class Variable < Node
4
+ # Returns the name of the variable
5
+ #
6
+ # @return [String] the variable name
7
+ def name
8
+ variable_name.text_value
9
+ end
10
+
11
+ # Returns the type of the variable
12
+ #
13
+ # @return [String] the variable type
14
+ def type
15
+ var_type.type.text_value
16
+ end
17
+
18
+ # Returns the size, if any of the variable. ie byte<6> y;
19
+ #
20
+ # @return [String/Integer/nil] the variable size
21
+ def size
22
+ return nil unless var_type && var_type.respond_to?(:size)
23
+
24
+ if var_type.size.text_value.empty?
25
+ nil
26
+ else
27
+ var_type.size.var_value.value
28
+ end
29
+ end
30
+
31
+ # Hash representation of this Variable Node
32
+ #
33
+ # @return [Hash]
34
+ def to_hash
35
+ {
36
+ name: name,
37
+ type: type,
38
+ modifier: nil,
39
+ value: nil,
40
+ size: size,
41
+ modifier_size: nil
42
+ }
43
+ end
44
+ end
45
+
46
+ # Variable with a modifier.
47
+ #
48
+ # ie: proto int x;
49
+ class VariableWithModifier < Variable
50
+ # Determins if the modifier of this variable is sized.
51
+ #
52
+ # ie: proto<len> CMsgHeaderProtobuf x;
53
+ def sized?
54
+ var_modifier.respond_to?(:size) &&
55
+ !var_modifier.size.text_value.empty?
56
+ end
57
+
58
+ # The size of the variable modifier
59
+ def modifier_size
60
+ return nil if var_type.nil?
61
+
62
+ var_modifier.size.value if sized?
63
+ end
64
+ end
65
+
66
+ # A variable with a modifier but no value
67
+ # ie: proto header hi;
68
+ class VariableWithModifierNoValue < VariableWithModifier
69
+ # Hash representation of the VariableWithModifierNoValue
70
+ #
71
+ # @return [Hash]
72
+ def to_hash
73
+ hsh = super
74
+
75
+ hsh.merge!(
76
+ modifier: var_modifier.word.text_value,
77
+ modifier_size: modifier_size
78
+ )
79
+ end
80
+ end
81
+
82
+ # A variable with a modifier and a default value
83
+ class VariableWithModifierWithValue < VariableWithModifierNoValue
84
+ # Hash representation of the VariableWithModifierWithValue
85
+ #
86
+ # @return [Hash]
87
+ def to_hash
88
+ hsh = super
89
+
90
+ hsh.merge!(
91
+ value: var_value.value
92
+ )
93
+ end
94
+ end
95
+
96
+ # Variable, no modifier with a value
97
+ # ie: int x = 1;
98
+ class VariableWithValue < Variable
99
+ # Hash representation of the VariableWithValue
100
+ #
101
+ # @return [Hash]
102
+ def to_hash
103
+ hsh = super
104
+ hsh.merge!(value: var_value.value)
105
+ end
106
+ end