divine 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|