gogyou 0.1.240911.prototype → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/{LICENSE.txt → LICENSE.markdown} +35 -39
- data/README.markdown +429 -0
- data/Rakefile +106 -0
- data/gemstub.rb +40 -0
- data/lib/gogyou.rb +264 -593
- data/lib/gogyou/accessor.rb +397 -0
- data/lib/gogyou/mixin.rb +641 -0
- data/lib/gogyou/model.rb +504 -0
- data/lib/gogyou/primitives.rb +317 -0
- data/lib/gogyou/typespec.rb +15 -0
- data/mkprims.rb +172 -0
- data/spec/gogyou_spec.rb +160 -0
- metadata +65 -34
- data/README.txt +0 -3
data/Rakefile
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
require "rake/clean"
|
3
|
+
|
4
|
+
DOC = FileList["{README,LICENSE,CHANGELOG,Changelog}{,.ja}{,.txt,.rd,.rdoc,.md,.markdown}"] +
|
5
|
+
FileList["ext/**/{README,LICENSE,CHANGELOG,Changelog}{,.ja}{,.txt,.rd,.rdoc,.md,.markdown}"]
|
6
|
+
#EXT = FileList["ext/**/*.{h,hh,c,cc,cpp,cxx}"] +
|
7
|
+
# FileList["ext/externals/**/*"]
|
8
|
+
EXT = FileList["ext/**/*"]
|
9
|
+
BIN = FileList["bin/*"]
|
10
|
+
LIB = FileList["lib/**/*.rb"]
|
11
|
+
SPEC = FileList["spec/**/*"]
|
12
|
+
EXAMPLE = FileList["examples/**/*"]
|
13
|
+
RAKEFILE = [File.basename(__FILE__), "gemstub.rb"]
|
14
|
+
EXTRA = []
|
15
|
+
|
16
|
+
load "gemstub.rb"
|
17
|
+
|
18
|
+
EXTCONF = FileList["ext/extconf.rb"]
|
19
|
+
EXTCONF.reject! { |n| !File.file?(n) }
|
20
|
+
GEMSTUB.extensions += EXTCONF
|
21
|
+
GEMSTUB.executables += FileList["bin/*"].map { |n| File.basename n }
|
22
|
+
|
23
|
+
GEMFILE = "#{GEMSTUB.name}-#{GEMSTUB.version}.gem"
|
24
|
+
GEMSPEC = "#{GEMSTUB.name}.gemspec"
|
25
|
+
|
26
|
+
GEMSTUB.files += DOC + EXT + EXTCONF + BIN + LIB + SPEC + EXAMPLE + RAKEFILE + EXTRA
|
27
|
+
GEMSTUB.rdoc_options ||= %w(--charset UTF-8)
|
28
|
+
GEMSTUB.extra_rdoc_files += DOC + LIB + EXT.reject { |n| n.include?("/externals/") || !%w(.h .hh .c .cc .cpp .cxx).include?(File.extname(n)) }
|
29
|
+
|
30
|
+
CLEAN << GEMSPEC
|
31
|
+
CLOBBER << GEMFILE
|
32
|
+
|
33
|
+
task :default => :all
|
34
|
+
|
35
|
+
task :all => GEMFILE
|
36
|
+
|
37
|
+
task :rdoc => DOC + EXT + LIB do
|
38
|
+
sh *(%w(rdoc) + GEMSTUB.rdoc_options + DOC + EXT + LIB)
|
39
|
+
end
|
40
|
+
|
41
|
+
file GEMFILE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + EXAMPLE + RAKEFILE + [GEMSPEC] do
|
42
|
+
sh "gem build #{GEMSPEC}"
|
43
|
+
end
|
44
|
+
|
45
|
+
file GEMSPEC => RAKEFILE do
|
46
|
+
File.write(GEMSPEC, GEMSTUB.to_ruby, mode: "wb")
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
RUBYSET ||= nil
|
51
|
+
|
52
|
+
if RUBYSET && !RUBYSET.empty? && !EXTCONF.empty?
|
53
|
+
RUBY_VERSIONS = RUBYSET.map do |ruby|
|
54
|
+
ver = `#{ruby} --disable gem -rrbconfig -e "puts RbConfig::CONFIG['ruby_version']"`.chomp
|
55
|
+
raise "failed ruby checking - ``#{ruby}''" unless $?.success?
|
56
|
+
[ver, ruby]
|
57
|
+
end
|
58
|
+
SOFILES_SET = RUBY_VERSIONS.map { |(ver, ruby)| ["lib/#{ver}/#{GEMSTUB.name}.so", ruby] }
|
59
|
+
SOFILES = SOFILES_SET.map { |(lib, ruby)| lib }
|
60
|
+
platforms = RUBYSET.map { |ruby| `#{ruby} -rubygems -e "puts Gem::Platform.local.to_s"`.chomp }
|
61
|
+
platforms.uniq!
|
62
|
+
platforms.compact!
|
63
|
+
unless platforms.size == 1
|
64
|
+
raise "wrong platforms (#{RUBYSET.inspect} => #{platforms.inspect})"
|
65
|
+
end
|
66
|
+
|
67
|
+
GEMSTUB_NATIVE = GEMSTUB.dup
|
68
|
+
GEMSTUB_NATIVE.files += SOFILES
|
69
|
+
GEMSTUB_NATIVE.platform = platforms[0]
|
70
|
+
GEMFILE_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.version}-#{GEMSTUB_NATIVE.platform}.gem"
|
71
|
+
GEMSPEC_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.platform}.gemspec"
|
72
|
+
|
73
|
+
task :all => [GEMFILE, :native]
|
74
|
+
|
75
|
+
task :native => GEMFILE_NATIVE
|
76
|
+
|
77
|
+
file GEMFILE_NATIVE => DOC + EXT + [EXTCONF] + BIN + LIB + SPEC + EXAMPLE + SOFILES + RAKEFILE + [GEMSPEC_NATIVE] do
|
78
|
+
sh "gem build #{GEMSPEC_NATIVE}"
|
79
|
+
end
|
80
|
+
|
81
|
+
file GEMSPEC_NATIVE => __FILE__ do
|
82
|
+
File.write(GEMSPEC_NATIVE, GEMSTUB_NATIVE.to_ruby, mode: "wb")
|
83
|
+
end
|
84
|
+
|
85
|
+
SOFILES_SET.each do |(soname, ruby)|
|
86
|
+
sodir = File.dirname(soname)
|
87
|
+
makefile = File.join(sodir, "Makefile")
|
88
|
+
|
89
|
+
CLEAN << GEMSPEC_NATIVE << sodir
|
90
|
+
CLOBBER << GEMFILE_NATIVE
|
91
|
+
|
92
|
+
directory sodir
|
93
|
+
|
94
|
+
file soname => [makefile] + EXT do
|
95
|
+
cd sodir do
|
96
|
+
sh "make"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
file makefile => [sodir] + [EXTCONF] do
|
101
|
+
cd sodir do
|
102
|
+
sh "#{ruby} ../../#{EXTCONF} \"--ruby=#{ruby}\""
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/gemstub.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
# "lib/gogyou/primitives.rb" がない場合は、読み込みを遅らせる。Gogyou::VERSION の参照も後回し。
|
3
|
+
hasprims = File.file?(File.join(File.dirname(__FILE__), "lib", "gogyou", "primitives.rb"))
|
4
|
+
require_relative "lib/gogyou" if hasprims
|
5
|
+
|
6
|
+
GEMSTUB = Gem::Specification.new do |s|
|
7
|
+
s.name = "gogyou"
|
8
|
+
s.version = Gogyou::VERSION if hasprims
|
9
|
+
s.summary = "binary data operation library with the C liked struct and union"
|
10
|
+
s.description = <<EOS
|
11
|
+
The gogyou is a library that provides auxiliary features of binary data operation for ruby.
|
12
|
+
|
13
|
+
The C-liked struct, union and multidimensional array definition are posible in ruby syntax.
|
14
|
+
|
15
|
+
* Usable nested struct.
|
16
|
+
* Usable nested union.
|
17
|
+
* Usable multidimensional array.
|
18
|
+
* Usable user definition types.
|
19
|
+
EOS
|
20
|
+
s.license = "2-clause BSD License"
|
21
|
+
s.author = "dearblue"
|
22
|
+
s.email = "dearblue@users.sourceforge.jp"
|
23
|
+
#s.author = "**PRIVATE**"
|
24
|
+
#s.email = "**PRIVATE**"
|
25
|
+
s.homepage = "http://sourceforge.jp/projects/rutsubo/"
|
26
|
+
|
27
|
+
s.required_ruby_version = ">= 2.0"
|
28
|
+
s.add_development_dependency "rspec", "~> 2.14"
|
29
|
+
s.add_development_dependency "rake", "~> 10.0"
|
30
|
+
end
|
31
|
+
|
32
|
+
LIB << "lib/gogyou/primitives.rb"
|
33
|
+
EXTRA << "mkprims.rb"
|
34
|
+
CLEAN << "lib/gogyou/primitives.rb"
|
35
|
+
|
36
|
+
file "lib/gogyou/primitives.rb" => "mkprims.rb" do
|
37
|
+
sh "ruby mkprims.rb"
|
38
|
+
require_relative "lib/gogyou"
|
39
|
+
GEMSTUB.version = Gogyou::VERSION
|
40
|
+
end
|
data/lib/gogyou.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#vim: set fileencoding:utf-8
|
2
2
|
|
3
3
|
# gogyou.rb
|
4
|
-
# - AUTHOR: dearblue <dearblue@sourceforge.jp>
|
4
|
+
# - AUTHOR: dearblue <dearblue@users.sourceforge.jp>
|
5
5
|
# - WEBSIZE: http://sourceforge.jp/projects/rutsubo/
|
6
6
|
# - LICENSE: same as 2-clause BSD License
|
7
7
|
|
@@ -19,612 +19,283 @@
|
|
19
19
|
# #
|
20
20
|
#++
|
21
21
|
|
22
|
-
# gogyou は ruby 向けに作成され、バイナリデータと構造体との変換を容易にするためのライブラリです。名前は春の七種の一つ『ごぎょう』からとりました。
|
23
22
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
# Sample = Gogyou.struct do
|
115
|
-
# uint8_t! :data1, 3 # 0000h に配置。幅は1。
|
116
|
-
# uint16_t! :data2, 3 # 0003h に配置。幅は2。
|
117
|
-
# uint32_t! :data3, 3 # 0009h に配置。幅は4。
|
118
|
-
# end
|
119
|
-
#
|
120
|
-
# p Sample::PACK_FORMAT # => "C3 S3 L3"
|
121
|
-
# p Sample::SIZE # => 21
|
122
|
-
#
|
123
|
-
# == 境界指定
|
124
|
-
#
|
125
|
-
# "alignment" (短縮して "align" も利用可) で、次の要素の配置が指定境界に来るようになります。ただし要素自体の境界配置が無効化さるわけではないため、そのことも含めて強制させるためには『!』を用いる必要があります。
|
126
|
-
#
|
127
|
-
# Sample = Gogyou.struct do
|
128
|
-
# uint8_t :data1 # 0000h に配置。
|
129
|
-
# alignment 16 # 穴埋め。次の要素は0010hに配置される。
|
130
|
-
# uint32_t :data2 # 0010h に配置。
|
131
|
-
# end
|
132
|
-
#
|
133
|
-
# p Sample::PACK_FORMAT # => "C x15 L"
|
134
|
-
#
|
135
|
-
# == 任意幅の穴埋め
|
136
|
-
#
|
137
|
-
# "padding" で、任意幅の穴埋めができます。
|
138
|
-
#
|
139
|
-
# Sample = Gogyou.struct do
|
140
|
-
# uint8_t :data1 # 0000h に配置。
|
141
|
-
# padding 8 # 穴埋め。次の要素は 0009h に配置される。
|
142
|
-
# uint32_t :data2 # 4バイト境界上の 000Ch に配置。
|
143
|
-
# end
|
144
|
-
#
|
145
|
-
# p Sample::PACK_FORMAT # => "C x8 x3 L"
|
146
|
-
#
|
147
|
-
# == 型の別名定義
|
148
|
-
#
|
149
|
-
# "typedef" で、C でいう型の別名が定義できます。
|
150
|
-
#
|
151
|
-
# Sample = Gogyou.struct do
|
152
|
-
# typedef :uint, :HANDLE # 以降 HANDLE を使うと uint を指定したことになる
|
153
|
-
#
|
154
|
-
# uint8_t :data1, 3
|
155
|
-
# HANDLE :data2
|
156
|
-
# end
|
157
|
-
#
|
158
|
-
# p Sample::PACK_FORMAT # => "C3 x I"
|
159
|
-
#
|
160
|
-
# 入れ子定義内でも親で定義した typedef は有効です。
|
161
|
-
#
|
162
|
-
# Sample = Gogyou.struct do
|
163
|
-
# typedef :uint, :HANDLE
|
164
|
-
#
|
165
|
-
# HANDLE :data1
|
166
|
-
# struct :dataset do
|
167
|
-
# HANDLE :data1 # この HANDLE は親スコープで typedef したものが継承されたものです。
|
168
|
-
# HANDLE :data2
|
169
|
-
# end
|
23
|
+
# gogyou は構造体や共用体、多次元配列 (もどき) を扱うためのライブラリです。
|
24
|
+
#
|
25
|
+
# 原始的な型情報は Gogyou::Primitives で定義してあり、struct や union メソッド内で利用できる型を次の表に示します:
|
26
|
+
#
|
27
|
+
# 符号あり 符号なし
|
28
|
+
# ---- ----
|
29
|
+
# 8ビット整数型 char uchar
|
30
|
+
# unsigned_char
|
31
|
+
# 16ビット整数型 short ushort
|
32
|
+
# unsigned_short
|
33
|
+
# 32ビット整数型 int uint
|
34
|
+
# unsigned_int
|
35
|
+
# 環境依存32/64ビット整数型 long ulong
|
36
|
+
# unsigned_long
|
37
|
+
# 64ビット整数型 longlong ulonglong
|
38
|
+
# long_long unsigned_long_long
|
39
|
+
# 32ビット浮動少数型 float
|
40
|
+
# 64ビット浮動少数型 double
|
41
|
+
# sizeof 表現型 ssize_t size_t
|
42
|
+
# ポインタ整数型 intptr_t uintptr_t
|
43
|
+
#
|
44
|
+
# *** ビット数環境非依存 ***
|
45
|
+
#
|
46
|
+
# バイトオーダー環境依存 バイトオーダー反転
|
47
|
+
# 符号あり 符号なし 符号あり 符号なし
|
48
|
+
# ---- ---- ---- ----
|
49
|
+
# 8ビット整数型 int8_t uint8_t // //
|
50
|
+
# 16ビット整数型 int16_t uint16_t int16_swap uint16_swap
|
51
|
+
# 24ビット整数型 int24_t uint24_t int24_swap uint24_swap
|
52
|
+
# 32ビット整数型 int32_t uint32_t int32_swap uint32_swap
|
53
|
+
# 48ビット整数型 int48_t uint48_t int48_swap uint48_swap
|
54
|
+
# 64ビット整数型 int64_t uint64_t int64_swap uint64_swap
|
55
|
+
#
|
56
|
+
# ビッグエンディアン リトルエンディアン
|
57
|
+
# 符号あり 符号なし 符号あり 符号なし
|
58
|
+
# ---- ---- ---- ----
|
59
|
+
# 16ビット整数型 int16_be uint16_be int16_le uint16_le
|
60
|
+
# 24ビット整数型 int24_be uint24_be int24_le uint24_le
|
61
|
+
# 32ビット整数型 int32_be uint32_be int32_le uint32_le
|
62
|
+
# 48ビット整数型 int48_be uint48_be int48_le uint48_le
|
63
|
+
# 64ビット整数型 int64_be uint64_be int64_le uint64_le
|
64
|
+
#
|
65
|
+
# ビッグエンディアン リトルエンディアン バイトオーダー反転
|
66
|
+
# 32ビット浮動少数型 float_be float_le float_swap
|
67
|
+
# 64ビット浮動少数型 double_be double_le double_swap
|
68
|
+
#
|
69
|
+
#
|
70
|
+
# ==== 利用者定義の型情報
|
71
|
+
#
|
72
|
+
# 型情報を利用者が定義して利用することが出来ます。
|
73
|
+
#
|
74
|
+
# 型情報オブジェクトは、次のメソッドを必要とします:
|
75
|
+
#
|
76
|
+
# * bytesize - 型のバイト数です。拡張要素を含んでいる場合は、最小となるバイト数です。
|
77
|
+
# * bytealign - 型のバイト位置境界です。uint32_t であれば、通常は 4バイトです。
|
78
|
+
# * aset(buffer, offset, value) - バッファに値を埋め込みます。
|
79
|
+
# * aref(buffer, offset) - バッファから値を取り出します。
|
80
|
+
# * extensible? - 型自身が拡張要素、または拡張要素が含まれているかの有無です。<tt>int a[0]</tt> のような可変個配列などの場合が当てはまります。
|
81
|
+
#
|
82
|
+
# 利用者定義の型情報は、struct / union / typedef メソッドの引数として与えることが出来ます。
|
83
|
+
#
|
84
|
+
#
|
85
|
+
# ==== example (ruby.h から struct RBasic と struct RString を模倣した場合)
|
86
|
+
#
|
87
|
+
# ポインタ型は実現できていないため、intptr_t で代用しています。
|
88
|
+
#
|
89
|
+
# module MyRuby
|
90
|
+
# extend Gogyou
|
91
|
+
#
|
92
|
+
# typedef :uintptr_t, :VALUE
|
93
|
+
#
|
94
|
+
# RBasic = struct {
|
95
|
+
# VALUE :flags
|
96
|
+
# VALUE :klass
|
97
|
+
# }
|
98
|
+
#
|
99
|
+
# RString = struct {
|
100
|
+
# RBasic :basic
|
101
|
+
# union -> {
|
102
|
+
# struct -> {
|
103
|
+
# long :len
|
104
|
+
# intptr_t :ptr
|
105
|
+
# union -> {
|
106
|
+
# long :capa
|
107
|
+
# VALUE :shared
|
108
|
+
# }, :aux
|
109
|
+
# }, :heap
|
110
|
+
# char :ary, RSTRING_EMBED_LEN_MAX + 1
|
111
|
+
# }, :as
|
112
|
+
# }
|
170
113
|
# end
|
171
114
|
#
|
172
|
-
# また任意のクラスを指定することで外部クラスをブロック内で定義することができるようになります。
|
173
115
|
#
|
174
|
-
#
|
175
|
-
# typedef MD5 :MD5 # 以降 MD5 で MD5 クラスが展開と格納を行う
|
116
|
+
# ==== "gogyou" の処理の分類とクラスの役割
|
176
117
|
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
# class MD5
|
183
|
-
# SIZE = 16
|
184
|
-
#
|
185
|
-
# def self.pack(obj)
|
186
|
-
# ...
|
187
|
-
# # string オブジェクトを返さなければならない
|
188
|
-
# # bytesize は SIZE と等しくなければならない
|
189
|
-
# end
|
118
|
+
# * 原始的な型情報の管理と登録
|
119
|
+
# * Primitives - 原始的な型情報
|
120
|
+
# * Model::TYPEMAP (hash) - 構造体構築時に利用できる、型名の登録
|
121
|
+
# * 型情報オブジェクト - 型の情報を保持するオブジェクト
|
190
122
|
#
|
191
|
-
#
|
192
|
-
# # str は SIZE 定数で指定した分量のバイナリ文字列
|
193
|
-
# ...
|
194
|
-
# # 展開したオブジェクトを返す
|
195
|
-
# end
|
196
|
-
# end
|
123
|
+
# Primitives 内の定数として定義されているオブジェクトや、Accessor のサブクラスなどが当てはまります。
|
197
124
|
#
|
198
|
-
#
|
125
|
+
# 利用者定義の任意のオブジェクト (クラスやモジュールも含まれる) も、利用できます。
|
199
126
|
#
|
200
|
-
#
|
127
|
+
# 利用者定義の型情報オブジェクトについては、README を参照してください。
|
128
|
+
# * 構造体構築
|
129
|
+
# * Model - 構造体・共用体の定義時にフィールド並びを管理するためのクラス
|
201
130
|
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
# -
|
205
|
-
# - 整数 (環境依存 : ビット数、エンディアン): s?size_t!?, u?intptr_t!?
|
206
|
-
# - 整数 (環境依存 : エンディアン): u?int16_t!?, u?int32_t!?, u?int64_t!?
|
207
|
-
# - 浮動少数 (環境依存 : ビット数、エンディアン): float!?, double!?
|
208
|
-
# - 浮動少数 (環境非依存): float(_be|_le)!?, double(_be|_le)!?
|
209
|
-
# - 整数 (環境非依存): u?int8(_t)?, u?int16(_be|_le)?!?, u?int32(_be|_le)?!?, u?int64(_be|_le)?!?
|
131
|
+
# 利用者が直接扱う必要はありません。
|
132
|
+
# * 構造体の実体の管理と参照・操作手段の提供
|
133
|
+
# * Accessor - 構造体・共用体・配列を定義したあとの各クラスの親クラス
|
210
134
|
#
|
211
|
-
#
|
135
|
+
# 次のインスタンスメソッドが定義されます。
|
212
136
|
#
|
213
|
-
#
|
137
|
+
# * #size - フィールドの要素数。配列の場合はその要素数。
|
138
|
+
# * #bytesize - バイトサイズを返す。可変長配列を含んでいる場合は、現在の buffer と offset から計算された最大値を返す。
|
139
|
+
# * #\<field> / #\<field>= - 構造体・共用体のフィールドへの参照・代入メソッド。配列の場合は定義されない。
|
140
|
+
# * #[] / []= - 配列の要素への参照・代入メソッド。構造体・共用体の場合は定義されない。
|
214
141
|
#
|
215
|
-
# そしてやはり pack / unpack は自力で記述した場合と比べれば重くなりますが、記述の容易さ・可読性に免じて目を瞑ってください。
|
216
|
-
|
217
142
|
module Gogyou
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
143
|
+
Gogyou = self
|
144
|
+
VERSION = Gem::Version.new("0.2")
|
145
|
+
|
146
|
+
require_relative "gogyou/typespec"
|
147
|
+
require_relative "gogyou/mixin"
|
148
|
+
require_relative "gogyou/model"
|
149
|
+
require_relative "gogyou/primitives"
|
150
|
+
require_relative "gogyou/accessor"
|
151
|
+
|
152
|
+
#
|
153
|
+
# call-seq:
|
154
|
+
# struct { ... } -> accessor class
|
155
|
+
#
|
156
|
+
# 構造体を定義します。モジュールやクラス内で <tt>extend Gogyou</tt> しない(したくない)場合に利用することが出来ます。
|
157
|
+
#
|
158
|
+
# === example
|
159
|
+
#
|
160
|
+
# class MyClass
|
161
|
+
# Type1 = Gogyou.struct {
|
162
|
+
# ...
|
163
|
+
# }
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
def self.struct(&block)
|
167
|
+
Model.struct(Model::TYPEMAP.dup, &block).create_accessor
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.union(&block)
|
171
|
+
Model.union(Model::TYPEMAP.dup, &block).create_accessor
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# call-seq:
|
176
|
+
# typeinfo(typename) -> typeinfo
|
177
|
+
# typeinfo(typeobj) -> typeinfo
|
178
|
+
#
|
179
|
+
# 型名に対する型情報子を取得します。
|
180
|
+
#
|
181
|
+
# 型情報子を渡した場合は、それをそのまま返り値とします。
|
182
|
+
#
|
183
|
+
# 型名が存在しないか、型情報子でない場合は nil を返します。
|
184
|
+
#
|
185
|
+
def self.typeinfo(type)
|
186
|
+
case type
|
187
|
+
when Symbol, String
|
188
|
+
return nil unless type =~ /\A[_A-Za-z][_0-9A-Za-z]*\Z/
|
189
|
+
Model::TYPEMAP[type.intern]
|
190
|
+
else
|
191
|
+
if Model.check_typeinfo(type)
|
192
|
+
type
|
193
|
+
else
|
194
|
+
nil
|
195
|
+
end
|
227
196
|
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
# 構造体 (もどき) を定義します。
|
201
|
+
#
|
202
|
+
# 入れ子の構造体や共用体を定義するのはもちろん、無名構造体に無名共用体、多次元配列を定義することが出来ます。
|
203
|
+
#
|
204
|
+
# <tt>extend Gogyou</tt> したモジュール・クラス内で定義された構造体(もどき)のクラスは自動的に型情報を取り込みます。
|
205
|
+
# サンプルコードの MyType3 の定義する際に使われる MyType1 と MyType2 に注目して下さい。
|
206
|
+
#
|
207
|
+
# === example
|
208
|
+
#
|
209
|
+
# class MyClass
|
210
|
+
# extend Gogyou
|
211
|
+
#
|
212
|
+
# MyType1 = struct { # struct MyType1 {
|
213
|
+
# uint32_t :a # uint32_t a;
|
214
|
+
# uint32_t :b # uint32_t b;
|
215
|
+
# uint32_t :c, 8, 4 # uint32_t c[8][4];
|
216
|
+
# } # };
|
217
|
+
#
|
218
|
+
# MyType2 = struct { # struct MyType2 {
|
219
|
+
# float :a, :b, :c, 8, 4 # float a, b, c[8][4];
|
220
|
+
# } # };
|
221
|
+
#
|
222
|
+
# MyType3 = union { # union MyType3 {
|
223
|
+
# MyType1 :a # MyType1 a;
|
224
|
+
# MyType2 :b # MyType2 b;
|
225
|
+
# } # };
|
226
|
+
# end
|
227
|
+
#
|
228
|
+
# t1 = MyClass::MyType1.new
|
229
|
+
# t2 = MyClass::MyType2.bind(String.alloc(MyClass::MyType2::BYTESIZE))
|
230
|
+
# t3 = MyClass::MyType3.bind(File.read("sample.bin", MyClass::MyType3::BYTESIZE, mode: "rb"))
|
231
|
+
#
|
232
|
+
def struct(&block)
|
233
|
+
Model.struct(update_typemap__GOGYOU__, &block).create_accessor
|
234
|
+
end
|
235
|
+
|
236
|
+
def union(&block)
|
237
|
+
Model.union(update_typemap__GOGYOU__, &block).create_accessor
|
238
|
+
end
|
239
|
+
|
240
|
+
#
|
241
|
+
# call-seq:
|
242
|
+
# typeinfo(typename) -> typeinfo
|
243
|
+
# typeinfo(typeobj) -> typeinfo
|
244
|
+
#
|
245
|
+
# 型名に対する型情報子を取得します。
|
246
|
+
#
|
247
|
+
# 型情報子を渡した場合は、それをそのまま返り値とします。
|
248
|
+
#
|
249
|
+
# 型名が存在しないか、型情報子でない場合は nil を返します。
|
250
|
+
#
|
251
|
+
def typeinfo(type)
|
252
|
+
case type
|
253
|
+
when Symbol, String
|
254
|
+
return nil unless type =~ /\A[_A-Za-z][_0-9A-Za-z]*\Z/
|
255
|
+
update_typemap__GOGYOU__[type.intern]
|
256
|
+
else
|
257
|
+
if Model.check_typeinfo(type)
|
258
|
+
type
|
259
|
+
else
|
260
|
+
nil
|
261
|
+
end
|
260
262
|
end
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
#
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
# Gogyou.struct によって生成したクラスが include によって組み込むモジュールです。
|
300
|
-
#
|
301
|
-
# 利用者定義クラスのインスタンスメソッドとして利用されます。
|
302
|
-
module Packer
|
303
|
-
def pack
|
304
|
-
self.class.pack(self)
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
module Types
|
309
|
-
SIZEOF_CHAR = [0].pack("C").bytesize
|
310
|
-
SIZEOF_SHORT = [0].pack("S").bytesize
|
311
|
-
SIZEOF_INT = [0].pack("I").bytesize
|
312
|
-
SIZEOF_LONG = [0].pack("L").bytesize
|
313
|
-
SIZEOF_LONGLONG = [0].pack("Q").bytesize
|
314
|
-
SIZEOF_SIZE_T = [nil].pack("P").bytesize
|
315
|
-
SIZEOF_FLOAT = [0].pack("F").bytesize
|
316
|
-
SIZEOF_DOUBLE = [0].pack("D").bytesize
|
317
|
-
|
318
|
-
FORMATOF_INT8_T = "c"
|
319
|
-
FORMATOF_UINT8_T = "C"
|
320
|
-
|
321
|
-
FORMATOF_INT16_T = "s"
|
322
|
-
FORMATOF_INT16_BE = FORMATOF_INT16_T + ">"
|
323
|
-
FORMATOF_INT16_LE = FORMATOF_INT16_T + "<"
|
324
|
-
FORMATOF_UINT16_T = "S"
|
325
|
-
FORMATOF_UINT16_BE = FORMATOF_UINT16_T + ">"
|
326
|
-
FORMATOF_UINT16_LE = FORMATOF_UINT16_T + "<"
|
327
|
-
|
328
|
-
case
|
329
|
-
when SIZEOF_LONG == 4
|
330
|
-
FORMATOF_INT32_T = "l"
|
331
|
-
FORMATOF_UINT32_T = "L"
|
332
|
-
when SIZEOF_INT == 4
|
333
|
-
FORMATOF_INT32_T = "i"
|
334
|
-
FORMATOF_UINT32_T = "I"
|
335
|
-
else
|
336
|
-
raise "can not be define int32_t type"
|
337
|
-
end
|
338
|
-
|
339
|
-
FORMATOF_INT32_BE = FORMATOF_INT32_T + ">"
|
340
|
-
FORMATOF_INT32_LE = FORMATOF_INT32_T + "<"
|
341
|
-
FORMATOF_UINT32_BE = FORMATOF_UINT32_T + ">"
|
342
|
-
FORMATOF_UINT32_LE = FORMATOF_UINT32_T + "<"
|
343
|
-
|
344
|
-
case
|
345
|
-
when SIZEOF_LONG == 8
|
346
|
-
FORMATOF_INT64_T = "l"
|
347
|
-
FORMATOF_UINT64_T = "L"
|
348
|
-
when SIZEOF_LONGLONG == 8
|
349
|
-
FORMATOF_INT64_T = "q"
|
350
|
-
FORMATOF_UINT64_T = "Q"
|
351
|
-
else
|
352
|
-
raise "can not be define int64_t type"
|
353
|
-
end
|
354
|
-
|
355
|
-
FORMATOF_INT64_BE = FORMATOF_INT64_T + ">"
|
356
|
-
FORMATOF_INT64_LE = FORMATOF_INT64_T + "<"
|
357
|
-
FORMATOF_UINT64_BE = FORMATOF_UINT64_T + ">"
|
358
|
-
FORMATOF_UINT64_LE = FORMATOF_UINT64_T + "<"
|
359
|
-
|
360
|
-
case
|
361
|
-
when SIZEOF_SIZE_T == 4
|
362
|
-
FORMATOF_SSIZE_T = FORMATOF_INT32_T
|
363
|
-
FORMATOF_SIZE_T = FORMATOF_UINT32_T
|
364
|
-
when SIZEOF_SIZE_T == 8
|
365
|
-
FORMATOF_SSIZE_T = FORMATOF_INT64_T
|
366
|
-
FORMATOF_SIZE_T = FORMATOF_UINT64_T
|
367
|
-
else
|
368
|
-
raise "can not be define size_t type"
|
369
|
-
end
|
370
|
-
|
371
|
-
FORMATOF_INTPTR_T = FORMATOF_SSIZE_T
|
372
|
-
FORMATOF_UINTPTR_T = FORMATOF_SIZE_T
|
373
|
-
SIZEOF_INTPTR_T = SIZEOF_UINTPTR_T = SIZEOF_SIZE_T
|
374
|
-
end
|
375
|
-
|
376
|
-
if false
|
377
|
-
Types.constants.sort.each do |e|
|
378
|
-
puts "#{e}: #{Types.const_get(e).inspect}."
|
379
|
-
end
|
380
|
-
raise "TEST BREAK!"
|
381
|
-
end
|
382
|
-
|
383
|
-
class Property < Struct.new(:name, :elementof, :offset, :pack, :unpack)
|
384
|
-
BasicStruct = superclass
|
385
|
-
end
|
386
|
-
|
387
|
-
# 構造体クラスの定義作業に使われるクラスです。
|
388
|
-
#
|
389
|
-
# Gogyou.struct に渡すブロック内において self はこのクラスのインスタンスに切り替わるため、レシーバなしのメソッド呼び出しはこのクラスのインスタンスメソッドが呼ばれることになります。
|
390
|
-
#
|
391
|
-
# もしブロック外では問題ないのにブロック内で問題が出る場合、このことが原因になることがあります。
|
392
|
-
class StructFarm < Struct.new(:packlist,
|
393
|
-
:properties,
|
394
|
-
:offset)
|
395
|
-
|
396
|
-
# Gogyou::StructFarm の派生元クラスとなる Struct インスタントクラス。
|
397
|
-
BasicStruct = superclass
|
398
|
-
|
399
|
-
include Types
|
400
|
-
|
401
|
-
def initialize
|
402
|
-
super([], [], 0)
|
403
|
-
end
|
404
|
-
|
405
|
-
def initialize_clone(obj)
|
406
|
-
self.packlist = []
|
407
|
-
self.properties = []
|
408
|
-
self.offset = 0
|
409
|
-
end
|
410
|
-
|
411
|
-
def variable?
|
412
|
-
false
|
413
|
-
end
|
414
|
-
|
415
|
-
def union(name, size = 1, &block)
|
416
|
-
raise NotImplementedError
|
417
|
-
f = UnionFarm.new
|
418
|
-
end
|
419
|
-
|
420
|
-
def struct(name, elementof = 1, &block)
|
421
|
-
f = clone
|
422
|
-
f.instance_eval(&block)
|
423
|
-
type = Gogyou.instance_eval { define_struct(f) }
|
424
|
-
|
425
|
-
name = name.to_sym
|
426
|
-
elementof = _convert_size(elementof)
|
427
|
-
elementof.times { packlist << "a#{type::SIZE}" }
|
428
|
-
properties << [name, elementof, offset, type.method(:pack), type.method(:unpack)]
|
429
|
-
self.offset += type::SIZE * elementof
|
430
|
-
type
|
431
|
-
end
|
432
|
-
|
433
|
-
def voidp(name, size = 1)
|
434
|
-
define(name, "P", 1, size, SIZEOF_SIZE_T, nil)
|
435
|
-
end
|
436
|
-
|
437
|
-
def typedef(target, aliasname)
|
438
|
-
case target
|
439
|
-
when String, Symbol
|
440
|
-
singleton_class.class_eval do
|
441
|
-
alias_method aliasname, target
|
442
|
-
alias_method :"#{aliasname}!", :"#{target}!" unless aliasname =~ /!$/ || target =~ /!$/
|
443
|
-
end
|
444
|
-
when Class
|
445
|
-
sizeof = target.const_get(:SIZE)
|
446
|
-
pack = target.method(:pack)
|
447
|
-
unpack = target.method(:unpack)
|
448
|
-
usertype(aliasname, sizeof, pack, unpack)
|
449
|
-
else
|
450
|
-
sizeof = target.size
|
451
|
-
pack = target.method(:pack)
|
452
|
-
unpack = target.method(:unpack)
|
453
|
-
usertype(aliasname, sizeof, pack, unpack)
|
454
|
-
end
|
455
|
-
self
|
456
|
-
end
|
457
|
-
|
458
|
-
# [tipename (require)]
|
459
|
-
# 型名
|
460
|
-
# [sizeof (require)]
|
461
|
-
# 1要素あたりのオクテット数
|
462
|
-
# [pack (optional)]
|
463
|
-
# 格納する場合に呼び出されるメソッド。不要であれば nil を指定可。
|
464
|
-
# [unpack (optional)]
|
465
|
-
# 展開する場合に呼び出されるメソッド。不要であれば nil を指定可。
|
466
|
-
def usertype(typename, sizeof, pack = nil, unpack = nil)
|
467
|
-
#raise(ArgumentError, "need block") unless reduce
|
468
|
-
#typename = typename.to_sym
|
469
|
-
#raise(ArgumentError, "wrong typename (#{typename})") if typename =~ /\s/m || typename !~ /^[_\w][_\w\d]*$/
|
470
|
-
define_singleton_method(typename, &->(name, size = 1) {
|
471
|
-
name = name.to_sym
|
472
|
-
size = _convert_size(size)
|
473
|
-
packlist.concat(["a#{sizeof}"] * size)
|
474
|
-
properties << [name, size, offset, pack, unpack]
|
475
|
-
self.offset += sizeof * size
|
476
|
-
self
|
477
|
-
})
|
478
|
-
self
|
479
|
-
end
|
480
|
-
|
481
|
-
def padding(size)
|
482
|
-
size = _convert_size(size)
|
483
|
-
packlist << (size > 1 ? "x#{size}" : "x")
|
484
|
-
self.offset += size
|
485
|
-
self
|
486
|
-
end
|
487
|
-
|
488
|
-
def alignment(elementof)
|
489
|
-
elementof = _convert_size(elementof)
|
490
|
-
size = (elementof - offset % elementof) % elementof
|
491
|
-
padding(size) if size > 0
|
492
|
-
self
|
493
|
-
end
|
494
|
-
|
495
|
-
alias align alignment
|
496
|
-
|
497
|
-
# call-seq:
|
498
|
-
# exclude(name, ...)
|
499
|
-
#
|
500
|
-
# 追加するメンバ変数を定義します。これで追加されたメンバ変数は pack / unpack の対象外として扱われます。
|
501
|
-
#
|
502
|
-
# インスタンス変数の代わりに定義することを想定しています。
|
503
|
-
def exclude(*names)
|
504
|
-
names.each do |n|
|
505
|
-
property = [n.to_sym, nil, nil]
|
506
|
-
properties << property
|
507
|
-
end
|
508
|
-
self
|
509
|
-
end
|
510
|
-
|
511
|
-
# メンバ変数宣言の実体。int や long などの型指定時に呼び出されます。
|
512
|
-
#
|
513
|
-
# [name] アクセッサ名 (メンバ名)
|
514
|
-
# [format] パックフォーマット (Array#pack や String#unpack を参照)
|
515
|
-
# [elementof] 要素数
|
516
|
-
# [sizeof] 1要素あたりのオクテット数
|
517
|
-
# [elements] パックフォーマットの要素数が複数要素として展開される場合は nil を指定する
|
518
|
-
# [pack] Array#pack の時に置き換える場合の前処理
|
519
|
-
# [unpack] String#unpack の時に置き換える後処理
|
520
|
-
def define(name, format, elementof, sizeof, elements = nil, packer = nil, unpacker = nil)
|
521
|
-
name = name.to_sym
|
522
|
-
elementof = _convert_size(elementof)
|
523
|
-
packlist << "#{format}#{elementof > 1 ? elementof : nil}"
|
524
|
-
property = [name, elements || elementof, offset]
|
525
|
-
property << packer << unpacker if packer || unpacker
|
526
|
-
properties << property
|
527
|
-
self.offset += sizeof * elementof
|
528
|
-
self
|
529
|
-
end
|
530
|
-
|
531
|
-
def unpack_ustring(str)
|
532
|
-
str.force_encoding(Encoding::UTF_8)
|
533
|
-
end
|
534
|
-
|
535
|
-
def pack_ustring(str)
|
536
|
-
str
|
537
|
-
end
|
538
|
-
|
539
|
-
[
|
540
|
-
# 0: type name
|
541
|
-
# 1: size of type
|
542
|
-
# 2: number of multiple elements
|
543
|
-
# 3: default number of element for pack format
|
544
|
-
# 4.0: pack format (non-suffix)
|
545
|
-
# 4.1: pack format ("_be" suffixed)
|
546
|
-
# 4.2: pack format ("_le" suffixed)
|
547
|
-
# 4.3: pack format ("_t" suffixed)
|
548
|
-
# 5: pack method (optional)
|
549
|
-
# 6: unpack method (optional)
|
550
|
-
[:binary, 1, 1, false, ["a", nil, nil, nil]],
|
551
|
-
[:ustring, 1, 1, false, ["Z", nil, nil, nil], :pack_ustring, :unpack_ustring],
|
552
|
-
[:char, SIZEOF_CHAR, nil, true, ["c", nil, nil, nil]],
|
553
|
-
[:uchar, SIZEOF_CHAR, nil, true, ["C", nil, nil, nil]],
|
554
|
-
[:short, SIZEOF_SHORT, nil, true, ["s", nil, nil, nil]],
|
555
|
-
[:ushort, SIZEOF_SHORT, nil, true, ["S", nil, nil, nil]],
|
556
|
-
[:int, SIZEOF_INT, nil, true, ["i", nil, nil, nil]],
|
557
|
-
[:uint, SIZEOF_INT, nil, true, ["I", nil, nil, nil]],
|
558
|
-
[:long, SIZEOF_LONG, nil, true, ["l", nil, nil, nil]],
|
559
|
-
[:ulong, SIZEOF_LONG, nil, true, ["L", nil, nil, nil]],
|
560
|
-
[:longlong, SIZEOF_LONGLONG, nil, true, ["q", nil, nil, nil]],
|
561
|
-
[:ulonglong, SIZEOF_LONGLONG, nil, true, ["Q", nil, nil, nil]],
|
562
|
-
[:float, SIZEOF_FLOAT, nil, true, ["F", "g", "e", nil]],
|
563
|
-
[:double, SIZEOF_DOUBLE, nil, true, ["D", "G", "E", nil]],
|
564
|
-
[:size_t, SIZEOF_SIZE_T, nil, true, [FORMATOF_SIZE_T, nil, nil, nil]],
|
565
|
-
[:ssize_t, SIZEOF_SIZE_T, nil, true, [FORMATOF_SSIZE_T, nil, nil, nil]],
|
566
|
-
[:intptr_t, SIZEOF_INTPTR_T, nil, true, [FORMATOF_INTPTR_T, nil, nil, nil]],
|
567
|
-
[:uintptr_t, SIZEOF_INTPTR_T, nil, true, [FORMATOF_UINTPTR_T, nil, nil, nil]],
|
568
|
-
[:int8, 1, nil, true, [FORMATOF_INT8_T, nil, nil, FORMATOF_INT8_T]],
|
569
|
-
[:uint8, 1, nil, true, [FORMATOF_UINT8_T, nil, nil, FORMATOF_UINT8_T]],
|
570
|
-
[:int16, 2, nil, true, [FORMATOF_INT16_BE, FORMATOF_INT16_BE, FORMATOF_INT16_LE, FORMATOF_INT16_T]],
|
571
|
-
[:uint16, 2, nil, true, [FORMATOF_UINT16_BE, FORMATOF_UINT16_BE, FORMATOF_UINT16_LE, FORMATOF_UINT16_T]],
|
572
|
-
[:int32, 4, nil, true, [FORMATOF_INT32_BE, FORMATOF_INT32_BE, FORMATOF_INT32_LE, FORMATOF_INT32_T]],
|
573
|
-
[:uint32, 4, nil, true, [FORMATOF_UINT32_BE, FORMATOF_UINT32_BE, FORMATOF_UINT32_LE, FORMATOF_UINT32_T]],
|
574
|
-
[:int64, 8, nil, true, [FORMATOF_INT64_BE, FORMATOF_INT64_BE, FORMATOF_INT64_LE, FORMATOF_INT64_T]],
|
575
|
-
[:uint64, 8, nil, true, [FORMATOF_UINT64_BE, FORMATOF_UINT64_BE, FORMATOF_UINT64_LE, FORMATOF_UINT64_T]],
|
576
|
-
].each do |name, sizeof, ismultielement, defaultelements, format, pack, unpack|
|
577
|
-
default_elementnum = defaultelements ? " = 1" : ""
|
578
|
-
["", "_be", "_le", "_t"].zip(format).each do |suffix, f|
|
579
|
-
next unless f
|
580
|
-
|
581
|
-
if pack || unpack
|
582
|
-
reduce = ""
|
583
|
-
reduce << ", " << (pack ? "method(#{pack.to_sym.inspect})" : "nil")
|
584
|
-
reduce << ", " << (unpack ? "method(#{unpack.to_sym.inspect})" : "nil")
|
585
|
-
end
|
586
|
-
|
587
|
-
class_eval(x = <<-EOS, "#{__FILE__}<#{name}#{suffix}>", __LINE__ + 1)
|
588
|
-
def #{name}#{suffix}(name, elementnum#{default_elementnum})
|
589
|
-
alignment #{sizeof}
|
590
|
-
define(name, #{f.inspect}, elementnum, #{sizeof}, #{ismultielement.inspect}#{reduce})
|
591
|
-
end
|
592
|
-
|
593
|
-
def #{name}#{suffix}!(name, elementnum#{default_elementnum})
|
594
|
-
define(name, #{f.inspect}, elementnum, #{sizeof}, #{ismultielement.inspect}#{reduce})
|
595
|
-
end
|
596
|
-
EOS
|
597
|
-
#puts x.gsub!(/\s+/m, " ").strip
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
#p instance_methods.sort - Object.methods
|
602
|
-
|
603
|
-
def _convert_size(size)
|
604
|
-
size = size.to_i
|
605
|
-
raise ArgumentError, "size is must not zero or negative" unless size > 0
|
606
|
-
size
|
607
|
-
end
|
608
|
-
end
|
609
|
-
|
610
|
-
class << self
|
611
|
-
private
|
612
|
-
def define_struct(farm)
|
613
|
-
syms = farm.properties.map { |e| e[0].to_sym }
|
614
|
-
raise(ArgumentError, "not defined struct members") if syms.empty?
|
615
|
-
type0 = ::Struct.new(*syms)
|
616
|
-
type0.class_eval do
|
617
|
-
const_set(:PACK_FORMAT, farm.packlist.join("").freeze)
|
618
|
-
const_set(:SIZE, farm.offset)
|
619
|
-
const_set(:VARIABLE, farm.variable?)
|
620
|
-
const_set(:PROPERTIES, farm.properties.freeze)
|
621
|
-
extend ModuleUnpacker
|
622
|
-
extend ModulePacker
|
623
|
-
include Packer
|
624
|
-
end
|
625
|
-
type = Class.new(type0)
|
626
|
-
type.const_set(:BasicStruct, type0)
|
627
|
-
type
|
628
|
-
end
|
263
|
+
end
|
264
|
+
|
265
|
+
#
|
266
|
+
# call-seq:
|
267
|
+
# typedef type, aliasname -> self
|
268
|
+
# typedef type, aliasname, *elements -> self
|
269
|
+
#
|
270
|
+
# [type]
|
271
|
+
# This parameter can given a symbol or an object.
|
272
|
+
#
|
273
|
+
# シンボル (または文字列) を与える場合、すでに定義されている型名である必要があります。
|
274
|
+
#
|
275
|
+
# クラスオブジェクト (またはモジュールオブジェクト) を与える場合、`.aset` と `.aref` `.bytesize` `.bytealign` メソッドを持つ必要があります。
|
276
|
+
#
|
277
|
+
# [aliasname]
|
278
|
+
# 定義する型名としてのシンボル (または文字列) を与えます。
|
279
|
+
#
|
280
|
+
# [elements]
|
281
|
+
# 配列型の要素数を与えます。要素数は複数をとることが出来、最後の要素数として `0` を与えると任意個の要素数として定義されます。
|
282
|
+
#
|
283
|
+
def typedef(type, aliasname, *elements)
|
284
|
+
Model.typedef(update_typemap__GOGYOU__, type, aliasname, *elements)
|
285
|
+
end
|
286
|
+
|
287
|
+
private
|
288
|
+
def update_typemap__GOGYOU__(force = false)
|
289
|
+
typemap = @typemap__GOGYOU__ ||= Model::TYPEMAP.dup
|
290
|
+
constants.each do |n|
|
291
|
+
obj = const_get(n)
|
292
|
+
next unless Model.check_typeinfo(obj)
|
293
|
+
if force
|
294
|
+
typemap[n] = obj
|
295
|
+
else
|
296
|
+
typemap[n] ||= obj
|
297
|
+
end
|
629
298
|
end
|
299
|
+
typemap
|
300
|
+
end
|
630
301
|
end
|