ronin-support 0.4.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (224) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +11 -0
  3. data/.github/workflows/ruby.yml +28 -0
  4. data/.ruby-version +1 -0
  5. data/.yardopts +1 -1
  6. data/ChangeLog.md +121 -33
  7. data/Gemfile +17 -18
  8. data/README.md +57 -33
  9. data/Rakefile +10 -3
  10. data/gemspec.yml +16 -7
  11. data/lib/ronin/binary.rb +21 -0
  12. data/lib/ronin/binary/hexdump.rb +20 -0
  13. data/lib/ronin/binary/hexdump/parser.rb +403 -0
  14. data/lib/ronin/binary/struct.rb +567 -0
  15. data/lib/ronin/binary/template.rb +454 -0
  16. data/lib/ronin/extensions.rb +5 -5
  17. data/lib/ronin/extensions/enumerable.rb +5 -5
  18. data/lib/ronin/extensions/file.rb +39 -33
  19. data/lib/ronin/extensions/ip_addr.rb +29 -31
  20. data/lib/ronin/extensions/kernel.rb +5 -5
  21. data/lib/ronin/extensions/meta.rb +5 -5
  22. data/lib/ronin/extensions/regexp.rb +50 -5
  23. data/lib/ronin/extensions/resolv.rb +7 -9
  24. data/lib/ronin/extensions/string.rb +10 -10
  25. data/lib/ronin/formatting.rb +5 -5
  26. data/lib/ronin/formatting/binary.rb +5 -5
  27. data/lib/ronin/formatting/digest.rb +5 -5
  28. data/lib/ronin/formatting/extensions.rb +5 -5
  29. data/lib/ronin/formatting/extensions/binary.rb +7 -5
  30. data/lib/ronin/formatting/extensions/binary/array.rb +61 -0
  31. data/lib/ronin/formatting/extensions/binary/base64.rb +106 -0
  32. data/lib/ronin/formatting/extensions/binary/file.rb +44 -11
  33. data/lib/ronin/formatting/extensions/binary/float.rb +65 -0
  34. data/lib/ronin/formatting/extensions/binary/integer.rb +66 -50
  35. data/lib/ronin/formatting/extensions/binary/string.rb +81 -205
  36. data/lib/ronin/formatting/extensions/digest.rb +5 -5
  37. data/lib/ronin/formatting/extensions/digest/file.rb +5 -5
  38. data/lib/ronin/formatting/extensions/digest/string.rb +5 -5
  39. data/lib/ronin/formatting/extensions/html.rb +5 -5
  40. data/lib/ronin/formatting/extensions/html/integer.rb +9 -13
  41. data/lib/ronin/formatting/extensions/html/string.rb +31 -39
  42. data/lib/ronin/formatting/extensions/http.rb +5 -5
  43. data/lib/ronin/formatting/extensions/http/integer.rb +6 -6
  44. data/lib/ronin/formatting/extensions/http/string.rb +7 -7
  45. data/lib/ronin/formatting/extensions/sql.rb +5 -5
  46. data/lib/ronin/formatting/extensions/sql/string.rb +22 -24
  47. data/lib/ronin/formatting/extensions/text.rb +5 -5
  48. data/lib/ronin/formatting/extensions/text/array.rb +13 -11
  49. data/lib/ronin/formatting/extensions/text/string.rb +70 -13
  50. data/lib/ronin/formatting/html.rb +5 -5
  51. data/lib/ronin/formatting/http.rb +5 -5
  52. data/lib/ronin/formatting/sql.rb +5 -5
  53. data/lib/ronin/formatting/text.rb +5 -5
  54. data/lib/ronin/fuzzing.rb +5 -5
  55. data/lib/ronin/fuzzing/extensions.rb +5 -5
  56. data/lib/ronin/fuzzing/extensions/string.rb +42 -213
  57. data/lib/ronin/fuzzing/fuzzer.rb +110 -0
  58. data/lib/ronin/fuzzing/fuzzing.rb +33 -26
  59. data/lib/ronin/fuzzing/mutator.rb +161 -0
  60. data/lib/ronin/fuzzing/repeater.rb +81 -0
  61. data/lib/ronin/fuzzing/template.rb +133 -0
  62. data/lib/ronin/mixin.rb +2 -2
  63. data/lib/ronin/network.rb +7 -5
  64. data/lib/ronin/network/dns.rb +64 -24
  65. data/lib/ronin/network/esmtp.rb +5 -5
  66. data/lib/ronin/network/extensions.rb +5 -5
  67. data/lib/ronin/network/extensions/dns.rb +5 -5
  68. data/lib/ronin/network/extensions/dns/net.rb +5 -5
  69. data/lib/ronin/network/extensions/esmtp.rb +5 -5
  70. data/lib/ronin/network/extensions/esmtp/net.rb +5 -5
  71. data/lib/ronin/network/extensions/http.rb +5 -5
  72. data/lib/ronin/network/extensions/http/net.rb +5 -5
  73. data/lib/ronin/network/extensions/http/uri/http.rb +5 -5
  74. data/lib/ronin/network/extensions/imap.rb +5 -5
  75. data/lib/ronin/network/extensions/imap/net.rb +5 -5
  76. data/lib/ronin/network/extensions/pop3.rb +5 -5
  77. data/lib/ronin/network/extensions/pop3/net.rb +5 -5
  78. data/lib/ronin/network/extensions/smtp.rb +5 -5
  79. data/lib/ronin/network/extensions/smtp/net.rb +5 -5
  80. data/lib/ronin/network/extensions/ssl.rb +5 -5
  81. data/lib/ronin/network/extensions/ssl/net.rb +5 -5
  82. data/lib/ronin/network/extensions/tcp.rb +5 -5
  83. data/lib/ronin/network/extensions/tcp/net.rb +5 -5
  84. data/lib/ronin/network/extensions/telnet.rb +5 -5
  85. data/lib/ronin/network/extensions/telnet/net.rb +5 -5
  86. data/lib/ronin/network/extensions/udp.rb +5 -5
  87. data/lib/ronin/network/extensions/udp/net.rb +5 -5
  88. data/lib/ronin/network/ftp.rb +149 -0
  89. data/lib/ronin/network/http.rb +5 -5
  90. data/lib/ronin/network/http/exceptions.rb +5 -5
  91. data/lib/ronin/network/http/exceptions/unknown_request.rb +5 -5
  92. data/lib/ronin/network/http/http.rb +65 -70
  93. data/lib/ronin/network/http/proxy.rb +5 -5
  94. data/lib/ronin/network/imap.rb +16 -15
  95. data/lib/ronin/network/mixins.rb +6 -5
  96. data/lib/ronin/network/mixins/dns.rb +5 -5
  97. data/lib/ronin/network/mixins/esmtp.rb +5 -5
  98. data/lib/ronin/network/mixins/ftp.rb +155 -0
  99. data/lib/ronin/network/mixins/http.rb +58 -587
  100. data/lib/ronin/network/mixins/imap.rb +5 -5
  101. data/lib/ronin/network/mixins/mixin.rb +5 -5
  102. data/lib/ronin/network/mixins/pop3.rb +5 -5
  103. data/lib/ronin/network/mixins/smtp.rb +5 -5
  104. data/lib/ronin/network/mixins/ssl.rb +5 -5
  105. data/lib/ronin/network/mixins/tcp.rb +43 -10
  106. data/lib/ronin/network/mixins/telnet.rb +5 -5
  107. data/lib/ronin/network/mixins/udp.rb +126 -6
  108. data/lib/ronin/network/mixins/unix.rb +279 -0
  109. data/lib/ronin/network/network.rb +5 -5
  110. data/lib/ronin/network/pop3.rb +10 -10
  111. data/lib/ronin/network/proxy.rb +578 -0
  112. data/lib/ronin/network/smtp.rb +5 -5
  113. data/lib/ronin/network/smtp/email.rb +6 -6
  114. data/lib/ronin/network/smtp/smtp.rb +12 -13
  115. data/lib/ronin/network/ssl.rb +16 -17
  116. data/lib/ronin/network/tcp.rb +7 -310
  117. data/lib/ronin/network/tcp/proxy.rb +417 -0
  118. data/lib/ronin/network/tcp/tcp.rb +452 -0
  119. data/lib/ronin/network/telnet.rb +34 -28
  120. data/lib/ronin/network/udp.rb +7 -271
  121. data/lib/ronin/network/udp/proxy.rb +191 -0
  122. data/lib/ronin/network/udp/udp.rb +452 -0
  123. data/lib/ronin/network/unix.rb +286 -0
  124. data/lib/ronin/path.rb +35 -39
  125. data/lib/ronin/spec/ui/output.rb +6 -12
  126. data/lib/ronin/support.rb +6 -5
  127. data/lib/ronin/support/inflector.rb +8 -12
  128. data/lib/ronin/support/support.rb +7 -5
  129. data/lib/ronin/support/version.rb +6 -6
  130. data/lib/ronin/templates.rb +5 -5
  131. data/lib/ronin/templates/erb.rb +5 -5
  132. data/lib/ronin/templates/template.rb +5 -5
  133. data/lib/ronin/ui/output.rb +5 -5
  134. data/lib/ronin/ui/output/helpers.rb +42 -28
  135. data/lib/ronin/ui/output/output.rb +17 -21
  136. data/lib/ronin/ui/output/terminal.rb +5 -5
  137. data/lib/ronin/ui/output/terminal/color.rb +15 -9
  138. data/lib/ronin/ui/output/terminal/raw.rb +5 -5
  139. data/lib/ronin/ui/shell.rb +8 -11
  140. data/lib/ronin/wordlist.rb +110 -30
  141. data/ronin-support.gemspec +39 -109
  142. data/spec/binary/hexdump/helpers/hexdumps.rb +13 -0
  143. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/ascii.bin +0 -0
  144. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/hexdump_decimal_shorts.txt +0 -0
  145. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/hexdump_hex_bytes.txt +0 -0
  146. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/hexdump_hex_shorts.txt +0 -0
  147. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/hexdump_octal_bytes.txt +0 -0
  148. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/hexdump_octal_shorts.txt +0 -0
  149. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/hexdump_repeated.txt +0 -0
  150. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_decimal_bytes.txt +0 -0
  151. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_decimal_ints.txt +0 -0
  152. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_decimal_quads.txt +0 -0
  153. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_decimal_shorts.txt +0 -0
  154. data/spec/binary/hexdump/helpers/hexdumps/od_doubles.txt +17 -0
  155. data/spec/binary/hexdump/helpers/hexdumps/od_floats.txt +17 -0
  156. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_hex_bytes.txt +0 -0
  157. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_hex_ints.txt +0 -0
  158. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_hex_quads.txt +0 -0
  159. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_hex_shorts.txt +0 -0
  160. data/spec/binary/hexdump/helpers/hexdumps/od_named_chars.txt +17 -0
  161. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_octal_bytes.txt +0 -0
  162. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_octal_ints.txt +0 -0
  163. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_octal_quads.txt +0 -0
  164. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_octal_shorts.txt +0 -0
  165. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/od_repeated.txt +0 -0
  166. data/spec/{formatting/binary → binary/hexdump}/helpers/hexdumps/repeated.bin +0 -0
  167. data/spec/binary/hexdump/parser_spec.rb +302 -0
  168. data/spec/binary/struct_spec.rb +496 -0
  169. data/spec/binary/template_spec.rb +416 -0
  170. data/spec/extensions/enumerable_spec.rb +4 -4
  171. data/spec/extensions/file_spec.rb +12 -14
  172. data/spec/extensions/ip_addr_spec.rb +76 -50
  173. data/spec/extensions/kernel_spec.rb +7 -7
  174. data/spec/extensions/regexp_spec.rb +119 -59
  175. data/spec/extensions/resolv_spec.rb +2 -2
  176. data/spec/extensions/string_spec.rb +31 -30
  177. data/spec/formatting/binary/array_spec.rb +26 -0
  178. data/spec/formatting/binary/base64_spec.rb +50 -0
  179. data/spec/formatting/binary/float_spec.rb +36 -0
  180. data/spec/formatting/binary/integer_spec.rb +76 -50
  181. data/spec/formatting/binary/string_spec.rb +91 -198
  182. data/spec/formatting/digest/string_spec.rb +5 -5
  183. data/spec/formatting/html/integer_spec.rb +6 -6
  184. data/spec/formatting/html/string_spec.rb +10 -10
  185. data/spec/formatting/http/integer_spec.rb +3 -3
  186. data/spec/formatting/http/string_spec.rb +5 -5
  187. data/spec/formatting/sql/string_spec.rb +21 -19
  188. data/spec/formatting/text/array_spec.rb +15 -15
  189. data/spec/formatting/text/string_spec.rb +58 -28
  190. data/spec/fuzzing/extensions/string_spec.rb +87 -0
  191. data/spec/fuzzing/fuzzer_spec.rb +109 -0
  192. data/spec/fuzzing/fuzzing_spec.rb +24 -0
  193. data/spec/fuzzing/mutator_spec.rb +112 -0
  194. data/spec/fuzzing/repeater_spec.rb +57 -0
  195. data/spec/fuzzing/template_spec.rb +54 -0
  196. data/spec/mixin_spec.rb +10 -12
  197. data/spec/network/dns_spec.rb +89 -23
  198. data/spec/network/ftp_spec.rb +81 -0
  199. data/spec/network/http/http_spec.rb +237 -144
  200. data/spec/network/http/proxy_spec.rb +37 -37
  201. data/spec/network/network_spec.rb +2 -2
  202. data/spec/network/proxy_spec.rb +121 -0
  203. data/spec/network/shared/unix_server.rb +31 -0
  204. data/spec/network/smtp/email_spec.rb +14 -14
  205. data/spec/network/ssl_spec.rb +53 -3
  206. data/spec/network/tcp/proxy_spec.rb +118 -0
  207. data/spec/network/tcp/tcp_spec.rb +316 -0
  208. data/spec/network/telnet_spec.rb +67 -0
  209. data/spec/network/udp/udp_spec.rb +298 -0
  210. data/spec/network/unix_spec.rb +182 -0
  211. data/spec/path_spec.rb +43 -18
  212. data/spec/spec_helper.rb +2 -3
  213. data/spec/support/inflector_spec.rb +4 -4
  214. data/spec/support_spec.rb +1 -1
  215. data/spec/templates/erb_spec.rb +3 -3
  216. data/spec/templates/template_spec.rb +10 -10
  217. data/spec/ui/shell_spec.rb +15 -15
  218. data/spec/wordlist_spec.rb +80 -19
  219. metadata +176 -121
  220. data/.gemtest +0 -0
  221. data/spec/formatting/binary/helpers/hexdumps.rb +0 -16
  222. data/spec/fuzzing/string_spec.rb +0 -158
  223. data/spec/network/tcp_spec.rb +0 -247
  224. data/spec/network/udp_spec.rb +0 -248
