ffi 1.17.0-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +456 -0
  3. data/COPYING +49 -0
  4. data/Gemfile +21 -0
  5. data/LICENSE +24 -0
  6. data/LICENSE.SPECS +22 -0
  7. data/README.md +137 -0
  8. data/Rakefile +206 -0
  9. data/ffi.gemspec +42 -0
  10. data/lib/2.5/ffi_c.bundle +0 -0
  11. data/lib/2.6/ffi_c.bundle +0 -0
  12. data/lib/2.7/ffi_c.bundle +0 -0
  13. data/lib/3.0/ffi_c.bundle +0 -0
  14. data/lib/3.1/ffi_c.bundle +0 -0
  15. data/lib/3.2/ffi_c.bundle +0 -0
  16. data/lib/3.3/ffi_c.bundle +0 -0
  17. data/lib/ffi/abstract_memory.rb +44 -0
  18. data/lib/ffi/autopointer.rb +180 -0
  19. data/lib/ffi/buffer.rb +4 -0
  20. data/lib/ffi/callback.rb +4 -0
  21. data/lib/ffi/compat.rb +43 -0
  22. data/lib/ffi/data_converter.rb +67 -0
  23. data/lib/ffi/dynamic_library.rb +118 -0
  24. data/lib/ffi/enum.rb +302 -0
  25. data/lib/ffi/errno.rb +43 -0
  26. data/lib/ffi/ffi.rb +50 -0
  27. data/lib/ffi/function.rb +71 -0
  28. data/lib/ffi/io.rb +62 -0
  29. data/lib/ffi/library.rb +576 -0
  30. data/lib/ffi/library_path.rb +109 -0
  31. data/lib/ffi/managedstruct.rb +84 -0
  32. data/lib/ffi/memorypointer.rb +1 -0
  33. data/lib/ffi/platform/aarch64-darwin/types.conf +130 -0
  34. data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
  35. data/lib/ffi/platform/aarch64-freebsd12/types.conf +181 -0
  36. data/lib/ffi/platform/aarch64-linux/types.conf +175 -0
  37. data/lib/ffi/platform/aarch64-openbsd/types.conf +134 -0
  38. data/lib/ffi/platform/aarch64-windows/types.conf +52 -0
  39. data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
  40. data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
  41. data/lib/ffi/platform/arm-linux/types.conf +132 -0
  42. data/lib/ffi/platform/hppa1.1-linux/types.conf +178 -0
  43. data/lib/ffi/platform/hppa2.0-linux/types.conf +178 -0
  44. data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
  45. data/lib/ffi/platform/i386-darwin/types.conf +100 -0
  46. data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  47. data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
  48. data/lib/ffi/platform/i386-gnu/types.conf +107 -0
  49. data/lib/ffi/platform/i386-linux/types.conf +103 -0
  50. data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  51. data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
  52. data/lib/ffi/platform/i386-solaris/types.conf +122 -0
  53. data/lib/ffi/platform/i386-windows/types.conf +52 -0
  54. data/lib/ffi/platform/ia64-linux/types.conf +104 -0
  55. data/lib/ffi/platform/loongarch64-linux/types.conf +141 -0
  56. data/lib/ffi/platform/mips-linux/types.conf +102 -0
  57. data/lib/ffi/platform/mips64-linux/types.conf +104 -0
  58. data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
  59. data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
  60. data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
  61. data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
  62. data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
  63. data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
  64. data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
  65. data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
  66. data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
  67. data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
  68. data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
  69. data/lib/ffi/platform/powerpc64le-linux/types.conf +100 -0
  70. data/lib/ffi/platform/riscv64-linux/types.conf +104 -0
  71. data/lib/ffi/platform/s390-linux/types.conf +102 -0
  72. data/lib/ffi/platform/s390x-linux/types.conf +102 -0
  73. data/lib/ffi/platform/sparc-linux/types.conf +102 -0
  74. data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
  75. data/lib/ffi/platform/sparcv9-linux/types.conf +102 -0
  76. data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
  77. data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
  78. data/lib/ffi/platform/sw_64-linux/types.conf +141 -0
  79. data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
  80. data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
  81. data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +130 -0
  82. data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
  83. data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
  84. data/lib/ffi/platform/x86_64-haiku/types.conf +117 -0
  85. data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
  86. data/lib/ffi/platform/x86_64-msys/types.conf +119 -0
  87. data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
  88. data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
  89. data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
  90. data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
  91. data/lib/ffi/platform.rb +187 -0
  92. data/lib/ffi/pointer.rb +167 -0
  93. data/lib/ffi/struct.rb +317 -0
  94. data/lib/ffi/struct_by_reference.rb +72 -0
  95. data/lib/ffi/struct_layout.rb +96 -0
  96. data/lib/ffi/struct_layout_builder.rb +227 -0
  97. data/lib/ffi/tools/const_generator.rb +232 -0
  98. data/lib/ffi/tools/generator.rb +105 -0
  99. data/lib/ffi/tools/generator_task.rb +32 -0
  100. data/lib/ffi/tools/struct_generator.rb +195 -0
  101. data/lib/ffi/tools/types_generator.rb +137 -0
  102. data/lib/ffi/types.rb +222 -0
  103. data/lib/ffi/union.rb +43 -0
  104. data/lib/ffi/variadic.rb +80 -0
  105. data/lib/ffi/version.rb +3 -0
  106. data/lib/ffi.rb +27 -0
  107. data/rakelib/ffi_gem_helper.rb +65 -0
  108. data/samples/getlogin.rb +8 -0
  109. data/samples/getpid.rb +8 -0
  110. data/samples/gettimeofday.rb +18 -0
  111. data/samples/hello.rb +8 -0
  112. data/samples/hello_ractor.rb +11 -0
  113. data/samples/inotify.rb +60 -0
  114. data/samples/pty.rb +75 -0
  115. data/samples/qsort.rb +20 -0
  116. data/samples/qsort_ractor.rb +28 -0
  117. data/sig/ffi/abstract_memory.rbs +165 -0
  118. data/sig/ffi/auto_pointer.rbs +27 -0
  119. data/sig/ffi/buffer.rbs +18 -0
  120. data/sig/ffi/data_converter.rbs +10 -0
  121. data/sig/ffi/dynamic_library.rbs +9 -0
  122. data/sig/ffi/enum.rbs +38 -0
  123. data/sig/ffi/function.rbs +39 -0
  124. data/sig/ffi/library.rbs +42 -0
  125. data/sig/ffi/native_type.rbs +86 -0
  126. data/sig/ffi/pointer.rbs +42 -0
  127. data/sig/ffi/struct.rbs +76 -0
  128. data/sig/ffi/struct_by_reference.rbs +11 -0
  129. data/sig/ffi/struct_by_value.rbs +7 -0
  130. data/sig/ffi/struct_layout.rbs +9 -0
  131. data/sig/ffi/struct_layout_builder.rbs +5 -0
  132. data/sig/ffi/type.rbs +39 -0
  133. data/sig/ffi.rbs +26 -0
  134. metadata +241 -0
