divine 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -14
- data/README.md +25 -0
- data/Rakefile +34 -19
- data/divine.gemspec +1 -0
- data/lib/divine.rb +3 -1
- data/lib/divine/code_generators/code_generator.rb +51 -1
- data/lib/divine/code_generators/csharp.rb +898 -0
- data/lib/divine/code_generators/java.rb +125 -13
- data/lib/divine/code_generators/javascript.rb +111 -4
- data/lib/divine/code_generators/ruby.rb +103 -9
- data/lib/divine/dsl.rb +95 -6
- data/lib/divine/graph_generator/graph_generator.rb +81 -0
- data/lib/divine/version.rb +2 -1
- data/test/basic_complex_test/basic_complex_test.rb +5 -0
- data/test/basic_complex_test/graph.jpg +0 -0
- data/test/basic_complex_test/java_test/JavaTest.java +1 -1
- data/test/basic_complex_test/ruby_test/ruby_test.rb +17 -4
- data/test/binaryTree_test/binaryTree_test.rb +5 -0
- data/test/binaryTree_test/csharp_test/csharp_test.cs +99 -0
- data/test/binaryTree_test/graph.png +0 -0
- data/test/binaryTree_test/java_test/JavaTest.java +1 -1
- data/test/binaryTree_test/ruby_test/ruby_test.rb +26 -3
- data/test/complex_test/complex_test.rb +5 -0
- data/test/complex_test/csharp_test/csharp_test.cs +109 -0
- data/test/complex_test/graph.png +0 -0
- data/test/complex_test/java_test/JavaTest.java +1 -1
- data/test/complex_test/ruby_test/ruby_test.rb +24 -1
- data/test/dynamic_int_test/csharp_test/csharp_test.cs +76 -0
- data/test/dynamic_int_test/dynamic_int_test.rb +20 -0
- data/test/dynamic_int_test/graph.jpg +0 -0
- data/test/dynamic_int_test/java_test/JavaTest.java +72 -0
- data/test/dynamic_int_test/js_test/js_test.js +54 -0
- data/test/dynamic_int_test/ruby_test/ruby_test.rb +55 -0
- data/test/ipv6_test/csharp_test/csharp_test.cs +73 -0
- data/test/ipv6_test/graph.jpg +0 -0
- data/test/ipv6_test/ipv6_test.rb +5 -0
- data/test/ipv6_test/java_test/JavaTest.java +1 -1
- data/test/ipv6_test/ruby_test/ruby_test.rb +24 -4
- data/test/lib/csharp/nunit.framework.dll +0 -0
- data/test/{java_lib → lib/java}/junit.jar +0 -0
- data/test/signed_int_test/csharp_test/csharp_test.cs +86 -0
- data/test/signed_int_test/graph.jpg +0 -0
- data/test/signed_int_test/java_test/JavaTest.java +1 -1
- data/test/signed_int_test/ruby_test/ruby_test.rb +21 -1
- data/test/signed_int_test/signed_int_test.rb +6 -0
- data/test/unify_test/unify_test.rb +17 -4
- metadata +54 -8
- data/test/signed_float_test/ruby_test/ruby_test.rb +0 -36
- data/test/signed_float_test/signed_float_test.rb +0 -14
data/.gitignore
CHANGED
@@ -16,25 +16,11 @@ test/tmp
|
|
16
16
|
test/version_tmp
|
17
17
|
tmp
|
18
18
|
*.class
|
19
|
-
test/basic_complex_test/java_test/bin.babel
|
20
|
-
test/basic_complex_test/js_test/bin.babel.js
|
21
|
-
test/basic_complex_test/ruby_test/bin.babel.rb
|
22
|
-
test/binaryTree_test/java_test/bin.babel
|
23
|
-
test/binaryTree_test/js_test/bin.babel.js
|
24
|
-
test/binaryTree_test/ruby_test/bin.babel.rb
|
25
|
-
test/complex_test/java_test/bin.babel
|
26
|
-
test/complex_test/js_test/bin.babel.js
|
27
|
-
test/complex_test/ruby_test/bin.babel.rb
|
28
|
-
test/ipv6_test/java_test/bin.babel
|
29
|
-
test/ipv6_test/js_test/bin.babel.js
|
30
|
-
test/ipv6_test/ruby_test/bin.babel.rb
|
31
19
|
test/basic_complex_test/ruby_test/test_babel.rb
|
32
20
|
test/binaryTree_test/ruby_test/test_binaryTree.rb
|
33
21
|
test/complex_test/ruby_test/test_complex.rb
|
34
22
|
test/ipv6_test/ruby_test/test_ipv6.rb
|
35
23
|
test/signed_int_test/ruby_test/test_signed_int.rb
|
36
|
-
test/signed_int_test/js_test/bin.babel.js
|
37
|
-
test/signed_int_test/ruby_test/bin.babel.rb
|
38
24
|
test/basic_complex_test/java_test/test_babel.java
|
39
25
|
test/binaryTree_test/java_test/test_binaryTree.java
|
40
26
|
test/complex_test/java_test/test_complex.java
|
@@ -45,3 +31,7 @@ test/binaryTree_test/js_test/test_binaryTree.js
|
|
45
31
|
test/complex_test/js_test/test_complex.js
|
46
32
|
test/ipv6_test/js_test/test_ipv6.js
|
47
33
|
test/signed_int_test/js_test/test_signed_int.js
|
34
|
+
bin.babel
|
35
|
+
bin.babel.csharp
|
36
|
+
bin.babel.rb
|
37
|
+
bin.babel.js
|
data/README.md
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
|
3
3
|
Divine provides a compact data interchange format for Ruby, Java and Javascript. Divine is similar to [Thrift](http://thrift.apache.org/) and [Protobuf](http://code.google.com/p/protobuf/), but I try to overcome of some of the shortcommings I think the other libraries have.
|
4
4
|
|
5
|
+
This software is still under active development and testing.
|
6
|
+
|
7
|
+
We support C#, Java, Ruby and Javascript at the moment.
|
5
8
|
|
6
9
|
## Example
|
7
10
|
|
@@ -152,6 +155,28 @@ Divine::CodeGenerator.new.generate(:ruby, file: 'test_babel.rb')
|
|
152
155
|
It is now not possible to alter _Foobar_ by accident. If you make a change to the struct, you will also need to provide a correct MD5 sum.
|
153
156
|
|
154
157
|
|
158
|
+
### Graphviz
|
159
|
+
|
160
|
+
To generate a graphviz diagram of your defined structs, add the following line to your definition file
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
Divine::GraphGenerator.new.draw(".", "graph", "jpg")
|
164
|
+
```
|
165
|
+
|
166
|
+
|
167
|
+
## Change log
|
168
|
+
Version 0.0.4
|
169
|
+
|
170
|
+
* Added dint63 (Dynamic Int 63)
|
171
|
+
* Added graphviz graph generation
|
172
|
+
|
173
|
+
Version 0.0.3
|
174
|
+
|
175
|
+
* Added C# code generator
|
176
|
+
* Added sint64 (Signed Int 64)
|
177
|
+
* Added versioning and freezing
|
178
|
+
|
179
|
+
|
155
180
|
## Installation
|
156
181
|
|
157
182
|
Add this line to your application's Gemfile:
|
data/Rakefile
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
|
2
|
+
require 'fileutils'
|
3
3
|
|
4
4
|
task :default => ["test:all"]
|
5
5
|
|
6
6
|
|
7
7
|
namespace :test do
|
8
8
|
desc "Run all tests"
|
9
|
-
task :all => [:ruby, :js, :java, :unify] # Make sure that the unify test be the last one in the list.
|
9
|
+
task :all => [:ruby, :js, :java, :csharp, :unify] # Make sure that the unify test be the last one in the list.
|
10
10
|
|
11
11
|
desc "Run Ruby code test suite"
|
12
12
|
task :ruby do
|
13
13
|
generate_source('ruby')
|
14
|
+
ruby "test/dynamic_int_test/ruby_test/ruby_test.rb"
|
14
15
|
ruby "test/signed_int_test/ruby_test/ruby_test.rb"
|
15
16
|
ruby "test/ipv6_test/ruby_test/ruby_test.rb"
|
16
17
|
ruby "test/complex_test/ruby_test/ruby_test.rb"
|
@@ -24,6 +25,7 @@ namespace :test do
|
|
24
25
|
desc "Run JS code test suite"
|
25
26
|
task :js do
|
26
27
|
generate_source('js')
|
28
|
+
system("node test/dynamic_int_test/js_test/js_test.js")
|
27
29
|
system("node test/signed_int_test/js_test/js_test.js")
|
28
30
|
system("node test/ipv6_test/js_test/js_test.js")
|
29
31
|
system("node test/complex_test/js_test/js_test.js")
|
@@ -37,28 +39,30 @@ namespace :test do
|
|
37
39
|
desc "Run java code test suite"
|
38
40
|
task :java do
|
39
41
|
generate_source('java')
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
system("javac -cp test/java_lib/junit.jar: test/ipv6_test/java_test/*.java")
|
47
|
-
system("java -cp test/ipv6_test/java_test/:test/java_lib/junit.jar:. org.junit.runner.JUnitCore JavaTest")
|
48
|
-
|
49
|
-
system("javac -cp test/java_lib/junit.jar: test/complex_test/java_test/*.java")
|
50
|
-
system("java -cp test/complex_test/java_test/:test/java_lib/junit.jar:. org.junit.runner.JUnitCore JavaTest")
|
51
|
-
|
52
|
-
system("javac -cp test/java_lib/junit.jar: test/binaryTree_test/java_test/*.java")
|
53
|
-
system("java -cp test/binaryTree_test/java_test/:test/java_lib/junit.jar:. org.junit.runner.JUnitCore JavaTest")
|
54
|
-
|
55
|
-
system("javac -cp test/java_lib/junit.jar: test/basic_complex_test/java_test/*.java")
|
56
|
-
system("java -cp test/basic_complex_test/java_test/:test/java_lib/junit.jar:. org.junit.runner.JUnitCore JavaTest")
|
42
|
+
test_java("dynamic_int")
|
43
|
+
test_java("signed_int")
|
44
|
+
test_java("ipv6")
|
45
|
+
test_java("complex")
|
46
|
+
test_java("binaryTree")
|
47
|
+
test_java("basic_complex")
|
57
48
|
|
58
49
|
system("find . -name 'test*.java' | xargs rm") # Remove generated source code files
|
59
50
|
system("find . -name '*.class' | xargs rm") # Remove generated .class files
|
60
51
|
end
|
61
52
|
|
53
|
+
desc "Run cSharp code test suite"
|
54
|
+
task :csharp do
|
55
|
+
generate_source('csharp')
|
56
|
+
test_csharp("dynamic_int")
|
57
|
+
test_csharp("signed_int")
|
58
|
+
test_csharp("ipv6")
|
59
|
+
test_csharp("complex")
|
60
|
+
test_csharp("binaryTree")
|
61
|
+
|
62
|
+
system("find . -name 'test*.cs' | xargs rm") # Remove generated source code files
|
63
|
+
system("find . -name '*.exe' | xargs rm") # Remove generated source code files
|
64
|
+
end
|
65
|
+
|
62
66
|
desc "Unify test to compare the produced binary files. Prerequisite Other tests must be run first to generate bin files to be compared"
|
63
67
|
task :unify do
|
64
68
|
ruby "test/unify_test/unify_test.rb"
|
@@ -66,9 +70,20 @@ namespace :test do
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
73
|
+
def test_java(test)
|
74
|
+
system("javac -cp test/lib/java/junit.jar: test/#{test}_test/java_test/*.java")
|
75
|
+
system("java -cp test/#{test}_test/java_test/:test/lib/java/junit.jar:. org.junit.runner.JUnitCore JavaTest")
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_csharp(test)
|
79
|
+
system("gmcs test/#{test}_test/csharp_test/*.cs -r:test/lib/csharp/nunit.framework.dll")
|
80
|
+
FileUtils.move "./test/#{test}_test/csharp_test/csharp_test.exe", "./test/lib/csharp/"
|
81
|
+
system("mono test/lib/csharp/csharp_test.exe")
|
82
|
+
end
|
69
83
|
|
70
84
|
def generate_source(lang)
|
71
85
|
puts "Divine Version #{Divine::VERSION}"
|
86
|
+
ruby "test/dynamic_int_test/dynamic_int_test.rb #{lang}"
|
72
87
|
ruby "test/signed_int_test/signed_int_test.rb #{lang}"
|
73
88
|
ruby "test/ipv6_test/ipv6_test.rb #{lang}"
|
74
89
|
ruby "test/complex_test/complex_test.rb #{lang}"
|
data/divine.gemspec
CHANGED
data/lib/divine.rb
CHANGED
@@ -7,12 +7,14 @@ require "divine/code_generators/code_generator"
|
|
7
7
|
require "divine/code_generators/ruby"
|
8
8
|
require "divine/code_generators/java"
|
9
9
|
require "divine/code_generators/javascript"
|
10
|
+
require "divine/code_generators/csharp"
|
11
|
+
require "divine/graph_generator/graph_generator"
|
10
12
|
|
11
13
|
module Divine
|
12
14
|
end
|
13
15
|
|
14
16
|
#
|
15
|
-
#
|
17
|
+
# start to build struct
|
16
18
|
#
|
17
19
|
def struct(name, properties=nil, &block)
|
18
20
|
#puts "struct #{name}"
|
@@ -5,7 +5,13 @@ require 'fileutils'
|
|
5
5
|
module Divine
|
6
6
|
$language_generators = {}
|
7
7
|
|
8
|
+
#
|
9
|
+
# Support methods that help to get fields and fields type from structs
|
10
|
+
#
|
8
11
|
class StructHandler
|
12
|
+
# name = name of struct
|
13
|
+
# latest_version = struct version
|
14
|
+
# structs = defined struct
|
9
15
|
attr_reader :name, :latest_version, :structs
|
10
16
|
|
11
17
|
def initialize(structs)
|
@@ -15,16 +21,30 @@ module Divine
|
|
15
21
|
@field_hash = structs.map(&:fields).flatten.group_by(&:name)
|
16
22
|
end
|
17
23
|
|
24
|
+
#
|
25
|
+
# Get field of given name
|
26
|
+
# * *Args* :
|
27
|
+
# - +name+ -> field's name
|
18
28
|
def field(name)
|
19
29
|
@field_hash[name]
|
20
30
|
end
|
21
31
|
|
32
|
+
#
|
33
|
+
# Get all fields names
|
34
|
+
#
|
22
35
|
def field_names
|
23
36
|
@field_hash.keys.sort
|
24
37
|
end
|
25
38
|
end
|
26
39
|
|
40
|
+
#
|
41
|
+
# Support methods needed when generating source code files
|
42
|
+
#
|
27
43
|
class BabelHelperMethods
|
44
|
+
|
45
|
+
#
|
46
|
+
# Handle indentation
|
47
|
+
#
|
28
48
|
def format_src(first_indent, following_indent, is, spc = " ")
|
29
49
|
indent = "#{spc * first_indent}"
|
30
50
|
is.flatten.compact.map do |i|
|
@@ -41,16 +61,26 @@ module Divine
|
|
41
61
|
end.compact.join("\n")
|
42
62
|
end
|
43
63
|
|
64
|
+
#
|
65
|
+
# Return new variable name
|
66
|
+
#
|
44
67
|
def get_fresh_variable_name
|
45
68
|
@vindex = (@vindex || 0xFF) + 1
|
46
69
|
return "var_#{@vindex.to_s(16)}"
|
47
70
|
end
|
48
71
|
|
72
|
+
#
|
73
|
+
# Camelize comming args
|
74
|
+
# * *Args* :
|
75
|
+
# - +*str+ -> list of arguments needed to be camelized
|
49
76
|
def camelize(*str)
|
50
77
|
ss = str.map(&:to_s).join("_").split(/_/).flatten
|
51
78
|
"#{ss.first.downcase}#{ss[1..-1].map(&:downcase).map(&:capitalize).join}"
|
52
79
|
end
|
53
80
|
|
81
|
+
#
|
82
|
+
# Return Header comments for generated files
|
83
|
+
#
|
54
84
|
def get_header_comment_text
|
55
85
|
return [
|
56
86
|
"",
|
@@ -115,6 +145,10 @@ module Divine
|
|
115
145
|
t1.get_field(field).referenced_types == t2.get_field(field).referenced_types
|
116
146
|
end
|
117
147
|
|
148
|
+
#
|
149
|
+
# Check if there is any strcut has changes
|
150
|
+
# * *Args* :
|
151
|
+
# - +*ss+ -> list of structs
|
118
152
|
def check_freezed_structs(ss)
|
119
153
|
ss.each do |s|
|
120
154
|
if s.freezed?
|
@@ -126,6 +160,10 @@ module Divine
|
|
126
160
|
end
|
127
161
|
end
|
128
162
|
|
163
|
+
#
|
164
|
+
# Generate signature for given struct
|
165
|
+
# * *Args* :
|
166
|
+
# - +*s+ -> struct object
|
129
167
|
def calculate_signature(s)
|
130
168
|
str = s.fields.map do |f|
|
131
169
|
"#{f.name}:#{f.referenced_types.inspect}"
|
@@ -135,8 +173,15 @@ module Divine
|
|
135
173
|
end
|
136
174
|
|
137
175
|
|
138
|
-
|
176
|
+
#
|
177
|
+
# Support basic methods that generate source code file(s) for target language
|
178
|
+
#
|
139
179
|
class CodeGenerator
|
180
|
+
#
|
181
|
+
# generate source code file(s)
|
182
|
+
# * *Args* :
|
183
|
+
# - +tagret+ -> target language
|
184
|
+
# - +opts+ -> Dictionary that contains generation params [file, parent_class, target_dir, ...]
|
140
185
|
def generate(target, opts)
|
141
186
|
gen = $language_generators[target.to_sym]
|
142
187
|
raise "Unknown target language: #{target}" unless gen
|
@@ -160,6 +205,11 @@ module Divine
|
|
160
205
|
end
|
161
206
|
end
|
162
207
|
|
208
|
+
#
|
209
|
+
# Create file
|
210
|
+
# * *Args* :
|
211
|
+
# - +path+ -> the path in which the file will be written
|
212
|
+
# - +content+ -> the content to be written
|
163
213
|
def writeFile(path, content)
|
164
214
|
File.open(path, 'w+') do |f|
|
165
215
|
puts "... writing #{path}"
|
@@ -0,0 +1,898 @@
|
|
1
|
+
module Divine
|
2
|
+
|
3
|
+
##
|
4
|
+
# * +C# Helper+ :
|
5
|
+
# Support base function needed to build Divine enviroment and classes corresponding to DSL structs
|
6
|
+
#
|
7
|
+
class CsharpHelperMethods < BabelHelperMethods
|
8
|
+
|
9
|
+
#
|
10
|
+
# Return the header comment
|
11
|
+
#
|
12
|
+
def get_header_comment
|
13
|
+
get_header_comment_text.map do |s|
|
14
|
+
"// #{s}"
|
15
|
+
end.join("\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Generate the base Divine Csharp Class
|
20
|
+
# that contains the main methods:
|
21
|
+
# * serialize
|
22
|
+
# * serialize Internal
|
23
|
+
# * deserialize
|
24
|
+
# * Read Methods
|
25
|
+
# * Write Methods
|
26
|
+
|
27
|
+
def csharp_base_class_template_str
|
28
|
+
<<EOS
|
29
|
+
namespace divine
|
30
|
+
{
|
31
|
+
public abstract class Divine
|
32
|
+
{
|
33
|
+
|
34
|
+
public byte[] serialize()
|
35
|
+
{
|
36
|
+
try
|
37
|
+
{
|
38
|
+
MemoryStream baos = new MemoryStream();
|
39
|
+
serializeInternal(baos);
|
40
|
+
baos.Close();
|
41
|
+
return baos.ToArray();
|
42
|
+
}
|
43
|
+
catch (System.IO.IOException ex)
|
44
|
+
{
|
45
|
+
throw ex;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
public abstract void serializeInternal(MemoryStream baos);
|
50
|
+
|
51
|
+
public abstract void deserialize(MemoryStream baos);
|
52
|
+
|
53
|
+
protected byte readInt8(MemoryStream data)
|
54
|
+
{
|
55
|
+
return (byte)(data.ReadByte() & 0xff);
|
56
|
+
}
|
57
|
+
|
58
|
+
protected ushort readInt16(MemoryStream data)
|
59
|
+
{
|
60
|
+
return (ushort)((data.ReadByte() << 8) | readInt8(data));
|
61
|
+
}
|
62
|
+
|
63
|
+
protected int readInt24(MemoryStream data)
|
64
|
+
{
|
65
|
+
return (data.ReadByte() << 16) | readInt16(data);
|
66
|
+
}
|
67
|
+
|
68
|
+
protected uint readInt32(MemoryStream data)
|
69
|
+
{
|
70
|
+
uint x = (uint)data.ReadByte() << 24;
|
71
|
+
uint y = (uint)readInt24(data);
|
72
|
+
return x | y;
|
73
|
+
}
|
74
|
+
|
75
|
+
protected int readSint32(MemoryStream data)
|
76
|
+
{
|
77
|
+
return (data.ReadByte() << 24) | readInt24(data);
|
78
|
+
}
|
79
|
+
|
80
|
+
protected long readSint64(MemoryStream data)
|
81
|
+
{
|
82
|
+
return ((long)readInt32(data) << 32) | (readInt32(data) & 0xFFFFFFFF);
|
83
|
+
}
|
84
|
+
|
85
|
+
protected long readDint63(MemoryStream data)
|
86
|
+
{
|
87
|
+
int b = this.readInt8(data);
|
88
|
+
long val = b & 0x7F;
|
89
|
+
while ((b >> 7) == 1)
|
90
|
+
{
|
91
|
+
b = this.readInt8(data);
|
92
|
+
val = val << 7;
|
93
|
+
val = val | (uint)(b & 0x7F);
|
94
|
+
}
|
95
|
+
return val;
|
96
|
+
}
|
97
|
+
|
98
|
+
protected bool readBool(MemoryStream data)
|
99
|
+
{
|
100
|
+
return readInt8(data) == 1;
|
101
|
+
}
|
102
|
+
|
103
|
+
protected String readString(MemoryStream data)
|
104
|
+
{
|
105
|
+
// Force utf8
|
106
|
+
try
|
107
|
+
{
|
108
|
+
return System.Text.Encoding.UTF8.GetString(readBytes(readInt16(data), data));
|
109
|
+
}
|
110
|
+
catch (System.IO.IOException ex)
|
111
|
+
{
|
112
|
+
throw ex;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
private byte[] readBytes(int size, MemoryStream data)
|
117
|
+
{
|
118
|
+
try
|
119
|
+
{
|
120
|
+
byte[] bs = new byte[size];
|
121
|
+
data.Read(bs, 0, size);
|
122
|
+
return bs;
|
123
|
+
}
|
124
|
+
catch (System.IO.IOException ex)
|
125
|
+
{
|
126
|
+
throw ex;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
protected byte[] readBinary(MemoryStream data)
|
131
|
+
{
|
132
|
+
try
|
133
|
+
{
|
134
|
+
long c = readInt32(data);
|
135
|
+
if (c > int.MaxValue)
|
136
|
+
{
|
137
|
+
throw new System.IndexOutOfRangeException("Binary data to big for csharp");
|
138
|
+
}
|
139
|
+
return readBytes((int)c, data);
|
140
|
+
}
|
141
|
+
catch (System.IO.IOException ex)
|
142
|
+
{
|
143
|
+
throw ex;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
protected byte[] readShortBinary(MemoryStream data)
|
148
|
+
{
|
149
|
+
try
|
150
|
+
{
|
151
|
+
return readBytes(readInt8(data), data);
|
152
|
+
}
|
153
|
+
catch (System.IO.IOException ex)
|
154
|
+
{
|
155
|
+
throw ex;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
protected String readIpNumber(MemoryStream data)
|
160
|
+
{
|
161
|
+
try
|
162
|
+
{
|
163
|
+
byte[] ips = readShortBinary(data);
|
164
|
+
if (ips.Length == 4)
|
165
|
+
{
|
166
|
+
return readIpv4Number(ips);
|
167
|
+
}
|
168
|
+
else
|
169
|
+
{
|
170
|
+
return readIpv6Number(ips);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
catch (System.IO.IOException ex)
|
174
|
+
{
|
175
|
+
throw ex;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
protected String readIpv4Number(byte[] ips)
|
180
|
+
{
|
181
|
+
String ip = "";
|
182
|
+
foreach (byte b in ips)
|
183
|
+
{
|
184
|
+
if (ip.Length > 0)
|
185
|
+
{
|
186
|
+
ip += ".";
|
187
|
+
}
|
188
|
+
ip += (b & 0xFF);
|
189
|
+
}
|
190
|
+
return ip;
|
191
|
+
}
|
192
|
+
|
193
|
+
protected String readIpv6Number(byte[] ips)
|
194
|
+
{
|
195
|
+
try
|
196
|
+
{
|
197
|
+
String ip = "";
|
198
|
+
int part1, part2;
|
199
|
+
for (int i = 0; i < ips.Length; i += 2)
|
200
|
+
{
|
201
|
+
part1 = ips[i] & 0xFF;
|
202
|
+
part2 = ips[i + 1] & 0xFF;
|
203
|
+
ip += part1 == 0 ? "" : part1.ToString("X");
|
204
|
+
ip += (part1 == 0 && part2 == 0) ? "" : (part2 < 10 && part1 != 0 ? "0" + part2.ToString("X") : part2.ToString("X"));
|
205
|
+
if (i < ips.Length - 2)
|
206
|
+
{
|
207
|
+
ip += ":";
|
208
|
+
}
|
209
|
+
}
|
210
|
+
ip = System.Text.RegularExpressions.Regex.Replace(ip, ":{3,}", "::");
|
211
|
+
return ip;
|
212
|
+
}
|
213
|
+
catch (System.IO.IOException ex)
|
214
|
+
{
|
215
|
+
throw ex;
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
protected void writeInt8(byte v, MemoryStream output)
|
220
|
+
{
|
221
|
+
if (v > 0xFF)
|
222
|
+
{ // Max 255
|
223
|
+
raiseError("Too large int8 number: " + v);
|
224
|
+
}
|
225
|
+
else if (v < 0)
|
226
|
+
{
|
227
|
+
raiseError("a negative number passed to int8 number: " + v);
|
228
|
+
}
|
229
|
+
output.WriteByte((byte) v);
|
230
|
+
}
|
231
|
+
|
232
|
+
protected void writeInt16(ushort v, MemoryStream output)
|
233
|
+
{
|
234
|
+
if (v > 0xFFFF)
|
235
|
+
{ // Max 65.535
|
236
|
+
raiseError("Too large int16 number: " + v);
|
237
|
+
}
|
238
|
+
else if (v < 0)
|
239
|
+
{
|
240
|
+
raiseError("a negative number passed to int16 number: " + v);
|
241
|
+
}
|
242
|
+
writeInt8((byte)(v >> 8 & 0xFF), output);
|
243
|
+
writeInt8((byte)(v & 0xFF), output);
|
244
|
+
}
|
245
|
+
|
246
|
+
protected void writeInt24(int v, MemoryStream output)
|
247
|
+
{
|
248
|
+
if (v > 0xFFFFFF)
|
249
|
+
{ // Max 16.777.215
|
250
|
+
raiseError("Too large int24 number: " + v);
|
251
|
+
}
|
252
|
+
else if (v < 0)
|
253
|
+
{ // In Case added to csharp declaration
|
254
|
+
raiseError("a negative number passed to int24 number: " + v);
|
255
|
+
}
|
256
|
+
writeInt8((byte)(v >> 16 & 0xFF), output);
|
257
|
+
writeInt16((ushort)(v & 0xFFFF), output);
|
258
|
+
}
|
259
|
+
|
260
|
+
protected void writeInt32(uint v, MemoryStream output)
|
261
|
+
{
|
262
|
+
if (v > 0xFFFFFFFF)
|
263
|
+
{ // Max 4.294.967.295
|
264
|
+
raiseError("Too large int32 number: " + v);
|
265
|
+
}
|
266
|
+
else if (v < 0)
|
267
|
+
{
|
268
|
+
raiseError("a negative number passed to int32 number: " + v);
|
269
|
+
}
|
270
|
+
writeInt8((byte)((v >> 24) & 0xFF), output);
|
271
|
+
writeInt24((int)(v & 0xFFFFFF), output);
|
272
|
+
}
|
273
|
+
|
274
|
+
protected void writeSint32(int v, MemoryStream output)
|
275
|
+
{
|
276
|
+
if (v > int.MaxValue)
|
277
|
+
{ // Max 2.147.483.647
|
278
|
+
raiseError("Too large sInt32 number: " + v + ", Max = " + int.MaxValue);
|
279
|
+
}
|
280
|
+
else if (v < int.MinValue)
|
281
|
+
{ // Min -2.147.483.648
|
282
|
+
raiseError("Too small sInt32 number: " + v + ", Min = " + int.MinValue);
|
283
|
+
}
|
284
|
+
writeInt8((byte)((v >> 24) & 0xFF), output);
|
285
|
+
writeInt24((int)(v & 0xFFFFFF), output);
|
286
|
+
}
|
287
|
+
|
288
|
+
protected void writeSint64(long v, MemoryStream output) {
|
289
|
+
if (v > long.MaxValue ) { // Max 9,223,372,036,854,775,807
|
290
|
+
raiseError("Too large sInt64 number: " + v + ", Max = " + long.MaxValue);
|
291
|
+
}else if(v < long.MinValue){ // Min -9,223,372,036,854,775,808
|
292
|
+
raiseError("Too small sInt64 number: " + v + ", Min = " + long.MinValue);
|
293
|
+
}
|
294
|
+
writeInt32((uint)((v >> 32) & 0xFFFFFFFF), output);
|
295
|
+
writeInt32((uint)(v & 0xFFFFFFFF), output);
|
296
|
+
}
|
297
|
+
|
298
|
+
|
299
|
+
|
300
|
+
protected void writeDint63(long v, MemoryStream output)
|
301
|
+
{
|
302
|
+
if (v > long.MaxValue)
|
303
|
+
{ // Max 9,223,372,036,854,775,807
|
304
|
+
raiseError("Too large Dynamic Int63 number: " + v + ", Max = " + long.MaxValue);
|
305
|
+
}
|
306
|
+
else if (v < long.MinValue)
|
307
|
+
{ // Min 0
|
308
|
+
raiseError("Too small Dynamic Int63 number: " + v + ", Min = " + 0);
|
309
|
+
}
|
310
|
+
char[] charArray = Convert.ToString(v, 2).ToCharArray();
|
311
|
+
Array.Reverse(charArray);
|
312
|
+
MatchCollection matches = Regex.Matches(new String(charArray), ".{1,7}");
|
313
|
+
for (int i = matches.Count - 1; i >= 0 ; i--)
|
314
|
+
{
|
315
|
+
String val = matches[i].Value;
|
316
|
+
val += new String(new char[7 - val.Length]).Replace("\\\\0", "0") + Math.Min(i, 1);
|
317
|
+
charArray = val.ToCharArray();
|
318
|
+
Array.Reverse(charArray);
|
319
|
+
String str = new String(charArray);
|
320
|
+
int t = Convert.ToInt32(str, 2);
|
321
|
+
this.writeInt8((byte)t, output);
|
322
|
+
}
|
323
|
+
|
324
|
+
}
|
325
|
+
|
326
|
+
protected void writeBool(bool v, MemoryStream output)
|
327
|
+
{
|
328
|
+
writeInt8((byte)(v ? 1 : 0), output);
|
329
|
+
}
|
330
|
+
|
331
|
+
protected void writeString(String v, MemoryStream output)
|
332
|
+
{
|
333
|
+
try
|
334
|
+
{
|
335
|
+
byte[] bs = System.Text.Encoding.UTF8.GetBytes (v);
|
336
|
+
|
337
|
+
if (bs.Length > 0xFFFF)
|
338
|
+
{
|
339
|
+
raiseError("Too large string: " + bs.Length + " bytes");
|
340
|
+
}
|
341
|
+
writeInt16((ushort)bs.Length, output);
|
342
|
+
output.Write(bs, 0, bs.Length);
|
343
|
+
}
|
344
|
+
catch (System.IO.IOException ex)
|
345
|
+
{
|
346
|
+
throw ex;
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
protected void writeBinary(byte[] v, MemoryStream output)
|
351
|
+
{
|
352
|
+
try
|
353
|
+
{
|
354
|
+
if ((uint)v.Length > 0xFFFFFFFF)
|
355
|
+
{
|
356
|
+
raiseError("Too large binary: " + v.Length + " bytes");
|
357
|
+
}
|
358
|
+
writeInt32((uint)v.Length, output);
|
359
|
+
output.Write(v, 0, v.Length);
|
360
|
+
}
|
361
|
+
catch (System.IO.IOException ex)
|
362
|
+
{
|
363
|
+
throw ex;
|
364
|
+
}
|
365
|
+
}
|
366
|
+
|
367
|
+
protected void write16Binary(int[] v, MemoryStream output)
|
368
|
+
{
|
369
|
+
try
|
370
|
+
{
|
371
|
+
if (v.Length * 2 > 0xFF)
|
372
|
+
{
|
373
|
+
raiseError("Too large 16_binary: " + (v.Length * 2) + " bytes");
|
374
|
+
}
|
375
|
+
writeInt8((byte)(v.Length * 2), output);
|
376
|
+
for (int i = 0; i < v.Length; i++)
|
377
|
+
{
|
378
|
+
this.writeInt16((ushort)v[i], output);
|
379
|
+
}
|
380
|
+
}
|
381
|
+
catch (System.IO.IOException ex)
|
382
|
+
{
|
383
|
+
throw ex;
|
384
|
+
}
|
385
|
+
}
|
386
|
+
|
387
|
+
protected void writeShortBinary(byte[] v, MemoryStream output)
|
388
|
+
{
|
389
|
+
try
|
390
|
+
{
|
391
|
+
if (v.Length > 0xFF)
|
392
|
+
{
|
393
|
+
raiseError("Too large short_binary: " + v.Length + " bytes");
|
394
|
+
}
|
395
|
+
writeInt8((byte)v.Length, output);
|
396
|
+
output.Write(v, 0, v.Length);
|
397
|
+
}
|
398
|
+
catch (System.IO.IOException ex)
|
399
|
+
{
|
400
|
+
throw ex;
|
401
|
+
}
|
402
|
+
}
|
403
|
+
|
404
|
+
protected void writeIpNumber(String v, MemoryStream output)
|
405
|
+
{
|
406
|
+
try
|
407
|
+
{
|
408
|
+
if (v.Contains(":"))
|
409
|
+
{
|
410
|
+
writeIpv6Number(v, output);
|
411
|
+
}
|
412
|
+
else
|
413
|
+
{
|
414
|
+
writeIpv4Number(v, output);
|
415
|
+
}
|
416
|
+
}
|
417
|
+
catch (System.IO.IOException ex)
|
418
|
+
{
|
419
|
+
throw ex;
|
420
|
+
}
|
421
|
+
}
|
422
|
+
|
423
|
+
protected void writeIpv4Number(String v, MemoryStream output)
|
424
|
+
{
|
425
|
+
try
|
426
|
+
{
|
427
|
+
byte[] ss = new byte[0];
|
428
|
+
if (v.Length != 0)
|
429
|
+
{
|
430
|
+
String[] bs = v.Split('.');
|
431
|
+
ss = new byte[bs.Length];
|
432
|
+
for (int i = 0; i < bs.Length; i++)
|
433
|
+
{
|
434
|
+
// TODO: check that each part is in range from 0 to 255
|
435
|
+
ss[i] = (byte)(int.Parse(bs[i]) & 0xFF);
|
436
|
+
}
|
437
|
+
}
|
438
|
+
if (ss.Length == 0 || ss.Length == 4)
|
439
|
+
{
|
440
|
+
writeShortBinary(ss, output);
|
441
|
+
}
|
442
|
+
else
|
443
|
+
{
|
444
|
+
raiseError("Unknown IP v4 number " + v); // Only IPv4 for now
|
445
|
+
}
|
446
|
+
}
|
447
|
+
catch (System.IO.IOException ex)
|
448
|
+
{
|
449
|
+
throw ex;
|
450
|
+
}
|
451
|
+
}
|
452
|
+
|
453
|
+
protected void writeIpv6Number(String v, MemoryStream output)
|
454
|
+
{
|
455
|
+
try
|
456
|
+
{
|
457
|
+
v = v.Replace(" ", "");
|
458
|
+
int[] ss = new int[0];
|
459
|
+
bool contains_ipv6_letters = Regex.IsMatch(v.Trim().ToLower(), "[0-9a-f]+");
|
460
|
+
bool contains_other_letters = Regex.IsMatch(v.Trim().ToLower(), "[^:0-9a-f]+");
|
461
|
+
bool contains_more_seprators = Regex.IsMatch(v.Trim().ToLower(), ":{3,}");
|
462
|
+
bool contains_one_shorthand = Regex.Matches(v.Trim().ToLower(), ":{2}").Count <= 1;
|
463
|
+
// make sure of v must have only one "::" and no more than two of ":".
|
464
|
+
// e.g. 1::1::1 & 1:::1:205
|
465
|
+
if (v.Trim().Length != 0 && !contains_more_seprators && contains_one_shorthand && !contains_other_letters
|
466
|
+
&& contains_ipv6_letters)
|
467
|
+
{
|
468
|
+
String[] bs = v.Split(':');
|
469
|
+
ss = new int[bs.Length];
|
470
|
+
for (int i = 0; i < bs.Length; i++)
|
471
|
+
{
|
472
|
+
String s = bs[i].Trim();
|
473
|
+
if (s.Length <= 4)
|
474
|
+
{ // to avoid such number 0125f
|
475
|
+
ss[i] = int.Parse(((s.Length == 0 ? "0" : bs[i].Trim())), System.Globalization.NumberStyles.HexNumber);
|
476
|
+
}
|
477
|
+
else
|
478
|
+
{
|
479
|
+
raiseError("Unknown IPv6 Group " + i + " which is " + s);
|
480
|
+
}
|
481
|
+
}
|
482
|
+
}
|
483
|
+
// Check for make sure of the size of the IP groups in case "::" is used
|
484
|
+
// [> 2 & < 8]or not [must == 8]
|
485
|
+
if (!contains_other_letters
|
486
|
+
&& (!v.Contains("::") && ss.Length == 0 || ss.Length == 8)
|
487
|
+
|| (v.Contains("::") && ss.Length > 2 && ss.Length < 8))
|
488
|
+
{
|
489
|
+
write16Binary(ss, output);
|
490
|
+
}
|
491
|
+
else
|
492
|
+
{
|
493
|
+
raiseError("Unknown IP v6 number " + v);
|
494
|
+
}
|
495
|
+
}
|
496
|
+
catch (System.IO.IOException ex)
|
497
|
+
{
|
498
|
+
throw ex;
|
499
|
+
}
|
500
|
+
}
|
501
|
+
|
502
|
+
protected void raiseError(String msg)
|
503
|
+
{
|
504
|
+
throw new System.InvalidOperationException("[" + GetType() + "] " + msg);
|
505
|
+
}
|
506
|
+
}
|
507
|
+
EOS
|
508
|
+
end
|
509
|
+
|
510
|
+
##
|
511
|
+
# Generate C# Class that corresponding to the struct definition
|
512
|
+
# * *Args* :
|
513
|
+
# - +sh+ -> Struct Name
|
514
|
+
|
515
|
+
def csharp_class_template(sh)
|
516
|
+
code = [
|
517
|
+
"public class #{sh.name} : Divine {",
|
518
|
+
:indent,
|
519
|
+
"",
|
520
|
+
|
521
|
+
# PROPERTIES
|
522
|
+
"public int struct_version = #{sh.latest_version};",
|
523
|
+
sh.field_names.map do |fn|
|
524
|
+
f = sh.field(fn).last
|
525
|
+
"public #{csharp_get_type_declaration(f)} #{fn} = #{csharp_get_empty_declaration(f)};"
|
526
|
+
end, "",
|
527
|
+
|
528
|
+
|
529
|
+
# SERiALIZE INTERNAL
|
530
|
+
"override",
|
531
|
+
"public void serializeInternal(MemoryStream baos) {",
|
532
|
+
:indent,
|
533
|
+
"try{",
|
534
|
+
:indent,
|
535
|
+
"writeInt8((byte)this.struct_version, baos);",
|
536
|
+
sh.structs.map do |s|
|
537
|
+
[
|
538
|
+
"if(this.struct_version == #{s.version}) {",
|
539
|
+
:indent,
|
540
|
+
s.simple_fields.map do |f|
|
541
|
+
"#{camelize("write", f.type)}(this.#{f.name}, baos);"
|
542
|
+
end,
|
543
|
+
s.complex_fields.map do |f|
|
544
|
+
[
|
545
|
+
"", "// Serialize #{f.type} '#{f.name}'",
|
546
|
+
csharp_serialize_internal("this.#{f.name}", f.referenced_types)
|
547
|
+
]
|
548
|
+
end,
|
549
|
+
"return;",
|
550
|
+
:deindent,
|
551
|
+
"}", ""
|
552
|
+
]
|
553
|
+
end, "",
|
554
|
+
"throw new System.InvalidOperationException(\"Unsupported version \" + this.struct_version + \" for type '#{sh.name}'\");",
|
555
|
+
:deindent,
|
556
|
+
"}catch (System.IO.IOException ex){",
|
557
|
+
:indent,
|
558
|
+
"throw ex;",
|
559
|
+
:deindent,
|
560
|
+
"}",
|
561
|
+
:deindent,
|
562
|
+
"}", "",
|
563
|
+
|
564
|
+
|
565
|
+
# DESERIALIZE
|
566
|
+
"override",
|
567
|
+
"public void deserialize(MemoryStream bais) {",
|
568
|
+
:indent,
|
569
|
+
"try{",
|
570
|
+
:indent,
|
571
|
+
"this.struct_version = readInt8(bais);",
|
572
|
+
sh.structs.map do |s|
|
573
|
+
[
|
574
|
+
"if(this.struct_version == #{s.version}) {",
|
575
|
+
:indent,
|
576
|
+
s.simple_fields.map do |f|
|
577
|
+
"this.#{f.name} = #{camelize("read", f.type)}(bais);"
|
578
|
+
end,
|
579
|
+
s.complex_fields.map do |f|
|
580
|
+
[
|
581
|
+
"", "// Read #{f.type} '#{f.name}'",
|
582
|
+
csharp_deserialize_internal("this.#{f.name}", f.referenced_types)
|
583
|
+
]
|
584
|
+
end,
|
585
|
+
"return;",
|
586
|
+
:deindent,
|
587
|
+
"}"
|
588
|
+
]
|
589
|
+
end, "",
|
590
|
+
"throw new System.InvalidOperationException(\"Unsupported version \" + this.struct_version + \" for type '#{sh.name}'\");",
|
591
|
+
:deindent,
|
592
|
+
"}catch (System.IO.IOException ex){",
|
593
|
+
:indent,
|
594
|
+
"throw ex;",
|
595
|
+
:deindent,
|
596
|
+
"}",
|
597
|
+
:deindent,
|
598
|
+
"}", "",
|
599
|
+
|
600
|
+
|
601
|
+
# END OF CLASS
|
602
|
+
:deindent,
|
603
|
+
"}"
|
604
|
+
]
|
605
|
+
|
606
|
+
format_src(3, 3, code)
|
607
|
+
end
|
608
|
+
|
609
|
+
##
|
610
|
+
# Generate default C# data types declaration values corresponding to each DSL types:
|
611
|
+
# * DSL Type --> Corresponding Default C# Value
|
612
|
+
# * dint63 --> 0 range -> [0 - 9,223,372,036,854,775,807]
|
613
|
+
# * 1 byte: range -> [0 - 127]
|
614
|
+
# * 2 bytes: range -> [0 - 16,383]
|
615
|
+
# * 3 bytes: range -> [0 - 2,097,151]
|
616
|
+
# * 4 bytes: range -> [0 - 268,435,455]
|
617
|
+
# * 5 bytes: range -> [0 - 34,359,738,367]
|
618
|
+
# * 6 bytes: range -> [0 - 4,398,046,511,103]
|
619
|
+
# * 7 bytes: range -> [0 - 562,949,953,421,311]
|
620
|
+
# * 8 bytes: range -> [0 - 72,057,594,037,927,935]
|
621
|
+
# * 9 bytes: range -> [0 - 9,223,372,036,854,775,807]
|
622
|
+
# * int8 --> 0 Range -> [0 - 255]
|
623
|
+
# * int16 --> 0 Range -> [0 - 65535]
|
624
|
+
# * int32 --> 0 Range -> [0 - 4.294.967.295]
|
625
|
+
# * sint32 --> 0 Range -> [-2.147.483.648 - 2.147.483.647]
|
626
|
+
# * sint64 --> 0 Range -> [-9.223.372.036.854.775.808, 9.223.372.036.854.775.807]
|
627
|
+
# * string --> ""
|
628
|
+
# * ip_number--> ""
|
629
|
+
# * binary --> new byte[0]
|
630
|
+
# * short_binary --> new byte[0]
|
631
|
+
# * list --> new List<type>()
|
632
|
+
# * map --> new Dictionary<keyType, valueType>()
|
633
|
+
|
634
|
+
def csharp_get_empty_declaration(types, is_reference_type = false)
|
635
|
+
if types.respond_to? :referenced_types
|
636
|
+
csharp_get_empty_declaration(types.referenced_types)
|
637
|
+
|
638
|
+
elsif types.respond_to?(:first) && types.size > 1
|
639
|
+
case types.first
|
640
|
+
when :list
|
641
|
+
"new #{csharp_get_type_declaration(types, true)}()"
|
642
|
+
when :map
|
643
|
+
"new #{csharp_get_type_declaration(types, true)}()"
|
644
|
+
else
|
645
|
+
raise "Missing empty declaration for #{types}"
|
646
|
+
end
|
647
|
+
|
648
|
+
elsif types.respond_to?(:first) && types.size == 1
|
649
|
+
csharp_get_empty_declaration(types.first, is_reference_type)
|
650
|
+
|
651
|
+
else
|
652
|
+
case types
|
653
|
+
when :binary, :short_binary
|
654
|
+
"new byte[0]"
|
655
|
+
when :int8, :int16, :int32, :sint32, :sint64, :dint63
|
656
|
+
"0"
|
657
|
+
when :string, :ip_number
|
658
|
+
"\"\""
|
659
|
+
else
|
660
|
+
if $all_structs[types]
|
661
|
+
types
|
662
|
+
else
|
663
|
+
raise "Unkown field type #{types}"
|
664
|
+
end
|
665
|
+
end
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
##
|
670
|
+
# Generate C# data types declaration corresponding to each DSL type
|
671
|
+
# * DSL Type --> Corresponding C# Type
|
672
|
+
# * int8 --> byte
|
673
|
+
# * int16 --> ushort
|
674
|
+
# * int32 --> uint
|
675
|
+
# * sint32 --> int
|
676
|
+
# * sint64 --> long
|
677
|
+
# * string --> string
|
678
|
+
# * ip_number--> string
|
679
|
+
# * binary --> byte[]
|
680
|
+
# * short_binary --> byte[]
|
681
|
+
# * list --> List<type>
|
682
|
+
# * map --> Dictionary<keyType, valueType>
|
683
|
+
|
684
|
+
def csharp_get_type_declaration(types, is_reference_type = false)
|
685
|
+
if types.respond_to? :referenced_types
|
686
|
+
csharp_get_type_declaration(types.referenced_types, is_reference_type)
|
687
|
+
|
688
|
+
elsif types.respond_to?(:first) && types.size > 1
|
689
|
+
case types.first
|
690
|
+
when :list
|
691
|
+
subtypes = csharp_get_type_declaration(types[1], true)
|
692
|
+
return "List<#{subtypes}>"
|
693
|
+
when :map
|
694
|
+
key_type = csharp_get_type_declaration(types[1], true)
|
695
|
+
value_type = csharp_get_type_declaration(types[2], true)
|
696
|
+
return "Dictionary<#{key_type}, #{value_type}>"
|
697
|
+
else
|
698
|
+
raise "Missing serialization for #{types}"
|
699
|
+
end
|
700
|
+
|
701
|
+
elsif types.respond_to?(:first) && types.size == 1
|
702
|
+
csharp_get_type_declaration(types.first, is_reference_type)
|
703
|
+
|
704
|
+
else
|
705
|
+
case types
|
706
|
+
when :binary, :short_binary
|
707
|
+
"byte[]"
|
708
|
+
when :int8
|
709
|
+
"byte"
|
710
|
+
when :int16
|
711
|
+
"ushort"
|
712
|
+
when :int32
|
713
|
+
"uint"
|
714
|
+
when :sint32
|
715
|
+
"int"
|
716
|
+
when :sint64, :dint63
|
717
|
+
"long"
|
718
|
+
when :string, :ip_number
|
719
|
+
"string"
|
720
|
+
else
|
721
|
+
if $all_structs[types]
|
722
|
+
types
|
723
|
+
else
|
724
|
+
raise "Unkown field type #{types}"
|
725
|
+
end
|
726
|
+
end
|
727
|
+
end
|
728
|
+
end
|
729
|
+
|
730
|
+
##
|
731
|
+
# Generate the way of serializing different DSL types
|
732
|
+
# * *Args* :
|
733
|
+
# - +var+ -> variable name
|
734
|
+
# - +types+ -> variable type
|
735
|
+
def csharp_serialize_internal(var, types)
|
736
|
+
if types.respond_to? :first
|
737
|
+
case types.first
|
738
|
+
when :list
|
739
|
+
nv = get_fresh_variable_name
|
740
|
+
idx = get_fresh_variable_name
|
741
|
+
return [
|
742
|
+
"writeInt32((uint)#{var}.Count, baos);",
|
743
|
+
"for(int #{idx}=0; #{idx}<#{var}.Count; #{idx}++) {",
|
744
|
+
:indent,
|
745
|
+
"#{csharp_get_type_declaration types[1]} #{nv} = #{var}[#{idx}];",
|
746
|
+
csharp_serialize_internal(nv, types[1]),
|
747
|
+
:deindent,
|
748
|
+
"}"
|
749
|
+
]
|
750
|
+
when :map
|
751
|
+
nv1 = get_fresh_variable_name
|
752
|
+
nv2 = get_fresh_variable_name
|
753
|
+
return [
|
754
|
+
"writeInt32((uint)#{var}.Count, baos);",
|
755
|
+
"foreach (#{csharp_get_type_declaration types[1]} #{nv1} in #{var}.Keys) {",
|
756
|
+
:indent,
|
757
|
+
"#{csharp_get_type_declaration types[2]} #{nv2} = #{var}[#{nv1}];",
|
758
|
+
csharp_serialize_internal(nv1, types[1]),
|
759
|
+
csharp_serialize_internal(nv2, types[2]),
|
760
|
+
:deindent,
|
761
|
+
"}"
|
762
|
+
]
|
763
|
+
else
|
764
|
+
raise "Missing serialization for #{var}"
|
765
|
+
end
|
766
|
+
else
|
767
|
+
if $all_structs[types]
|
768
|
+
"#{var}.serializeInternal(baos);"
|
769
|
+
|
770
|
+
elsif $available_types[types] && $available_types[types].ancestors.include?(SimpleDefinition)
|
771
|
+
"#{self.camelize "write", types}(#{var}, baos);"
|
772
|
+
|
773
|
+
else
|
774
|
+
raise "Missing code generation case #{types}"
|
775
|
+
end
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
##
|
780
|
+
# Generate the way of deserializing different DSL types
|
781
|
+
# * *Args* :
|
782
|
+
# - +var+ -> variable name
|
783
|
+
# - +types+ -> variable type
|
784
|
+
|
785
|
+
def csharp_deserialize_internal(var, types)
|
786
|
+
if types.respond_to? :first
|
787
|
+
case types.first
|
788
|
+
when :list
|
789
|
+
count = get_fresh_variable_name
|
790
|
+
nv = get_fresh_variable_name
|
791
|
+
iter = get_fresh_variable_name
|
792
|
+
return [
|
793
|
+
"#{"#{csharp_get_type_declaration(types)} " unless var.include? "this."}#{var} = #{csharp_get_empty_declaration(types)};",
|
794
|
+
"uint #{count} = this.readInt32(bais);",
|
795
|
+
"for(int #{iter}=0; #{iter}<#{count}; #{iter}++) {",
|
796
|
+
:indent,
|
797
|
+
csharp_deserialize_internal(nv, types[1]),
|
798
|
+
"#{var}.Add(#{nv});",
|
799
|
+
:deindent,
|
800
|
+
"}"
|
801
|
+
]
|
802
|
+
when :map
|
803
|
+
count = get_fresh_variable_name
|
804
|
+
nv1 = get_fresh_variable_name
|
805
|
+
nv2 = get_fresh_variable_name
|
806
|
+
iter = get_fresh_variable_name
|
807
|
+
return ["#{"#{csharp_get_type_declaration(types)} " unless var.include? "this."}#{var} = #{csharp_get_empty_declaration(types)};",
|
808
|
+
"uint #{count} = readInt32(bais);",
|
809
|
+
"for(int #{iter}=0; #{iter}<#{count}; #{iter}++) {",
|
810
|
+
:indent,
|
811
|
+
csharp_deserialize_internal(nv1, types[1]),
|
812
|
+
csharp_deserialize_internal(nv2, types[2]),
|
813
|
+
"#{var}.Add(#{nv1}, #{nv2});",
|
814
|
+
:deindent,
|
815
|
+
"}"
|
816
|
+
]
|
817
|
+
else
|
818
|
+
raise "Missing serialization for #{var}"
|
819
|
+
end
|
820
|
+
else
|
821
|
+
# case types
|
822
|
+
# when :map
|
823
|
+
# "#{var} = #{csharp_get_empty_declaration(types)}"
|
824
|
+
# when :list
|
825
|
+
# "#{var} = #{csharp_get_empty_declaration(types)}"
|
826
|
+
# else
|
827
|
+
if $all_structs.key? types
|
828
|
+
[
|
829
|
+
"#{types} #{var} = new #{types}();",
|
830
|
+
"#{var}.deserialize(bais);"
|
831
|
+
]
|
832
|
+
else
|
833
|
+
"#{"#{csharp_get_type_declaration(types)} " unless var.include? "this."}#{var} = #{self.camelize("read", types)}(bais);"
|
834
|
+
end
|
835
|
+
# end
|
836
|
+
end
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
##
|
841
|
+
# Responsible for generating Divine and structs classes
|
842
|
+
#
|
843
|
+
class CsharpGenerator < CsharpHelperMethods
|
844
|
+
|
845
|
+
##
|
846
|
+
# Generate csharp class(es)
|
847
|
+
# * *Args* :
|
848
|
+
# - +structs+ -> Dictionary of structs
|
849
|
+
# - +opts+ -> Dictionary that contains generation params [file, debug, parent_class, target_dir]
|
850
|
+
|
851
|
+
def generate_code(structs, opts)
|
852
|
+
$debug_csharp = true if opts[:debug]
|
853
|
+
base_template = Erubis::Eruby.new(csharp_base_class_template_str)
|
854
|
+
keys = structs.keys.sort
|
855
|
+
src = keys.map do |k|
|
856
|
+
ss = structs[k]
|
857
|
+
# Check different aspects the the structs
|
858
|
+
vss = sanity_check(ss)
|
859
|
+
csharp_class_template(StructHandler.new(vss))
|
860
|
+
end
|
861
|
+
|
862
|
+
# User defined super class?
|
863
|
+
toplevel = opts[:parent_class] || nil
|
864
|
+
toplevel = " : #{toplevel}" if toplevel
|
865
|
+
|
866
|
+
return [{
|
867
|
+
file: opts[:file],
|
868
|
+
src: "#{csharp_get_begin_module(opts)}#{base_template.result({ toplevel_class: toplevel })}\n\n#{src.join("\n\n")} }"
|
869
|
+
}]
|
870
|
+
end
|
871
|
+
|
872
|
+
##
|
873
|
+
# Build header comments and list of imports
|
874
|
+
|
875
|
+
def csharp_get_begin_module(opts)
|
876
|
+
str = "#{get_header_comment}\n\n"
|
877
|
+
str << get_csharp_imports
|
878
|
+
str << "\n\n"
|
879
|
+
return str
|
880
|
+
end
|
881
|
+
|
882
|
+
##
|
883
|
+
# Generate list of imports needed in generated C# classes
|
884
|
+
#
|
885
|
+
def get_csharp_imports
|
886
|
+
[
|
887
|
+
"System",
|
888
|
+
"System.Collections.Generic",
|
889
|
+
"System.Text.RegularExpressions",
|
890
|
+
"System.IO"
|
891
|
+
].map do |i|
|
892
|
+
"using #{i};"
|
893
|
+
end.join("\n")
|
894
|
+
end
|
895
|
+
end
|
896
|
+
|
897
|
+
$language_generators[:csharp] = CsharpGenerator.new
|
898
|
+
end
|