def test_recursive_struct(self): FFI = pydffi.FFI() CU = FFI.cdef(''' typedef struct { unsigned char a; int b; int c; short d; } A; typedef struct _Node Node; struct _Node { A v; struct _Node* next; }; ''') A = CU.types.A Node = CU.types.Node A0 = A(a=0, b=1, c=10, d=20) A1 = A(a=1, b=2, c=-10, d=-20) N1 = Node(v=A1, next=pydffi.ptr(Node)()) N0 = Node(v=A0, next=pydffi.ptr(N1)) for T in self.generated_types(Node, "_Node"): V = self.purectypes.unpack(T, bytes(pydffi.view_as_bytes(N0))) for attr in ("a", "b", "c", "d"): self.assertEqual(getattr(V.v, attr), getattr(N0.v, attr)) self.assertEqual(V.next, int(N0.next))
def test_recursive_union(self): FFI = pydffi.FFI() CU = FFI.cdef(''' typedef struct { unsigned char a; int b; int c; short d; } A; typedef union _Node Node; union _Node { A v; Node* next; }; ''') A = CU.types.A Node = CU.types.Node A0 = A(a=0, b=1, c=10, d=20) A1 = A(a=1, b=2, c=-10, d=-20) N1 = Node() N1.next = pydffi.ptr(Node)() N0 = Node() N0.next = pydffi.ptr(N1) for T in self.generated_types(Node, "_Node"): V = self.purectypes.unpack(T, bytes(pydffi.view_as_bytes(N0))) self.assertEqual(V.next, int(N0.next))
def test_ptrs(self): F = self.FFI O = F.UInt32Ty(4) P = pydffi.ptr(O) NewP = F.UInt32PtrTy(int(P.value)) self.assertEqual(NewP.obj, O)
def test_symbol(self): addr = 0xAABBCCDD pydffi.addSymbol("my_custom_symbol", 0xAABBCCDD) F = self.FFI CU = F.cdef(''' extern void my_custom_symbol(int); ''') self.assertEqual(pydffi.ptr(CU.funcs.my_custom_symbol).value, addr)
def test_cast(self): FFI = self.FFI # Integer casts for Ty in (FFI.UInt8, FFI.UInt16, FFI.UInt32, FFI.UInt64): v = random.getrandbits(pydffi.sizeof(Ty(0)) * 8) V = Ty(v) for CTy in (FFI.UInt8Ty, FFI.UInt16Ty, FFI.UInt32Ty, FFI.UInt64Ty): VC = pydffi.cast(V, CTy) self.assertEqual(VC.value, v & (2**(CTy.size * 8) - 1)) # Array/pointer casts CU = FFI.compile(''' #include <stdio.h> #include <stdbool.h> typedef struct { char buf[256]; } A; bool verify(const char* msg, const char* ref) { return strcmp(msg, ref) == 0; } bool verify_struct(A const* a, const char* ref) { return strcmp(a->buf, ref) == 0; } ''') verify_struct = CU.funcs.verify_struct SA = CU.types.A A = pydffi.CStructObj(SA) mem = pydffi.view_as_bytes(A) b = b"hello!\x00" mem[:len(b)] = b self.assertTrue(verify_struct(pydffi.ptr(A), b"hello!")) verify = getattr(CU.funcs, "verify") buf = A.buf buf = pydffi.cast(pydffi.ptr(buf), FFI.Int8PtrTy) self.assertTrue(verify(buf, b"hello!")) # Cast back buf = pydffi.cast(buf, FFI.pointerType(SA)) self.assertTrue(verify_struct(buf, b"hello!"))
def test_array(self): CU = self.FFI.compile(''' #include <stdio.h> #include <string.h> #include <stdbool.h> struct A { char buf[128]; }; struct A init() { struct A a; strcpy(a.buf, "hello"); return a; } bool verify(struct A const* v, const char* ref) { return strcmp(v->buf, ref) == 0; } ''') A = CU.funcs.init() Buf = A.buf self.assertEqual(Buf.get(0), "h") Buf.set(0, 'H') self.assertEqual(Buf.get(0), "H") self.assertTrue(CU.funcs.verify(pydffi.ptr(A), b"Hello")) m = pydffi.view_as_bytes(Buf) v = ord("Z") if sys.version_info >= (3, 0) else struct.pack( "B", ord("Z")) m[0] = v self.assertTrue(CU.funcs.verify(pydffi.ptr(A), b"Zello")) UIntTy = self.FFI.basicType(pydffi.BasicKind.UInt) N = 10 ArrTy = self.FFI.arrayType(UIntTy, N) Arr = pydffi.CArrayObj(ArrTy) for i in range(N): Arr.set(i, i) for i in range(N): self.assertEqual(Arr.get(i), i)
def test_structs(self): FFI = self.FFI CU = FFI.compile(''' struct A { unsigned char a; short b; }; int check(struct A a, unsigned char aref, short bref) { return (a.a == aref) && (a.b == bref); } int checkptr(struct A* a, unsigned char aref, short bref) { return (a->a == aref) && (a->b == bref); } void set(struct A* a) { a->a = 59; a->b = 1111; } struct A init() { struct A ret; ret.a = 44; ret.b = 5555; return ret; } ''') A = CU.types.A fields_name = sorted((f.name for f in A)) self.assertEqual(fields_name[0], 'a') self.assertEqual(fields_name[1], 'b') Av = CU.types.A(a=1, b=2) # Direct data access throught a memoryview mv = pydffi.view_as_bytes(Av) # Set a throught mv v = 5 if sys.version_info >= (3, 0) else struct.pack("B", 5) mv[0] = v self.assertEqual(Av.a, 5) self.assertEqual(Av.b, 2) self.assertTrue(getattr(CU.funcs, "check")(Av, 5, 2)) pAv = pydffi.ptr(Av) self.assertTrue(CU.funcs.checkptr(pAv, 5, 2)) CU.funcs.set(pAv) self.assertTrue(getattr(CU.funcs, "check")(Av, 59, 1111)) self.assertEqual(Av.a, 59) self.assertEqual(Av.b, 1111) Av = CU.funcs.init() self.assertEqual(Av.a, 44) self.assertEqual(Av.b, 5555)
def test_new_structs(self): D = self.FFI CU = D.compile(''' #include <stdio.h> struct A { int a; short b; }; void print(char* ret, size_t n, struct A a) { snprintf(ret, n, "%d %d", a.a, a.b); } ''') buf = self.FFI.arrayType(self.FFI.CharTy, 128)() a = CU.types.A(a=4, b=10) getattr(CU.funcs, "print")(pydffi.ptr(buf), 128, a) self.assertEqual(self.cstr_from_array(buf), b"4 10") a = CU.types.A(a=0, b=0) getattr(CU.funcs, "print")(pydffi.ptr(buf), 128, a) self.assertEqual(self.cstr_from_array(buf), b"0 0")
def test_array_ptr(self): CU = self.FFI.compile(''' #include <stdio.h> typedef int int2[2]; void foo(char* buf, size_t n, int2* ar) { snprintf(buf, n, "%d %d", ar[0][0], ar[0][1]); } ''') v = CU.types.int2() v.set(0, 1) v.set(1, 2) buf = self.FFI.arrayType(self.FFI.CharTy, 128)() CU.funcs.foo(pydffi.ptr(buf), 128, pydffi.ptr(v)) self.assertEqual(self.cstr_from_array(buf), b"1 2") v[0] = 10 v[1] = 20 CU.funcs.foo(pydffi.ptr(buf), 128, pydffi.ptr(v)) self.assertEqual(self.cstr_from_array(buf), b"10 20")
def test_func_ptr(self): FFI = self.FFI CU = FFI.compile(''' typedef struct { int a; int b; int res; } Res; typedef Res(*op)(int,int); static Res get_res(int res, int a, int b) { Res Ret = {a,b,res}; return Ret; } static Res add(int a, int b) { return get_res(a+b,a,b); } static Res sub(int a, int b) { return get_res(a-b,a,b); } op get_op(unsigned Id) { if (Id == 0) return add; if (Id == 1) return sub; return 0; } Res call(op f, int a, int b) { return f(a,b); } ''') Add = CU.funcs.get_op(0) Add = Add.obj Res = Add(1, 4) self.assertEqual(Res.res, 5) sub_addr = pydffi.ptr(CU.funcs.sub) Res = CU.funcs.call(sub_addr, 1, 5) self.assertEqual(Res.res, -4) subFuncTy = pydffi.typeof(CU.funcs.sub).type funcByAddr = subFuncTy(sub_addr) self.assertEqual(funcByAddr(1, 5).res, -4) funcByAddr = subFuncTy(sub_addr.value) self.assertEqual(funcByAddr(1, 5).res, -4)
def test_buffers(self): CU = self.FFI.compile(''' #include <stdio.h> #include <stdint.h> void print(const char* msg) { puts(msg); } void print_u8(uint8_t const* buf, size_t len) { for (size_t i = 0; i < len; ++i) { printf("%02X ", buf[i]); } printf("\\n"); } void bytesupper(uint8_t* S) { const size_t Len = strlen(S); printf("%lu\\n", Len); for (size_t i = 0; i < Len; ++i) { S[i] = toupper(S[i]); } } void strupper(char* S) { bytesupper(S); } ''') print_ = getattr(CU.funcs, "print") print_u8 = CU.funcs.print_u8 bytesupper = CU.funcs.bytesupper strupper = CU.funcs.strupper # CHECK: coucou print_("coucou") # CHECK: héllo print_("héllo") buf = u"héllo".encode("utf8") # CHECK: 68 C3 A9 6C 6C 6F print_u8(buf, len(buf)) buf = bytearray(b"hello") bytesupper(buf) self.assertEqual(buf, b"HELLO") buf = bytearray(b"hello") buf_char = pydffi.view_as(self.FFI.arrayType(self.FFI.UInt8Ty, len(buf)), buf) strupper(pydffi.cast(pydffi.ptr(buf_char),self.FFI.CharPtrTy)) self.assertEqual(buf, b"HELLO")
void print(const char* msg) { puts(msg); } void print_struct(A const* a) { print(a->buf); } ''') print_struct = CU.funcs.print_struct SA = CU.types.A A = pydffi.CStructObj(SA) mem = pydffi.view_as_bytes(A) b = b"hello!\x00" mem[:len(b)] = b # CHECK: hello! print_struct(pydffi.ptr(A)) print_ = getattr(CU.funcs, "print") buf = A.buf buf = pydffi.cast(pydffi.ptr(buf),FFI.Int8PtrTy) # CHECK: hello! print_(buf) # Cast back buf = pydffi.cast(buf, FFI.pointerType(SA)) # CHECK: hello! print_struct(buf)
struct A a; strcpy(a.buf, "hello"); return a; } void dump(struct A const* v) { puts(v->buf); } ''') A = CU.funcs.init() Buf = A.buf assert(Buf.get(0) == "h") Buf.set(0, 'H') assert(Buf.get(0) == "H") # CHECK: Hello CU.funcs.dump(pydffi.ptr(A)) m = pydffi.view_as_bytes(Buf) v = ord("Z") if sys.version_info >= (3, 0) else struct.pack("B", ord("Z")) m[0] = v # CHECK: Zello CU.funcs.dump(pydffi.ptr(A)) UIntTy = FFI.basicType(pydffi.BasicKind.UInt) N = 10 ArrTy = FFI.arrayType(UIntTy, N) Arr=pydffi.CArrayObj(ArrTy) for i in range(N): Arr.set(i, i) for i in range(N): assert(Arr.get(i) == i)
Res Ret = {a,b,res}; return Ret; } static Res add(int a, int b) { return get_res(a+b,a,b); } static Res sub(int a, int b) { return get_res(a-b,a,b); } op get_op(unsigned Id) { if (Id == 0) return add; if (Id == 1) return sub; return 0; } Res call(op f, int a, int b) { return f(a,b); } ''') Add=CU.funcs.get_op(0) Add=Add.obj Res=Add(1,4) assert(Res.res == 5) Res=CU.funcs.call(pydffi.ptr(CU.funcs.sub), 1, 5) assert(Res.res == -4)
# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # RUN: "%python" "%s" | "%FileCheck" "%s" import pydffi FFI = pydffi.FFI() CU = FFI.compile(''' #include <stdio.h> typedef int int2[2]; int foo(int2* ar) { printf("%d %d\\n", ar[0][0], ar[0][1]); } ''') v = CU.types.int2() v.set(0, 1) v.set(1, 2) # CHECK: 1 2 CU.funcs.foo(pydffi.ptr(v)) v[0] = 10 v[1] = 20 # CHECK: 10 20 CU.funcs.foo(pydffi.ptr(v))
fields_name = sorted((f.name for f in A)) assert (fields_name[0] == 'a') assert (fields_name[1] == 'b') Av = CU.types.A(a=1, b=2) # Direct data access throught a memoryview mv = pydffi.view_as_bytes(Av) # Set a throught mv v = 5 if sys.version_info >= (3, 0) else struct.pack("B", 5) mv[0] = v assert (Av.a == 5) assert (Av.b == 2) # CHECK: a=5, b=2 getattr(CU.funcs, "print")(Av) pAv = pydffi.ptr(Av) # CHECK: a=5, b=2 CU.funcs.printptr(pAv) CU.funcs.set(pAv) # CHECK: a=59, b=1111 getattr(CU.funcs, "print")(Av) assert (Av.a == 59) assert (Av.b == 1111) Av = CU.funcs.init() assert (Av.a == 44) assert (Av.b == 5555)
} void strupper(char* S) { bytesupper(S); } ''') print_ = getattr(CU.funcs, "print") print_u8 = CU.funcs.print_u8 bytesupper = CU.funcs.bytesupper strupper = CU.funcs.strupper # CHECK: coucou print_("coucou") # CHECK: héllo print_("héllo") buf = u"héllo".encode("utf8") # CHECK: 68 C3 A9 6C 6C 6F print_u8(buf, len(buf)) buf = bytearray(b"hello") # CHECK: 5 bytesupper(buf) assert(buf == b"HELLO") buf = bytearray(b"hello") buf_char = pydffi.view_as(FFI.arrayType(FFI.UInt8Ty, len(buf)), buf) # CHECK: 5 strupper(pydffi.cast(pydffi.ptr(buf_char),FFI.CharPtrTy)) assert(buf == b"HELLO")
# REQUIRES: linux # RUN: %python "%s" "%S" |%FileCheck "%s" # CHECK: readdir.py import pydffi import sys D = pydffi.FFI() CU = D.cdef("#include <dirent.h>") dir_ = CU.funcs.opendir(sys.argv[1]) if not dir_: print("error reading directory") sys.exit(1) readdir = CU.funcs.readdir while True: dirent = readdir(dir_) if not dirent: break name = dirent.obj.d_name name = pydffi.cast(pydffi.ptr(name), D.CharPtrTy) print(name.cstr.tobytes()) CU.funcs.closedir(dir_)
def cstr_from_array(self, ar): return pydffi.cast(pydffi.ptr(ar), self.FFI.CharPtrTy).cstr
import pydffi import sys pydffi.dlopen("/usr/lib/x86_64-linux-gnu/libarchive.so") D = pydffi.FFI() CU = D.cdef(''' #include <archive.h> #include <archive_entry.h> ''') funcs = CU.funcs archive_read_next_header = funcs.archive_read_next_header archive_entry_pathname_utf8 = funcs.archive_entry_pathname_utf8 archive_read_data_skip = funcs.archive_read_data_skip a = funcs.archive_read_new() funcs.archive_read_support_filter_all(a) funcs.archive_read_support_format_all(a) r = funcs.archive_read_open_filename(a, sys.argv[1], 10240) if r != 0: raise RuntimeError("unable to open archive") entry = pydffi.ptr(CU.types.archive_entry)() while archive_read_next_header(a, pydffi.ptr(entry)) == 0: pathname = archive_entry_pathname_utf8(entry) print(pathname.cstr.tobytes().decode("utf8")) archive_read_data_skip(a) funcs.archive_read_free(a)