alinta-ffi 1.9.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +49 -0
  3. data/LICENSE +24 -0
  4. data/README.md +112 -0
  5. data/Rakefile +243 -0
  6. data/ext/ffi_c/AbstractMemory.c +1109 -0
  7. data/ext/ffi_c/AbstractMemory.h +175 -0
  8. data/ext/ffi_c/ArrayType.c +162 -0
  9. data/ext/ffi_c/ArrayType.h +59 -0
  10. data/ext/ffi_c/Buffer.c +365 -0
  11. data/ext/ffi_c/Call.c +517 -0
  12. data/ext/ffi_c/Call.h +110 -0
  13. data/ext/ffi_c/ClosurePool.c +283 -0
  14. data/ext/ffi_c/ClosurePool.h +57 -0
  15. data/ext/ffi_c/DataConverter.c +91 -0
  16. data/ext/ffi_c/DynamicLibrary.c +339 -0
  17. data/ext/ffi_c/DynamicLibrary.h +98 -0
  18. data/ext/ffi_c/Function.c +998 -0
  19. data/ext/ffi_c/Function.h +87 -0
  20. data/ext/ffi_c/FunctionInfo.c +271 -0
  21. data/ext/ffi_c/LastError.c +184 -0
  22. data/ext/ffi_c/LastError.h +47 -0
  23. data/ext/ffi_c/LongDouble.c +63 -0
  24. data/ext/ffi_c/LongDouble.h +51 -0
  25. data/ext/ffi_c/MappedType.c +168 -0
  26. data/ext/ffi_c/MappedType.h +59 -0
  27. data/ext/ffi_c/MemoryPointer.c +197 -0
  28. data/ext/ffi_c/MemoryPointer.h +53 -0
  29. data/ext/ffi_c/MethodHandle.c +358 -0
  30. data/ext/ffi_c/MethodHandle.h +55 -0
  31. data/ext/ffi_c/Platform.c +129 -0
  32. data/ext/ffi_c/Platform.h +45 -0
  33. data/ext/ffi_c/Pointer.c +508 -0
  34. data/ext/ffi_c/Pointer.h +63 -0
  35. data/ext/ffi_c/Struct.c +829 -0
  36. data/ext/ffi_c/Struct.h +106 -0
  37. data/ext/ffi_c/StructByReference.c +190 -0
  38. data/ext/ffi_c/StructByReference.h +50 -0
  39. data/ext/ffi_c/StructByValue.c +150 -0
  40. data/ext/ffi_c/StructByValue.h +55 -0
  41. data/ext/ffi_c/StructLayout.c +698 -0
  42. data/ext/ffi_c/Thread.c +352 -0
  43. data/ext/ffi_c/Thread.h +95 -0
  44. data/ext/ffi_c/Type.c +397 -0
  45. data/ext/ffi_c/Type.h +62 -0
  46. data/ext/ffi_c/Types.c +139 -0
  47. data/ext/ffi_c/Types.h +89 -0
  48. data/ext/ffi_c/Variadic.c +304 -0
  49. data/ext/ffi_c/compat.h +78 -0
  50. data/ext/ffi_c/extconf.rb +71 -0
  51. data/ext/ffi_c/ffi.c +98 -0
  52. data/ext/ffi_c/libffi.bsd.mk +40 -0
  53. data/ext/ffi_c/libffi.darwin.mk +105 -0
  54. data/ext/ffi_c/libffi.gnu.mk +32 -0
  55. data/ext/ffi_c/libffi.mk +18 -0
  56. data/ext/ffi_c/libffi.vc.mk +26 -0
  57. data/ext/ffi_c/libffi.vc64.mk +26 -0
  58. data/ext/ffi_c/rbffi.h +57 -0
  59. data/ext/ffi_c/rbffi_endian.h +59 -0
  60. data/ext/ffi_c/win32/stdbool.h +8 -0
  61. data/ext/ffi_c/win32/stdint.h +201 -0
  62. data/ffi.gemspec +23 -0
  63. data/gen/Rakefile +30 -0
  64. data/lib/ffi.rb +20 -0
  65. data/lib/ffi/autopointer.rb +203 -0
  66. data/lib/ffi/buffer.rb +4 -0
  67. data/lib/ffi/callback.rb +4 -0
  68. data/lib/ffi/enum.rb +296 -0
  69. data/lib/ffi/errno.rb +43 -0
  70. data/lib/ffi/ffi.rb +44 -0
  71. data/lib/ffi/io.rb +62 -0
  72. data/lib/ffi/library.rb +590 -0
  73. data/lib/ffi/managedstruct.rb +84 -0
  74. data/lib/ffi/memorypointer.rb +1 -0
  75. data/lib/ffi/platform.rb +164 -0
  76. data/lib/ffi/platform/aarch64-linux/types.conf +104 -0
  77. data/lib/ffi/platform/arm-linux/types.conf +104 -0
  78. data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
  79. data/lib/ffi/platform/i386-darwin/types.conf +100 -0
  80. data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  81. data/lib/ffi/platform/i386-gnu/types.conf +107 -0
  82. data/lib/ffi/platform/i386-linux/types.conf +103 -0
  83. data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  84. data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
  85. data/lib/ffi/platform/i386-solaris/types.conf +122 -0
  86. data/lib/ffi/platform/i386-windows/types.conf +105 -0
  87. data/lib/ffi/platform/ia64-linux/types.conf +104 -0
  88. data/lib/ffi/platform/mips-linux/types.conf +102 -0
  89. data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
  90. data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
  91. data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
  92. data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
  93. data/lib/ffi/platform/powerpc-linux/types.conf +100 -0
  94. data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
  95. data/lib/ffi/platform/s390-linux/types.conf +102 -0
  96. data/lib/ffi/platform/s390x-linux/types.conf +102 -0
  97. data/lib/ffi/platform/sparc-linux/types.conf +102 -0
  98. data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
  99. data/lib/ffi/platform/sparc64-linux/types.conf +102 -0
  100. data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
  101. data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
  102. data/lib/ffi/platform/x86_64-darwin/types.conf +126 -0
  103. data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
  104. data/lib/ffi/platform/x86_64-linux/types.conf +102 -0
  105. data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
  106. data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
  107. data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
  108. data/lib/ffi/platform/x86_64-windows/types.conf +120 -0
  109. data/lib/ffi/pointer.rb +161 -0
  110. data/lib/ffi/struct.rb +371 -0
  111. data/lib/ffi/struct_layout_builder.rb +227 -0
  112. data/lib/ffi/tools/const_generator.rb +229 -0
  113. data/lib/ffi/tools/generator.rb +60 -0
  114. data/lib/ffi/tools/generator_task.rb +36 -0
  115. data/lib/ffi/tools/struct_generator.rb +194 -0
  116. data/lib/ffi/tools/types_generator.rb +134 -0
  117. data/lib/ffi/types.rb +194 -0
  118. data/lib/ffi/union.rb +43 -0
  119. data/lib/ffi/variadic.rb +78 -0
  120. data/lib/ffi/version.rb +4 -0
  121. data/libtest/Benchmark.c +52 -0
  122. data/libtest/BoolTest.c +34 -0
  123. data/libtest/BufferTest.c +31 -0
  124. data/libtest/ClosureTest.c +205 -0
  125. data/libtest/EnumTest.c +51 -0
  126. data/libtest/FunctionTest.c +70 -0
  127. data/libtest/GNUmakefile +149 -0
  128. data/libtest/GlobalVariable.c +62 -0
  129. data/libtest/LastErrorTest.c +21 -0
  130. data/libtest/NumberTest.c +132 -0
  131. data/libtest/PointerTest.c +63 -0
  132. data/libtest/ReferenceTest.c +23 -0
  133. data/libtest/StringTest.c +34 -0
  134. data/libtest/StructTest.c +243 -0
  135. data/libtest/UnionTest.c +43 -0
  136. data/libtest/VariadicTest.c +99 -0
  137. data/spec/ffi/LICENSE.SPECS +22 -0
  138. data/spec/ffi/async_callback_spec.rb +35 -0
  139. data/spec/ffi/bitmask_spec.rb +575 -0
  140. data/spec/ffi/bool_spec.rb +32 -0
  141. data/spec/ffi/buffer_spec.rb +279 -0
  142. data/spec/ffi/callback_spec.rb +773 -0
  143. data/spec/ffi/custom_param_type.rb +37 -0
  144. data/spec/ffi/custom_type_spec.rb +74 -0
  145. data/spec/ffi/dup_spec.rb +52 -0
  146. data/spec/ffi/enum_spec.rb +423 -0
  147. data/spec/ffi/errno_spec.rb +20 -0
  148. data/spec/ffi/ffi_spec.rb +28 -0
  149. data/spec/ffi/fixtures/Benchmark.c +52 -0
  150. data/spec/ffi/fixtures/BitmaskTest.c +51 -0
  151. data/spec/ffi/fixtures/BoolTest.c +34 -0
  152. data/spec/ffi/fixtures/BufferTest.c +31 -0
  153. data/spec/ffi/fixtures/ClosureTest.c +205 -0
  154. data/spec/ffi/fixtures/EnumTest.c +51 -0
  155. data/spec/ffi/fixtures/FunctionTest.c +142 -0
  156. data/spec/ffi/fixtures/GNUmakefile +149 -0
  157. data/spec/ffi/fixtures/GlobalVariable.c +62 -0
  158. data/spec/ffi/fixtures/LastErrorTest.c +21 -0
  159. data/spec/ffi/fixtures/NumberTest.c +132 -0
  160. data/spec/ffi/fixtures/PipeHelper.h +21 -0
  161. data/spec/ffi/fixtures/PipeHelperPosix.c +41 -0
  162. data/spec/ffi/fixtures/PipeHelperWindows.c +72 -0
  163. data/spec/ffi/fixtures/PointerTest.c +63 -0
  164. data/spec/ffi/fixtures/ReferenceTest.c +23 -0
  165. data/spec/ffi/fixtures/StringTest.c +34 -0
  166. data/spec/ffi/fixtures/StructTest.c +243 -0
  167. data/spec/ffi/fixtures/UnionTest.c +43 -0
  168. data/spec/ffi/fixtures/VariadicTest.c +99 -0
  169. data/spec/ffi/fixtures/classes.rb +438 -0
  170. data/spec/ffi/function_spec.rb +97 -0
  171. data/spec/ffi/io_spec.rb +16 -0
  172. data/spec/ffi/library_spec.rb +286 -0
  173. data/spec/ffi/long_double.rb +30 -0
  174. data/spec/ffi/managed_struct_spec.rb +68 -0
  175. data/spec/ffi/memorypointer_spec.rb +78 -0
  176. data/spec/ffi/number_spec.rb +247 -0
  177. data/spec/ffi/platform_spec.rb +114 -0
  178. data/spec/ffi/pointer_spec.rb +285 -0
  179. data/spec/ffi/rbx/attach_function_spec.rb +34 -0
  180. data/spec/ffi/rbx/memory_pointer_spec.rb +198 -0
  181. data/spec/ffi/rbx/spec_helper.rb +6 -0
  182. data/spec/ffi/rbx/struct_spec.rb +18 -0
  183. data/spec/ffi/spec_helper.rb +93 -0
  184. data/spec/ffi/string_spec.rb +118 -0
  185. data/spec/ffi/strptr_spec.rb +50 -0
  186. data/spec/ffi/struct_by_ref_spec.rb +43 -0
  187. data/spec/ffi/struct_callback_spec.rb +69 -0
  188. data/spec/ffi/struct_initialize_spec.rb +35 -0
  189. data/spec/ffi/struct_packed_spec.rb +50 -0
  190. data/spec/ffi/struct_spec.rb +882 -0
  191. data/spec/ffi/typedef_spec.rb +91 -0
  192. data/spec/ffi/union_spec.rb +67 -0
  193. data/spec/ffi/variadic_spec.rb +132 -0
  194. data/spec/spec.opts +4 -0
  195. metadata +309 -0