@@ -0,0 +1,187 @@
1
+ #
2
+ # Copyright (C) 2008, 2009 Wayne Meissner
3
+ #
4
+ # This file is part of ruby-ffi.
5
+ #
6
+ # All rights reserved.
7
+ #
8
+ # Redistribution and use in source and binary forms, with or without
9
+ # modification, are permitted provided that the following conditions are met:
10
+ #
11
+ # * Redistributions of source code must retain the above copyright notice, this
12
+ # list of conditions and the following disclaimer.
13
+ # * Redistributions in binary form must reproduce the above copyright notice
14
+ # this list of conditions and the following disclaimer in the documentation
15
+ # and/or other materials provided with the distribution.
16
+ # * Neither the name of the Ruby FFI project nor the names of its contributors
17
+ # may be used to endorse or promote products derived from this software
18
+ # without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#
30
+
31
+ require 'rbconfig'
32
+ require_relative 'compat'
33
+
34
+ module FFI
35
+ class PlatformError < LoadError; end
36
+
37
+ # This module defines different constants and class methods to play with
38
+ # various platforms.
39
+ module Platform
40
+ OS = FFI.make_shareable(case RbConfig::CONFIG['host_os'].downcase
41
+ when /linux/
42
+ "linux"
43
+ when /darwin/
44
+ "darwin"
45
+ when /freebsd/
46
+ "freebsd"
47
+ when /netbsd/
48
+ "netbsd"
49
+ when /openbsd/
50
+ "openbsd"
51
+ when /dragonfly/
52
+ "dragonflybsd"
53
+ when /sunos|solaris/
54
+ "solaris"
55
+ when /mingw|mswin/
56
+ "windows"
57
+ else
58
+ RbConfig::CONFIG['host_os'].downcase
59
+ end)
60
+
61
+ OSVERSION = RbConfig::CONFIG['host_os'].gsub(/[^\d]/, '').to_i
62
+
63
+ CPU = FFI.make_shareable(RbConfig::CONFIG['host_cpu'])
64
+
65
+ ARCH = FFI.make_shareable(case CPU.downcase
66
+ when /amd64|x86_64|x64/
67
+ "x86_64"
68
+ when /i\d86|x86|i86pc/
69
+ "i386"
70
+ when /ppc64|powerpc64/
71
+ "powerpc64"
72
+ when /ppc|powerpc/
73
+ "powerpc"
74
+ when /sparcv9|sparc64/
75
+ "sparcv9"
76
+ when /arm64|aarch64/ # MacOS calls it "arm64", other operating systems "aarch64"
77
+ "aarch64"
78
+ when /^arm/
79
+ if OS == "darwin" # Ruby before 3.0 reports "arm" instead of "arm64" as host_cpu on darwin
80
+ "aarch64"
81
+ else
82
+ "arm"
83
+ end
84
+ else
85
+ RbConfig::CONFIG['host_cpu']
86
+ end)
87
+
88
+ private
89
+ # @param [String) os
90
+ # @return [Boolean]
91
+ # Test if current OS is +os+.
92
+ def self.is_os(os)
93
+ OS == os
94
+ end
95
+
96
+ IS_GNU = defined?(GNU_LIBC)
97
+ IS_LINUX = is_os("linux")
98
+ IS_MAC = is_os("darwin")
99
+ IS_FREEBSD = is_os("freebsd")
100
+ IS_NETBSD = is_os("netbsd")
101
+ IS_OPENBSD = is_os("openbsd")
102
+ IS_DRAGONFLYBSD = is_os("dragonfly")
103
+ IS_SOLARIS = is_os("solaris")
104
+ IS_WINDOWS = is_os("windows")
105
+ IS_BSD = IS_MAC || IS_FREEBSD || IS_NETBSD || IS_OPENBSD || IS_DRAGONFLYBSD
106
+
107
+ # Add the version for known ABI breaks
108
+ name_version = "12" if IS_FREEBSD && OSVERSION >= 12 # 64-bit inodes
109
+
110
+ NAME = FFI.make_shareable("#{ARCH}-#{OS}#{name_version}")
111
+ CONF_DIR = FFI.make_shareable(File.join(File.dirname(__FILE__), 'platform', NAME))
112
+
113
+ public
114
+
115
+ LIBPREFIX = FFI.make_shareable(case OS
116
+ when /windows|msys/
117
+ ''
118
+ when /cygwin/
119
+ 'cyg'
120
+ else
121
+ 'lib'
122
+ end)
123
+
124
+ LIBSUFFIX = FFI.make_shareable(case OS
125
+ when /darwin/
126
+ 'dylib'
127
+ when /linux|bsd|solaris/
128
+ 'so'
129
+ when /windows|cygwin|msys/
130
+ 'dll'
131
+ else
132
+ # Punt and just assume a sane unix (i.e. anything but AIX)
133
+ 'so'
134
+ end)
135
+
136
+ LIBC = FFI.make_shareable(if IS_WINDOWS
137
+ crtname = RbConfig::CONFIG["RUBY_SO_NAME"][/msvc\w+/] || 'ucrtbase'
138
+ "#{crtname}.dll"
139
+ elsif IS_GNU
140
+ GNU_LIBC
141
+ elsif OS == 'cygwin'
142
+ "cygwin1.dll"
143
+ elsif OS == 'msys'
144
+ # Not sure how msys 1.0 behaves, tested on MSYS2.
145
+ "msys-2.0.dll"
146
+ else
147
+ "#{LIBPREFIX}c.#{LIBSUFFIX}"
148
+ end)
149
+
150
+ LITTLE_ENDIAN = 1234 unless defined?(LITTLE_ENDIAN)
151
+ BIG_ENDIAN = 4321 unless defined?(BIG_ENDIAN)
152
+ unless defined?(BYTE_ORDER)
153
+ BYTE_ORDER = [0x12345678].pack("I") == [0x12345678].pack("N") ? BIG_ENDIAN : LITTLE_ENDIAN
154
+ end
155
+
156
+ # Test if current OS is a *BSD (include MAC)
157
+ # @return [Boolean]
158
+ def self.bsd?
159
+ IS_BSD
160
+ end
161
+
162
+ # Test if current OS is Windows
163
+ # @return [Boolean]
164
+ def self.windows?
165
+ IS_WINDOWS
166
+ end
167
+
168
+ # Test if current OS is Mac OS
169
+ # @return [Boolean]
170
+ def self.mac?
171
+ IS_MAC
172
+ end
173
+
174
+ # Test if current OS is Solaris (Sun OS)
175
+ # @return [Boolean]
176
+ def self.solaris?
177
+ IS_SOLARIS
178
+ end
179
+
180
+ # Test if current OS is a unix OS
181
+ # @return [Boolean]
182
+ def self.unix?
183
+ !IS_WINDOWS
184
+ end
185
+ end
186
+ end
187
+
@@ -0,0 +1,167 @@
1
+ #
2
+ # Copyright (C) 2008, 2009 Wayne Meissner
3
+ # Copyright (c) 2007, 2008 Evan Phoenix
4
+ #
5
+ # This file is part of ruby-ffi.
6
+ #
7
+ # All rights reserved.
8
+ #
9
+ # Redistribution and use in source and binary forms, with or without
10
+ # modification, are permitted provided that the following conditions are met:
11
+ #
12
+ # * Redistributions of source code must retain the above copyright notice, this
13
+ # list of conditions and the following disclaimer.
14
+ # * Redistributions in binary form must reproduce the above copyright notice
15
+ # this list of conditions and the following disclaimer in the documentation
16
+ # and/or other materials provided with the distribution.
17
+ # * Neither the name of the Ruby FFI project nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this software
19
+ # without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+
33
+ require 'ffi/platform'
34
+
35
+ # NOTE: all method definitions in this file are conditional on
36
+ # whether they are not already defined. This is needed because
37
+ # some Ruby implementations (e.g., TruffleRuby) might already
38
+ # provide these methods due to using FFI internally, and we
39
+ # should not override them to avoid warnings.
40
+
41
+ module FFI
42
+ class Pointer
43
+
44
+ # Pointer size
45
+ SIZE = Platform::ADDRESS_SIZE / 8 unless const_defined?(:SIZE)
46
+
47
+ # Return the size of a pointer on the current platform, in bytes
48
+ # @return [Integer]
49
+ def self.size
50
+ SIZE
51
+ end unless respond_to?(:size)
52
+
53
+ # @param [nil,Integer] len length of string to return
54
+ # @return [String]
55
+ # Read pointer's contents as a string, or the first +len+ bytes of the
56
+ # equivalent string if +len+ is not +nil+.
57
+ def read_string(len=nil)
58
+ if len
59
+ return ''.b if len == 0
60
+ get_bytes(0, len)
61
+ else
62
+ get_string(0)
63
+ end
64
+ end unless method_defined?(:read_string)
65
+
66
+ # @param [Integer] len length of string to return
67
+ # @return [String]
68
+ # Read the first +len+ bytes of pointer's contents as a string.
69
+ #
70
+ # Same as:
71
+ # ptr.read_string(len) # with len not nil
72
+ def read_string_length(len)
73
+ get_bytes(0, len)
74
+ end unless method_defined?(:read_string_length)
75
+
76
+ # @return [String]
77
+ # Read pointer's contents as a string.
78
+ #
79
+ # Same as:
80
+ # ptr.read_string # with no len
81
+ def read_string_to_null
82
+ get_string(0)
83
+ end unless method_defined?(:read_string_to_null)
84
+
85
+ # @param [String] str string to write
86
+ # @param [Integer] len length of string to return
87
+ # @return [self]
88
+ # Write +len+ first bytes of +str+ in pointer's contents.
89
+ #
90
+ # Same as:
91
+ # ptr.write_string(str, len) # with len not nil
92
+ def write_string_length(str, len)
93
+ put_bytes(0, str, 0, len)
94
+ end unless method_defined?(:write_string_length)
95
+
96
+ # @param [String] str string to write
97
+ # @param [Integer] len length of string to return
98
+ # @return [self]
99
+ # Write +str+ in pointer's contents, or first +len+ bytes if
100
+ # +len+ is not +nil+.
101
+ def write_string(str, len=nil)
102
+ len = str.bytesize unless len
103
+ # Write the string data without NUL termination
104
+ put_bytes(0, str, 0, len)
105
+ end unless method_defined?(:write_string)
106
+
107
+ # @param [Type] type type of data to read from pointer's contents
108
+ # @param [Symbol] reader method to send to +self+ to read +type+
109
+ # @param [Integer] length
110
+ # @return [Array]
111
+ # Read an array of +type+ of length +length+.
112
+ # @example
113
+ # ptr.read_array_of_type(TYPE_UINT8, :read_uint8, 4) # -> [1, 2, 3, 4]
114
+ def read_array_of_type(type, reader, length)
115
+ ary = []
116
+ size = FFI.type_size(type)
117
+ tmp = self
118
+ length.times { |j|
119
+ ary << tmp.send(reader)
120
+ tmp += size unless j == length-1 # avoid OOB
121
+ }
122
+ ary
123
+ end unless method_defined?(:read_array_of_type)
124
+
125
+ # @param [Type] type type of data to write to pointer's contents
126
+ # @param [Symbol] writer method to send to +self+ to write +type+
127
+ # @param [Array] ary
128
+ # @return [self]
129
+ # Write +ary+ in pointer's contents as +type+.
130
+ # @example
131
+ # ptr.write_array_of_type(TYPE_UINT8, :put_uint8, [1, 2, 3 ,4])
132
+ def write_array_of_type(type, writer, ary)
133
+ size = FFI.type_size(type)
134
+ ary.each_with_index { |val, i|
135
+ break unless i < self.size
136
+ self.send(writer, i * size, val)
137
+ }
138
+ self
139
+ end unless method_defined?(:write_array_of_type)
140
+
141
+ # @return [self]
142
+ def to_ptr
143
+ self
144
+ end unless method_defined?(:to_ptr)
145
+
146
+ # @param [Symbol,Type] type of data to read
147
+ # @return [Object]
148
+ # Read pointer's contents as +type+
149
+ #
150
+ # Same as:
151
+ # ptr.get(type, 0)
152
+ def read(type)
153
+ get(type, 0)
154
+ end unless method_defined?(:read)
155
+
156
+ # @param [Symbol,Type] type of data to read
157
+ # @param [Object] value to write
158
+ # @return [nil]
159
+ # Write +value+ of type +type+ to pointer's content
160
+ #
161
+ # Same as:
162
+ # ptr.put(type, 0)
163
+ def write(type, value)
164
+ put(type, 0, value)
165
+ end unless method_defined?(:write)
166
+ end
167
+ end
data/lib/ffi/struct.rb ADDED
@@ -0,0 +1,317 @@
1
+ #
2
+ # Copyright (C) 2008-2010 Wayne Meissner
3
+ # Copyright (C) 2008, 2009 Andrea Fazzi
4
+ # Copyright (C) 2008, 2009 Luc Heinrich
5
+ #
6
+ # This file is part of ruby-ffi.
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice, this
14
+ # list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the Ruby FFI project nor the names of its contributors
19
+ # may be used to endorse or promote products derived from this software
20
+ # without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
26
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+
34
+ require 'ffi/platform'
35
+ require 'ffi/struct_layout'
36
+ require 'ffi/struct_layout_builder'
37
+ require 'ffi/struct_by_reference'
38
+
39
+ module FFI
40
+
41
+ class Struct
42
+
43
+ # Get struct size
44
+ # @return [Integer]
45
+ def size
46
+ self.class.size
47
+ end
48
+
49
+ # @return [Integer] Struct alignment
50
+ def alignment
51
+ self.class.alignment
52
+ end
53
+ alias_method :align, :alignment
54
+
55
+ # (see FFI::StructLayout#offset_of)
56
+ def offset_of(name)
57
+ self.class.offset_of(name)
58
+ end
59
+
60
+ # (see FFI::StructLayout#members)
61
+ def members
62
+ self.class.members
63
+ end
64
+
65
+ # @return [Array]
66
+ # Get array of values from Struct fields.
67
+ def values
68
+ members.map { |m| self[m] }
69
+ end
70
+
71
+ # (see FFI::StructLayout#offsets)
72
+ def offsets
73
+ self.class.offsets
74
+ end
75
+
76
+ # Clear the struct content.
77
+ # @return [self]
78
+ def clear
79
+ pointer.clear
80
+ self
81
+ end
82
+
83
+ # Get {Pointer} to struct content.
84
+ # @return [AbstractMemory]
85
+ def to_ptr
86
+ pointer
87
+ end
88
+
89
+ # Get struct size
90
+ # @return [Integer]
91
+ def self.size
92
+ defined?(@layout) ? @layout.size : defined?(@size) ? @size : 0
93
+ end
94
+
95
+ # set struct size
96
+ # @param [Integer] size
97
+ # @return [size]
98
+ def self.size=(size)
99
+ raise ArgumentError, "Size already set" if defined?(@size) || defined?(@layout)
100
+ @size = size
101
+ end
102
+
103
+ # @return (see Struct#alignment)
104
+ def self.alignment
105
+ @layout.alignment
106
+ end
107
+
108
+ # (see FFI::Type#members)
109
+ def self.members
110
+ @layout.members
111
+ end
112
+
113
+ # (see FFI::StructLayout#offsets)
114
+ def self.offsets
115
+ @layout.offsets
116
+ end
117
+
118
+ # (see FFI::StructLayout#offset_of)
119
+ def self.offset_of(name)
120
+ @layout.offset_of(name)
121
+ end
122
+
123
+ def self.in
124
+ ptr(:in)
125
+ end
126
+
127
+ def self.out
128
+ ptr(:out)
129
+ end
130
+
131
+ def self.ptr(flags = :inout)
132
+ @ref_data_type ||= Type::Mapped.new(StructByReference.new(self))
133
+ end
134
+
135
+ def self.val
136
+ @val_data_type ||= StructByValue.new(self)
137
+ end
138
+
139
+ def self.by_value
140
+ self.val
141
+ end
142
+
143
+ def self.by_ref(flags = :inout)
144
+ self.ptr(flags)
145
+ end
146
+
147
+ class ManagedStructConverter < StructByReference
148
+
149
+ # @param [Struct] struct_class
150
+ def initialize(struct_class)
151
+ super(struct_class)
152
+
153
+ raise NoMethodError, "release() not implemented for class #{struct_class}" unless struct_class.respond_to? :release
154
+ @method = struct_class.method(:release)
155
+ end
156
+
157
+ # @param [Pointer] ptr
158
+ # @param [nil] ctx
159
+ # @return [Struct]
160
+ def from_native(ptr, ctx)
161
+ struct_class.new(AutoPointer.new(ptr, @method))
162
+ end
163
+ end
164
+
165
+ def self.auto_ptr
166
+ @managed_type ||= Type::Mapped.new(ManagedStructConverter.new(self))
167
+ end
168
+
169
+
170
+ class << self
171
+ public
172
+
173
+ # @return [StructLayout]
174
+ # @overload layout
175
+ # @return [StructLayout]
176
+ # Get struct layout.
177
+ # @overload layout(*spec)
178
+ # @param [Array<Symbol, Integer>,Array(Hash)] spec
179
+ # @return [StructLayout]
180
+ # Create struct layout from +spec+.
181
+ # @example Creating a layout from an array +spec+
182
+ # class MyStruct < Struct
183
+ # layout :field1, :int,
184
+ # :field2, :pointer,
185
+ # :field3, :string
186
+ # end
187
+ # @example Creating a layout from an array +spec+ with offset
188
+ # class MyStructWithOffset < Struct
189
+ # layout :field1, :int,
190
+ # :field2, :pointer, 6, # set offset to 6 for this field
191
+ # :field3, :string
192
+ # end
193
+ # @example Creating a layout from a hash +spec+
194
+ # class MyStructFromHash < Struct
195
+ # layout :field1 => :int,
196
+ # :field2 => :pointer,
197
+ # :field3 => :string
198
+ # end
199
+ # @example Creating a layout with pointers to functions
200
+ # class MyFunctionTable < Struct
201
+ # layout :function1, callback([:int, :int], :int),
202
+ # :function2, callback([:pointer], :void),
203
+ # :field3, :string
204
+ # end
205
+ def layout(*spec)
206
+ return @layout if spec.size == 0
207
+
208
+ warn "[DEPRECATION] Struct layout is already defined for class #{self.inspect}. Redefinition as in #{caller[0]} will be disallowed in ffi-2.0." if defined?(@layout)
209
+
210
+ builder = StructLayoutBuilder.new
211
+ builder.union = self < Union
212
+ builder.packed = @packed if defined?(@packed)
213
+ builder.alignment = @min_alignment if defined?(@min_alignment)
214
+
215
+ if spec[0].kind_of?(Hash)
216
+ hash_layout(builder, spec)
217
+ else
218
+ array_layout(builder, spec)
219
+ end
220
+ builder.size = @size if defined?(@size) && @size > builder.size
221
+ cspec = builder.build
222
+ @layout = cspec unless self == Struct
223
+ @size = cspec.size
224
+ return cspec
225
+ end
226
+
227
+
228
+ protected
229
+
230
+ def callback(params, ret)
231
+ mod = enclosing_module
232
+ ret_type = find_type(ret, mod)
233
+ if ret_type == Type::STRING
234
+ raise TypeError, ":string is not allowed as return type of callbacks"
235
+ end
236
+ FFI::CallbackInfo.new(ret_type, params.map { |e| find_type(e, mod) })
237
+ end
238
+
239
+ def packed(packed = 1)
240
+ @packed = packed
241
+ end
242
+ alias :pack :packed
243
+
244
+ def aligned(alignment = 1)
245
+ @min_alignment = alignment
246
+ end
247
+ alias :align :aligned
248
+
249
+ def enclosing_module
250
+ begin
251
+ mod = self.name.split("::")[0..-2].inject(Object) { |obj, c| obj.const_get(c) }
252
+ if mod.respond_to?(:find_type) && (mod.is_a?(FFI::Library) || mod < FFI::Struct)
253
+ mod
254
+ end
255
+ rescue Exception
256
+ nil
257
+ end
258
+ end
259
+
260
+
261
+ def find_field_type(type, mod = enclosing_module)
262
+ if type.kind_of?(Class) && type < Struct
263
+ FFI::Type::Struct.new(type)
264
+
265
+ elsif type.kind_of?(Class) && type < FFI::StructLayout::Field
266
+ type
267
+
268
+ elsif type.kind_of?(::Array)
269
+ FFI::Type::Array.new(find_field_type(type[0]), type[1])
270
+
271
+ else
272
+ find_type(type, mod)
273
+ end
274
+ end
275
+
276
+ def find_type(type, mod = enclosing_module)
277
+ if mod
278
+ mod.find_type(type)
279
+ end || FFI.find_type(type)
280
+ end
281
+
282
+ private
283
+
284
+ # @param [StructLayoutBuilder] builder
285
+ # @param [Hash] spec
286
+ # @return [builder]
287
+ # Add hash +spec+ to +builder+.
288
+ def hash_layout(builder, spec)
289
+ spec[0].each do |name, type|
290
+ builder.add name, find_field_type(type), nil
291
+ end
292
+ end
293
+
294
+ # @param [StructLayoutBuilder] builder
295
+ # @param [Array<Symbol, Integer>] spec
296
+ # @return [builder]
297
+ # Add array +spec+ to +builder+.
298
+ def array_layout(builder, spec)
299
+ i = 0
300
+ while i < spec.size
301
+ name, type = spec[i, 2]
302
+ i += 2
303
+
304
+ # If the next param is a Integer, it specifies the offset
305
+ if spec[i].kind_of?(Integer)
306
+ offset = spec[i]
307
+ i += 1
308
+ else
309
+ offset = nil
310
+ end
311
+
312
+ builder.add name, find_field_type(type), offset
313
+ end
314
+ end
315
+ end
316
+ end
317
+ end