@@ -0,0 +1,567 @@
1
+ #
2
+ # Copyright (c) 2006-2021 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # This file is part of ronin-support.
5
+ #
6
+ # ronin-support is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # ronin-support is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with ronin-support. If not, see <https://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'ronin/binary/template'
21
+
22
+ require 'set'
23
+
24
+ module Ronin
25
+ module Binary
26
+ #
27
+ # Generic Binary Struct class.
28
+ #
29
+ # ## Example
30
+ #
31
+ # class Packet < Binary::Struct
32
+ #
33
+ # endian :network
34
+ #
35
+ # layout :length, :uint32,
36
+ # :data, [:uchar, 48]
37
+ #
38
+ # end
39
+ #
40
+ # pkt = Packet.new
41
+ # pkt.length = 5
42
+ # pkt.data = 'hello'
43
+ #
44
+ # buffer = pkt.pack
45
+ # # => "\x00\x00\x00\x05hello\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
46
+ #
47
+ # new_pkt = Packet.unpack(buffer)
48
+ # # => #<Packet: length: 5, data: "hello">
49
+ #
50
+ # @api public
51
+ #
52
+ class Struct
53
+
54
+ #
55
+ # Initializes the structure.
56
+ #
57
+ def initialize
58
+ # initialize the fields in order
59
+ self.class.layout.each do |name|
60
+ self[name] = self.class.default(self.class.fields[name])
61
+ end
62
+ end
63
+
64
+ #
65
+ # The fields in the structure.
66
+ #
67
+ # @return [Hash{Symbol => type, (type, length)}]
68
+ # The field names and types.
69
+ #
70
+ # @api private
71
+ #
72
+ def self.fields
73
+ @fields ||= {}
74
+ end
75
+
76
+ #
77
+ # Determines if a field exists in the structure.
78
+ #
79
+ # @param [Symbol] name
80
+ # The field name.
81
+ #
82
+ # @return [Boolean]
83
+ # Specifies that the field exists in the structure.
84
+ #
85
+ def self.field?(name)
86
+ fields.has_key?(name.to_sym)
87
+ end
88
+
89
+ #
90
+ # Unpacks data into the structure.
91
+ #
92
+ # @param [String] data
93
+ # The data to unpack.
94
+ #
95
+ # @param [Hash] options
96
+ # Unpacking options.
97
+ #
98
+ # @option options [:little, :big, :network] :endian
99
+ # The endianness to apply to the types.
100
+ #
101
+ # @return [Struct]
102
+ # The newly unpacked structure.
103
+ #
104
+ def self.unpack(data,options={})
105
+ new().unpack(data,options)
106
+ end
107
+
108
+ #
109
+ # Determines if a field exists in the structure.
110
+ #
111
+ # @param [Symbol] name
112
+ # The name of the field.
113
+ #
114
+ # @return [Boolean]
115
+ # Specifies whether the field exists.
116
+ #
117
+ def field?(name)
118
+ self.class.field?(name)
119
+ end
120
+
121
+ #
122
+ # Reads a value from the structure.
123
+ #
124
+ # @param [Symbol] name
125
+ # The field name.
126
+ #
127
+ # @return [Integer, Float, String, Struct]
128
+ # The value of the field.
129
+ #
130
+ # @raise [ArgumentError]
131
+ # The structure does not contain the field.
132
+ #
133
+ def [](name)
134
+ if field?(name) then send(name)
135
+ else raise(ArgumentError,"no such field '#{name}'")
136
+ end
137
+ end
138
+
139
+ #
140
+ # Writes a value to the structure.
141
+ #
142
+ # @param [Symbol] name
143
+ # The field name.
144
+ #
145
+ # @param [Integer, Float, String, Struct] value
146
+ # The value to write.
147
+ #
148
+ # @return [Integer, Float, String, Struct]
149
+ # The value of the field.
150
+ #
151
+ # @raise [ArgumentError]
152
+ # The structure does not contain the field.
153
+ #
154
+ def []=(name,value)
155
+ if field?(name) then send("#{name}=",value)
156
+ else raise(ArgumentError,"no such field '#{name}'")
157
+ end
158
+ end
159
+
160
+ #
161
+ # The values within the structure.
162
+ #
163
+ # @return [Array<Integer, Float, String, Struct>]
164
+ # The values of the fields.
165
+ #
166
+ def values
167
+ normalize = lambda { |value|
168
+ case value
169
+ when Struct then value.values
170
+ else value
171
+ end
172
+ }
173
+
174
+ self.class.layout.map do |name|
175
+ case (value = self[name])
176
+ when Array then value.map(&normalize)
177
+ else normalize[value]
178
+ end
179
+ end
180
+ end
181
+
182
+ #
183
+ # Clears the fields of the structure.
184
+ #
185
+ # @return [Struct]
186
+ # The cleared structure.
187
+ #
188
+ def clear
189
+ each_field do |struct,name,field|
190
+ struct[name] = self.class.default(field)
191
+ end
192
+
193
+ return self
194
+ end
195
+
196
+ #
197
+ # Packs the structure.
198
+ #
199
+ # @param [Hash] options
200
+ # Pack options.
201
+ #
202
+ # @option options [:little, :big, :network] :endian
203
+ # The endianness to apply to the types.
204
+ #
205
+ # @return [String]
206
+ # The packed structure.
207
+ #
208
+ def pack(options={})
209
+ self.class.templates[options].pack(*values.flatten)
210
+ end
211
+
212
+ #
213
+ # Unpacks data into the structure.
214
+ #
215
+ # @param [String] data
216
+ # The data to unpack.
217
+ #
218
+ # @param [Hash] options
219
+ # Unpack options.
220
+ #
221
+ # @option options [:little, :big, :network] :endian
222
+ # The endianness to apply to the types.
223
+ #
224
+ # @return [Struct]
225
+ # The unpacked structure.
226
+ #
227
+ def unpack(data,options={})
228
+ values = self.class.templates[options].unpack(data)
229
+
230
+ each_field do |struct,name,(type,length)|
231
+ struct[name] = if length
232
+ if Template::STRING_TYPES.include?(type)
233
+ # string types are combined into a single String
234
+ values.shift
235
+ else
236
+ # shift off an Array of elements
237
+ values.shift(length)
238
+ end
239
+ else
240
+ values.shift
241
+ end
242
+ end
243
+
244
+ return self
245
+ end
246
+
247
+ #
248
+ # @see #pack
249
+ #
250
+ def to_s
251
+ pack
252
+ end
253
+
254
+ #
255
+ # @see #pack
256
+ #
257
+ def to_str
258
+ pack
259
+ end
260
+
261
+ #
262
+ # Inspects the structure.
263
+ #
264
+ # @return [String]
265
+ # The inspected structure.
266
+ #
267
+ def inspect
268
+ "#<#{self.class}: " << self.class.layout.map { |name|
269
+ "#{name}: " << self[name].inspect
270
+ }.join(', ') << '>'
271
+ end
272
+
273
+ protected
274
+
275
+ #
276
+ # Typedefs.
277
+ #
278
+ # @return [Hash{Symbol => Symbol}]
279
+ # The typedef aliases.
280
+ #
281
+ # @api private
282
+ #
283
+ def self.typedefs
284
+ @@typedefs ||= {}
285
+ end
286
+
287
+ #
288
+ # Defines a typedef.
289
+ #
290
+ # @param [Symbol] type
291
+ # The original type.
292
+ #
293
+ # @param [Symbol] type_alias
294
+ # The new type.
295
+ #
296
+ def self.typedef(type,type_alias)
297
+ type = typedefs.fetch(type,type)
298
+
299
+ unless (type.kind_of?(Symbol) || type < Struct)
300
+ raise(TypeError,"#{type.inspect} is not a Symbol or #{Struct}")
301
+ end
302
+
303
+ typedefs[type_alias] = typedefs.fetch(type,type)
304
+ end
305
+
306
+ # core typedefs
307
+ typedef :ulong, :pointer
308
+ typedef :uchar, :bool
309
+
310
+ # *_t typedefs
311
+ typedef :uint8, :uint8_t
312
+ typedef :uint16, :uint16_t
313
+ typedef :uint32, :uint32_t
314
+ typedef :uint64, :uint64_t
315
+ typedef :int8, :int8_t
316
+ typedef :int16, :int16_t
317
+ typedef :int32, :int32_t
318
+ typedef :int64, :int64_t
319
+
320
+ # network endian types
321
+ typedef :uint16_be, :uint16_net
322
+ typedef :uint32_be, :uint32_net
323
+ typedef :uint64_be, :uint64_net
324
+ typedef :int16_be, :int16_net
325
+ typedef :int32_be, :int32_net
326
+ typedef :int64_be, :int64_net
327
+ typedef :ushort_be, :ushort_net
328
+ typedef :uint_be, :uint_net
329
+ typedef :ulong_be, :ulong_net
330
+ typedef :ulong_long_be, :ulong_long_net
331
+ typedef :int_be, :int_net
332
+ typedef :long_be, :long_net
333
+ typedef :long_long_be, :long_long_net
334
+
335
+ # libc typedefs
336
+ typedef :long, :blkcnt_t
337
+ typedef :pointer, :caddr_t
338
+ typedef :int, :clockid_t
339
+ typedef :int, :daddr_t
340
+ typedef :ulong, :dev_t
341
+ typedef :long, :fd_mask
342
+ typedef :ulong, :fsblkcnt_t
343
+ typedef :ulong, :fsfilcnt_t
344
+ typedef :uint32, :git_t
345
+ typedef :uint32, :id_t
346
+ typedef :ulong, :ino_t
347
+ typedef :int32, :key_t
348
+ typedef :long, :loff_t
349
+ typedef :uint32, :mode_t
350
+ typedef :ulong, :nlink_t
351
+ typedef :long, :off_t
352
+ typedef :int32, :pid_t
353
+ typedef :uint32, :pthread_key_t
354
+ typedef :int32, :pthread_once_t
355
+ typedef :ulong, :pthread_t
356
+ typedef :long, :quad_t
357
+ typedef :long, :register_t
358
+ typedef :ulong, :rlim_t
359
+ typedef :uint16, :sa_family_t
360
+ typedef :ulong, :size_t
361
+ typedef :uint32, :socklen_t
362
+ typedef :long, :suseconds_t
363
+ typedef :long, :ssize_t
364
+ typedef :long, :time_t
365
+ typedef :pointer, :timer_t
366
+ typedef :uint32, :uid_t
367
+
368
+ #
369
+ # Sets or gets the endianness of the structure.
370
+ #
371
+ # @param [:little, :big, :network, nil] type
372
+ # The new endianness.
373
+ #
374
+ # @return [:little, :big, :network, nil]
375
+ # The endianness of the structure.
376
+ #
377
+ def self.endian(type=nil)
378
+ if type then @endian = type.to_sym
379
+ else @endian
380
+ end
381
+ end
382
+
383
+ #
384
+ # The layout of the structure.
385
+ #
386
+ # @param [Array<(name, type)>] fields
387
+ # The new fields for the structure.
388
+ #
389
+ # @return [Array<Symbol>]
390
+ # The field names in order.
391
+ #
392
+ # @example
393
+ # layout :length, :uint32,
394
+ # :data, [:uchar, 256]
395
+ #
396
+ def self.layout(*fields)
397
+ unless fields.empty?
398
+ @layout = []
399
+ @fields = {}
400
+
401
+ fields.each_slice(2) do |name,(type,length)|
402
+ type = typedefs.fetch(type,type)
403
+
404
+ unless (type.kind_of?(Symbol) || type < Struct)
405
+ raise(TypeError,"#{type.inspect} is not a Symbol or #{Struct}")
406
+ end
407
+
408
+ @layout << name
409
+ @fields[name] = [type, length]
410
+
411
+ attr_accessor name
412
+ end
413
+ end
414
+
415
+ return (@layout ||= [])
416
+ end
417
+
418
+ #
419
+ # The templates for the structure.
420
+ #
421
+ # @return [Hash{Hash => Template}]
422
+ # The templates and their options.
423
+ #
424
+ # @api semipublic
425
+ #
426
+ def self.templates
427
+ @templates ||= Hash.new do |hash,options|
428
+ fields = each_field.map { |struct,name,field| field }
429
+ options = {:endian => self.endian}.merge(options)
430
+
431
+ hash[options] = template(fields,options)
432
+ end
433
+ end
434
+
435
+ #
436
+ # Creates a new template for the structure.
437
+ #
438
+ # @param [Array<type, (type, length)>] fields
439
+ # The fields of the structure.
440
+ #
441
+ # @param [Hash] options
442
+ # Template options.
443
+ #
444
+ # @return [Template]
445
+ # The new template.
446
+ #
447
+ # @api semipublic
448
+ #
449
+ def self.template(fields,options={})
450
+ Template.new(fields,options)
451
+ end
452
+
453
+ #
454
+ # Default value for a field.
455
+ #
456
+ # @param [type, (type, length)] type
457
+ # The type of the field.
458
+ #
459
+ # @return [Integer, Float, String, Struct]
460
+ # The default value for the type.
461
+ #
462
+ # @api private
463
+ #
464
+ def self.default(type)
465
+ type, length = type
466
+
467
+ if length
468
+ if Template::STRING_TYPES.include?(type)
469
+ # arrays of chars should be Strings
470
+ String.new
471
+ else
472
+ # create an array of values
473
+ Array.new(length) { |index| default(type) }
474
+ end
475
+ else
476
+ if type.kind_of?(Symbol)
477
+ if Template::INT_TYPES.include?(type) then 0
478
+ elsif Template::FLOAT_TYPES.include?(type) then 0.0
479
+ elsif Template::CHAR_TYPES.include?(type) then "\0"
480
+ elsif Template::STRING_TYPES.include?(type) then ''
481
+ end
482
+ elsif type < Struct
483
+ type.new
484
+ end
485
+ end
486
+ end
487
+
488
+ #
489
+ # Enumerates the fields of the structure, and all nested structures.
490
+ #
491
+ # @yield [struct, name, type]
492
+ # The given block will be passed each structure, field name and field
493
+ # type.
494
+ #
495
+ # @yieldparam [Struct] struct
496
+ # The structure class.
497
+ #
498
+ # @yieldparam [Symbol] name
499
+ # The name of the field.
500
+ #
501
+ # @yieldparam [type, (type, length)] type
502
+ # The type of the field.
503
+ #
504
+ # @return [Enumerator]
505
+ # If no block is given, an Enumerator will be returned.
506
+ #
507
+ # @api private
508
+ #
509
+ def self.each_field(&block)
510
+ return enum_for(__method__) unless block
511
+
512
+ layout.each do |name|
513
+ type, length = field = fields[name]
514
+
515
+ if type.kind_of?(Symbol)
516
+ yield self, name, field
517
+ elsif type < Struct
518
+ if length
519
+ length.times { type.each_field(&block) }
520
+ else
521
+ type.each_field(&block)
522
+ end
523
+ end
524
+ end
525
+ end
526
+
527
+ #
528
+ # Enumerates the fields of the structure, and all nested structure.
529
+ #
530
+ # @yield [struct, name, type]
531
+ # The given block will be passed each structure, field name and type.
532
+ #
533
+ # @yieldparam [Struct] struct
534
+ # The structure instance.
535
+ #
536
+ # @yieldparam [Symbol] name
537
+ # The name of the field.
538
+ #
539
+ # @yieldparam [type, (type, length)] type
540
+ # The type of the field.
541
+ #
542
+ # @return [Enumerator]
543
+ # If no block is given, an Enumerator will be returned.
544
+ #
545
+ # @api private
546
+ #
547
+ def each_field(&block)
548
+ return enum_for(__method__) unless block
549
+
550
+ self.class.layout.each do |name|
551
+ type, length = field = self.class.fields[name]
552
+
553
+ if type.kind_of?(Symbol)
554
+ yield self, name, field
555
+ elsif type < Struct
556
+ if length
557
+ self[name].each { |struct| struct.each_field(&block) }
558
+ else
559
+ self[name].each_field(&block)
560
+ end
561
+ end
562
+ end
563
+ end
564
+
565
+ end
566
+ end
567
+ end