@@ -0,0 +1,129 @@
1
+ /*
2
+ * Copyright (c) 2008-2010 Wayne Meissner
3
+ *
4
+ * Copyright (c) 2008-2013, Ruby FFI project contributors
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ * * Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * * Neither the name of the Ruby FFI project nor the
15
+ * names of its contributors may be used to endorse or promote products
16
+ * derived from this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #ifndef _MSC_VER
31
+ # include <sys/param.h>
32
+ #endif
33
+ # include <sys/types.h>
34
+ #ifndef _MSC_VER
35
+ # include <stdint.h>
36
+ # include <stdbool.h>
37
+ #else
38
+ # include "win32/stdint.h"
39
+ # include "win32/stdbool.h"
40
+ #endif
41
+ #include <ruby.h>
42
+ #include <ctype.h>
43
+ #include "rbffi_endian.h"
44
+ #include "Platform.h"
45
+
46
+ #if defined(__GNU__) || defined(__GLIBC__)
47
+ # include <gnu/lib-names.h>
48
+ #endif
49
+
50
+ static VALUE PlatformModule = Qnil;
51
+
52
+ /*
53
+ * Determine the cpu type at compile time - useful for MacOSX where the the
54
+ * system installed ruby incorrectly reports 'host_cpu' as 'powerpc' when running
55
+ * on intel.
56
+ */
57
+ #if defined(__x86_64__) || defined(__x86_64) || defined(__amd64) || defined(_M_X64) || defined(_M_AMD64)
58
+ # define CPU "x86_64"
59
+
60
+ #elif defined(__i386__) || defined(__i386) || defined(_M_IX86)
61
+ # define CPU "i386"
62
+
63
+ #elif defined(__ppc64__) || defined(__powerpc64__) || defined(_M_PPC)
64
+ # define CPU "ppc64"
65
+
66
+ #elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc)
67
+ # define CPU "ppc"
68
+
69
+ /*
70
+ * Need to check for __sparcv9 first, because __sparc will be defined either way.
71
+ * Note that __sparcv9 seems to only be set for Solaris. On Linux, __sparc will
72
+ * be set, along with __arch64__ if a 64-bit platform.
73
+ */
74
+ #elif defined(__sparcv9__) || defined(__sparcv9)
75
+ # define CPU "sparcv9"
76
+
77
+ #elif defined(__sparc__) || defined(__sparc)
78
+ # if defined(__arch64__)
79
+ # define CPU "sparcv9"
80
+ # else
81
+ # define CPU "sparc"
82
+ # endif
83
+
84
+ #elif defined(__arm__) || defined(__arm)
85
+ # define CPU "arm"
86
+
87
+ #elif defined(__mips__) || defined(__mips)
88
+ # define CPU "mips"
89
+
90
+ #elif defined(__s390__)
91
+ # define CPU "s390"
92
+
93
+ #else
94
+ # define CPU "unknown"
95
+ #endif
96
+
97
+ static void
98
+ export_primitive_types(VALUE module)
99
+ {
100
+ #define S(name, T) do { \
101
+ typedef struct { char c; T v; } s; \
102
+ rb_define_const(module, #name "_ALIGN", INT2NUM((sizeof(s) - sizeof(T)) * 8)); \
103
+ rb_define_const(module, #name "_SIZE", INT2NUM(sizeof(T)* 8)); \
104
+ } while(0)
105
+ S(INT8, char);
106
+ S(INT16, short);
107
+ S(INT32, int);
108
+ S(INT64, long long);
109
+ S(LONG, long);
110
+ S(FLOAT, float);
111
+ S(DOUBLE, double);
112
+ S(ADDRESS, void*);
113
+ #undef S
114
+ }
115
+
116
+ void
117
+ rbffi_Platform_Init(VALUE moduleFFI)
118
+ {
119
+ PlatformModule = rb_define_module_under(moduleFFI, "Platform");
120
+ rb_define_const(PlatformModule, "BYTE_ORDER", INT2FIX(BYTE_ORDER));
121
+ rb_define_const(PlatformModule, "LITTLE_ENDIAN", INT2FIX(LITTLE_ENDIAN));
122
+ rb_define_const(PlatformModule, "BIG_ENDIAN", INT2FIX(BIG_ENDIAN));
123
+ rb_define_const(PlatformModule, "CPU", rb_str_new2(CPU));
124
+ #if defined(__GNU__) || defined(__GLIBC__)
125
+ rb_define_const(PlatformModule, "GNU_LIBC", rb_str_new2(LIBC_SO));
126
+ #endif
127
+ export_primitive_types(PlatformModule);
128
+ }
129
+
@@ -0,0 +1,45 @@
1
+ /*
2
+ * Copyright (c) 2008-2010 Wayne Meissner
3
+ *
4
+ * Copyright (c) 2008-2013, Ruby FFI project contributors
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ * * Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * * Neither the name of the Ruby FFI project nor the
15
+ * names of its contributors may be used to endorse or promote products
16
+ * derived from this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #ifndef RBFFI_PLATFORM_H
31
+ #define RBFFI_PLATFORM_H
32
+
33
+ #ifdef __cplusplus
34
+ extern "C" {
35
+ #endif
36
+
37
+ extern void rbffi_Platform_Init(VALUE moduleFFI);
38
+
39
+
40
+ #ifdef __cplusplus
41
+ }
42
+ #endif
43
+
44
+ #endif /* RBFFI_PLATFORM_H */
45
+
@@ -0,0 +1,508 @@
1
+ /*
2
+ * Copyright (c) 2008, 2009, Wayne Meissner
3
+ *
4
+ * Copyright (c) 2008-2013, Ruby FFI project contributors
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ * * Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * * Neither the name of the Ruby FFI project nor the
15
+ * names of its contributors may be used to endorse or promote products
16
+ * derived from this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #ifndef _MSC_VER
31
+ # include <stdint.h>
32
+ # include <stdbool.h>
33
+ #else
34
+ # include "win32/stdint.h"
35
+ # include "win32/stdbool.h"
36
+ #endif
37
+ #include <limits.h>
38
+ #include <ruby.h>
39
+ #include "rbffi.h"
40
+ #include "rbffi_endian.h"
41
+ #include "AbstractMemory.h"
42
+ #include "Pointer.h"
43
+
44
+ #define POINTER(obj) rbffi_AbstractMemory_Cast((obj), rbffi_PointerClass)
45
+
46
+ VALUE rbffi_PointerClass = Qnil;
47
+ VALUE rbffi_NullPointerSingleton = Qnil;
48
+
49
+ static void ptr_release(Pointer* ptr);
50
+ static void ptr_mark(Pointer* ptr);
51
+
52
+ VALUE
53
+ rbffi_Pointer_NewInstance(void* addr)
54
+ {
55
+ Pointer* p;
56
+ VALUE obj;
57
+
58
+ if (addr == NULL) {
59
+ return rbffi_NullPointerSingleton;
60
+ }
61
+
62
+ obj = Data_Make_Struct(rbffi_PointerClass, Pointer, NULL, -1, p);
63
+ p->memory.address = addr;
64
+ p->memory.size = LONG_MAX;
65
+ p->memory.flags = (addr == NULL) ? 0 : (MEM_RD | MEM_WR);
66
+ p->memory.typeSize = 1;
67
+ p->rbParent = Qnil;
68
+
69
+ return obj;
70
+ }
71
+
72
+ static VALUE
73
+ ptr_allocate(VALUE klass)
74
+ {
75
+ Pointer* p;
76
+ VALUE obj;
77
+
78
+ obj = Data_Make_Struct(klass, Pointer, ptr_mark, ptr_release, p);
79
+ p->rbParent = Qnil;
80
+ p->memory.flags = MEM_RD | MEM_WR;
81
+
82
+ return obj;
83
+ }
84
+
85
+ /*
86
+ * @overload initialize(pointer)
87
+ * @param [Pointer] pointer another pointer to initialize from
88
+ * Create a new pointer from another {Pointer}.
89
+ * @overload initialize(type, address)
90
+ * @param [Type] type type for pointer
91
+ * @param [Integer] address base address for pointer
92
+ * Create a new pointer from a {Type} and a base address
93
+ * @return [self]
94
+ * A new instance of Pointer.
95
+ */
96
+ static VALUE
97
+ ptr_initialize(int argc, VALUE* argv, VALUE self)
98
+ {
99
+ Pointer* p;
100
+ VALUE rbType = Qnil, rbAddress = Qnil;
101
+ int typeSize = 1;
102
+
103
+ Data_Get_Struct(self, Pointer, p);
104
+
105
+ switch (rb_scan_args(argc, argv, "11", &rbType, &rbAddress)) {
106
+ case 1:
107
+ rbAddress = rbType;
108
+ typeSize = 1;
109
+ break;
110
+ case 2:
111
+ typeSize = rbffi_type_size(rbType);
112
+ break;
113
+ default:
114
+ rb_raise(rb_eArgError, "Invalid arguments");
115
+ }
116
+
117
+ switch (TYPE(rbAddress)) {
118
+ case T_FIXNUM:
119
+ case T_BIGNUM:
120
+ p->memory.address = (void*) (uintptr_t) NUM2LL(rbAddress);
121
+ p->memory.size = LONG_MAX;
122
+ if (p->memory.address == NULL) {
123
+ p->memory.flags = 0;
124
+ }
125
+ break;
126
+
127
+ default:
128
+ if (rb_obj_is_kind_of(rbAddress, rbffi_PointerClass)) {
129
+ Pointer* orig;
130
+
131
+ p->rbParent = rbAddress;
132
+ Data_Get_Struct(rbAddress, Pointer, orig);
133
+ p->memory = orig->memory;
134
+ } else {
135
+ rb_raise(rb_eTypeError, "wrong argument type, expected Integer or FFI::Pointer");
136
+ }
137
+ break;
138
+ }
139
+
140
+ p->memory.typeSize = typeSize;
141
+
142
+ return self;
143
+ }
144
+
145
+ /*
146
+ * call-seq: ptr.initialize_copy(other)
147
+ * @param [Pointer] other source for cloning or dupping
148
+ * @return [self]
149
+ * @raise {RuntimeError} if +other+ is an unbounded memory area, or is unreadable/unwritable
150
+ * @raise {NoMemError} if failed to allocate memory for new object
151
+ * DO NOT CALL THIS METHOD.
152
+ *
153
+ * This method is internally used by #dup and #clone. Memory content is copied from +other+.
154
+ */
155
+ static VALUE
156
+ ptr_initialize_copy(VALUE self, VALUE other)
157
+ {
158
+ AbstractMemory* src;
159
+ Pointer* dst;
160
+
161
+ Data_Get_Struct(self, Pointer, dst);
162
+ src = POINTER(other);
163
+ if (src->size == LONG_MAX) {
164
+ rb_raise(rb_eRuntimeError, "cannot duplicate unbounded memory area");
165
+ return Qnil;
166
+ }
167
+
168
+ if ((dst->memory.flags & (MEM_RD | MEM_WR)) != (MEM_RD | MEM_WR)) {
169
+ rb_raise(rb_eRuntimeError, "cannot duplicate unreadable/unwritable memory area");
170
+ return Qnil;
171
+ }
172
+
173
+ if (dst->storage != NULL) {
174
+ xfree(dst->storage);
175
+ dst->storage = NULL;
176
+ }
177
+
178
+ dst->storage = xmalloc(src->size + 7);
179
+ if (dst->storage == NULL) {
180
+ rb_raise(rb_eNoMemError, "failed to allocate memory size=%lu bytes", src->size);
181
+ return Qnil;
182
+ }
183
+
184
+ dst->allocated = true;
185
+ dst->autorelease = true;
186
+ dst->memory.address = (void *) (((uintptr_t) dst->storage + 0x7) & (uintptr_t) ~0x7UL);
187
+ dst->memory.size = src->size;
188
+ dst->memory.typeSize = src->typeSize;
189
+
190
+ /* finally, copy the actual memory contents */
191
+ memcpy(dst->memory.address, src->address, src->size);
192
+
193
+ return self;
194
+ }
195
+
196
+ static VALUE
197
+ slice(VALUE self, long offset, long size)
198
+ {
199
+ AbstractMemory* ptr;
200
+ Pointer* p;
201
+ VALUE retval;
202
+
203
+ Data_Get_Struct(self, AbstractMemory, ptr);
204
+ checkBounds(ptr, offset, size == LONG_MAX ? 1 : size);
205
+
206
+ retval = Data_Make_Struct(rbffi_PointerClass, Pointer, ptr_mark, -1, p);
207
+
208
+ p->memory.address = ptr->address + offset;
209
+ p->memory.size = size;
210
+ p->memory.flags = ptr->flags;
211
+ p->memory.typeSize = ptr->typeSize;
212
+ p->rbParent = self;
213
+
214
+ return retval;
215
+ }
216
+
217
+ /*
218
+ * Document-method: +
219
+ * call-seq: ptr + offset
220
+ * @param [Numeric] offset
221
+ * @return [Pointer]
222
+ * Return a new {Pointer} from an existing pointer and an +offset+.
223
+ */
224
+ static VALUE
225
+ ptr_plus(VALUE self, VALUE offset)
226
+ {
227
+ AbstractMemory* ptr;
228
+ long off = NUM2LONG(offset);
229
+
230
+ Data_Get_Struct(self, AbstractMemory, ptr);
231
+
232
+ return slice(self, off, ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off);
233
+ }
234
+
235
+ /*
236
+ * call-seq: ptr.slice(offset, length)
237
+ * @param [Numeric] offset
238
+ * @param [Numeric] length
239
+ * @return [Pointer]
240
+ * Return a new {Pointer} from an existing one. This pointer points on same contents
241
+ * from +offset+ for a length +length+.
242
+ */
243
+ static VALUE
244
+ ptr_slice(VALUE self, VALUE rbOffset, VALUE rbLength)
245
+ {
246
+ return slice(self, NUM2LONG(rbOffset), NUM2LONG(rbLength));
247
+ }
248
+
249
+ /*
250
+ * call-seq: ptr.inspect
251
+ * @return [String]
252
+ * Inspect pointer object.
253
+ */
254
+ static VALUE
255
+ ptr_inspect(VALUE self)
256
+ {
257
+ char buf[100];
258
+ Pointer* ptr;
259
+
260
+ Data_Get_Struct(self, Pointer, ptr);
261
+
262
+ if (ptr->memory.size != LONG_MAX) {
263
+ snprintf(buf, sizeof(buf), "#<%s address=%p size=%lu>",
264
+ rb_obj_classname(self), ptr->memory.address, ptr->memory.size);
265
+ } else {
266
+ snprintf(buf, sizeof(buf), "#<%s address=%p>", rb_obj_classname(self), ptr->memory.address);
267
+ }
268
+
269
+ return rb_str_new2(buf);
270
+ }
271
+
272
+ /*
273
+ * Document-method: null?
274
+ * call-seq: ptr.null?
275
+ * @return [Boolean]
276
+ * Return +true+ if +self+ is a {NULL} pointer.
277
+ */
278
+ static VALUE
279
+ ptr_null_p(VALUE self)
280
+ {
281
+ Pointer* ptr;
282
+
283
+ Data_Get_Struct(self, Pointer, ptr);
284
+
285
+ return ptr->memory.address == NULL ? Qtrue : Qfalse;
286
+ }
287
+
288
+ /*
289
+ * Document-method: ==
290
+ * call-seq: ptr == other
291
+ * @param [Pointer] other
292
+ * Check equality between +self+ and +other+. Equality is tested on {#address}.
293
+ */
294
+ static VALUE
295
+ ptr_equals(VALUE self, VALUE other)
296
+ {
297
+ Pointer* ptr;
298
+
299
+ Data_Get_Struct(self, Pointer, ptr);
300
+
301
+ if (NIL_P(other)) {
302
+ return ptr->memory.address == NULL ? Qtrue : Qfalse;
303
+ }
304
+
305
+ return ptr->memory.address == POINTER(other)->address ? Qtrue : Qfalse;
306
+ }
307
+
308
+ /*
309
+ * call-seq: ptr.address
310
+ * @return [Numeric] pointer's base address
311
+ * Return +self+'s base address (alias: #to_i).
312
+ */
313
+ static VALUE
314
+ ptr_address(VALUE self)
315
+ {
316
+ Pointer* ptr;
317
+
318
+ Data_Get_Struct(self, Pointer, ptr);
319
+
320
+ return ULL2NUM((uintptr_t) ptr->memory.address);
321
+ }
322
+
323
+ #if BYTE_ORDER == LITTLE_ENDIAN
324
+ # define SWAPPED_ORDER BIG_ENDIAN
325
+ #else
326
+ # define SWAPPED_ORDER LITTLE_ENDIAN
327
+ #endif
328
+
329
+ /*
330
+ * Get or set +self+'s endianness
331
+ * @overload order
332
+ * @return [:big, :little] endianness of +self+
333
+ * @overload order(order)
334
+ * @param [Symbol] order endianness to set (+:little+, +:big+ or +:network+). +:big+ and +:network+
335
+ * are synonymous.
336
+ * @return [self]
337
+ */
338
+ static VALUE
339
+ ptr_order(int argc, VALUE* argv, VALUE self)
340
+ {
341
+ Pointer* ptr;
342
+
343
+ Data_Get_Struct(self, Pointer, ptr);
344
+ if (argc == 0) {
345
+ int order = (ptr->memory.flags & MEM_SWAP) == 0 ? BYTE_ORDER : SWAPPED_ORDER;
346
+ return order == BIG_ENDIAN ? ID2SYM(rb_intern("big")) : ID2SYM(rb_intern("little"));
347
+ } else {
348
+ VALUE rbOrder = Qnil;
349
+ int order = BYTE_ORDER;
350
+
351
+ if (rb_scan_args(argc, argv, "1", &rbOrder) < 1) {
352
+ rb_raise(rb_eArgError, "need byte order");
353
+ }
354
+ if (SYMBOL_P(rbOrder)) {
355
+ ID id = SYM2ID(rbOrder);
356
+ if (id == rb_intern("little")) {
357
+ order = LITTLE_ENDIAN;
358
+
359
+ } else if (id == rb_intern("big") || id == rb_intern("network")) {
360
+ order = BIG_ENDIAN;
361
+ }
362
+ }
363
+ if (order != BYTE_ORDER) {
364
+ Pointer* p2;
365
+ VALUE retval = slice(self, 0, ptr->memory.size);
366
+
367
+ Data_Get_Struct(retval, Pointer, p2);
368
+ p2->memory.flags |= MEM_SWAP;
369
+ return retval;
370
+ }
371
+
372
+ return self;
373
+ }
374
+ }
375
+
376
+
377
+ /*
378
+ * call-seq: ptr.free
379
+ * @return [self]
380
+ * Free memory pointed by +self+.
381
+ */
382
+ static VALUE
383
+ ptr_free(VALUE self)
384
+ {
385
+ Pointer* ptr;
386
+
387
+ Data_Get_Struct(self, Pointer, ptr);
388
+
389
+ if (ptr->allocated) {
390
+ if (ptr->storage != NULL) {
391
+ xfree(ptr->storage);
392
+ ptr->storage = NULL;
393
+ }
394
+ ptr->allocated = false;
395
+
396
+ } else {
397
+ VALUE caller = rb_funcall(rb_funcall(Qnil, rb_intern("caller"), 0), rb_intern("first"), 0);
398
+
399
+ rb_warn("calling free on non allocated pointer %s from %s", RSTRING_PTR(ptr_inspect(self)), RSTRING_PTR(rb_str_to_str(caller)));
400
+ }
401
+
402
+ return self;
403
+ }
404
+
405
+ static VALUE
406
+ ptr_type_size(VALUE self)
407
+ {
408
+ Pointer* ptr;
409
+
410
+ Data_Get_Struct(self, Pointer, ptr);
411
+
412
+ return INT2NUM(ptr->memory.typeSize);
413
+ }
414
+
415
+ /*
416
+ * call-seq: ptr.autorelease = autorelease
417
+ * @param [Boolean] autorelease
418
+ * @return [Boolean] +autorelease+
419
+ * Set +autorelease+ attribute. See also Autorelease section.
420
+ */
421
+ static VALUE
422
+ ptr_autorelease(VALUE self, VALUE autorelease)
423
+ {
424
+ Pointer* ptr;
425
+
426
+ Data_Get_Struct(self, Pointer, ptr);
427
+ ptr->autorelease = autorelease == Qtrue;
428
+
429
+ return autorelease;
430
+ }
431
+
432
+ /*
433
+ * call-seq: ptr.autorelease?
434
+ * @return [Boolean]
435
+ * Get +autorelease+ attribute. See also Autorelease section.
436
+ */
437
+ static VALUE
438
+ ptr_autorelease_p(VALUE self)
439
+ {
440
+ Pointer* ptr;
441
+
442
+ Data_Get_Struct(self, Pointer, ptr);
443
+
444
+ return ptr->autorelease ? Qtrue : Qfalse;
445
+ }
446
+
447
+
448
+ static void
449
+ ptr_release(Pointer* ptr)
450
+ {
451
+ if (ptr->autorelease && ptr->allocated && ptr->storage != NULL) {
452
+ xfree(ptr->storage);
453
+ ptr->storage = NULL;
454
+ }
455
+ xfree(ptr);
456
+ }
457
+
458
+ static void
459
+ ptr_mark(Pointer* ptr)
460
+ {
461
+ rb_gc_mark(ptr->rbParent);
462
+ }
463
+
464
+ void
465
+ rbffi_Pointer_Init(VALUE moduleFFI)
466
+ {
467
+ VALUE rbNullAddress = ULL2NUM(0);
468
+ VALUE ffi_AbstractMemory = rbffi_AbstractMemoryClass;
469
+
470
+ /*
471
+ * Document-class: FFI::Pointer < FFI::AbstractMemory
472
+ * Pointer class is used to manage C pointers with ease. A {Pointer} object is defined by his
473
+ * {#address} (as a C pointer). It permits additions with an integer for pointer arithmetic.
474
+ *
475
+ * ==Autorelease
476
+ * A pointer object may autorelease his contents when freed (by default). This behaviour may be
477
+ * changed with {#autorelease=} method.
478
+ */
479
+ rbffi_PointerClass = rb_define_class_under(moduleFFI, "Pointer", ffi_AbstractMemory);
480
+ /*
481
+ * Document-variable: Pointer
482
+ */
483
+ rb_global_variable(&rbffi_PointerClass);
484
+
485
+ rb_define_alloc_func(rbffi_PointerClass, ptr_allocate);
486
+ rb_define_method(rbffi_PointerClass, "initialize", ptr_initialize, -1);
487
+ rb_define_method(rbffi_PointerClass, "initialize_copy", ptr_initialize_copy, 1);
488
+ rb_define_method(rbffi_PointerClass, "inspect", ptr_inspect, 0);
489
+ rb_define_method(rbffi_PointerClass, "to_s", ptr_inspect, 0);
490
+ rb_define_method(rbffi_PointerClass, "+", ptr_plus, 1);
491
+ rb_define_method(rbffi_PointerClass, "slice", ptr_slice, 2);
492
+ rb_define_method(rbffi_PointerClass, "null?", ptr_null_p, 0);
493
+ rb_define_method(rbffi_PointerClass, "address", ptr_address, 0);
494
+ rb_define_alias(rbffi_PointerClass, "to_i", "address");
495
+ rb_define_method(rbffi_PointerClass, "==", ptr_equals, 1);
496
+ rb_define_method(rbffi_PointerClass, "order", ptr_order, -1);
497
+ rb_define_method(rbffi_PointerClass, "autorelease=", ptr_autorelease, 1);
498
+ rb_define_method(rbffi_PointerClass, "autorelease?", ptr_autorelease_p, 0);
499
+ rb_define_method(rbffi_PointerClass, "free", ptr_free, 0);
500
+ rb_define_method(rbffi_PointerClass, "type_size", ptr_type_size, 0);
501
+
502
+ rbffi_NullPointerSingleton = rb_class_new_instance(1, &rbNullAddress, rbffi_PointerClass);
503
+ /*
504
+ * NULL pointer
505
+ */
506
+ rb_define_const(rbffi_PointerClass, "NULL", rbffi_NullPointerSingleton);
507
+ }
508
+