-
-
Save atoulme/d37e62545c68dcddd389f284f779311e to your computer and use it in GitHub Desktop.
JNR bindings generator for sodium
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys | |
# This is not required if you've installed pycparser into | |
# your site-packages/ with setup.py | |
sys.path.extend(['.', '..']) | |
from pycparser import c_parser, c_ast, parse_file | |
class JNRRender(c_ast.NodeVisitor): | |
def __init__(self, commented_c_def, interface_decl, delegate_def): | |
self.commented_c_def = commented_c_def | |
self.interface_decl = interface_decl | |
self.delegate_def = delegate_def | |
def visit_FuncDecl(self, n): | |
return_type = '' | |
func_name = '' | |
(func_name, return_type) = self._handle_ptrdecl(n) | |
if self.commented_c_def: | |
sys.stdout.write('// ') | |
sys.stdout.write(return_type) | |
sys.stdout.write(' ') | |
sys.stdout.write(func_name) | |
sys.stdout.write('(') | |
for i, param in enumerate(n.args.params): | |
(param_name, (x, param_type)) = self._handle_param(param) | |
if i: | |
sys.stdout.write(', ') | |
sys.stdout.write(param_type) | |
if param_name is not None: | |
sys.stdout.write(' ') | |
sys.stdout.write(param_name) | |
sys.stdout.write(')') | |
sys.stdout.write(';\n') | |
if self.interface_decl: | |
self._write_jtype(return_type, False) | |
sys.stdout.write(' ') | |
sys.stdout.write(func_name) | |
sys.stdout.write('(') | |
for i, param in enumerate(n.args.params): | |
(param_name, (x, param_type)) = self._handle_param(param) | |
if i: | |
sys.stdout.write(', ') | |
if param_name is None and param_type == 'void': | |
continue | |
else: | |
self._write_jtype(param_type, True) | |
if param_name is not None: | |
sys.stdout.write(' ') | |
sys.stdout.write(param_name) | |
sys.stdout.write(');\n\n') | |
if self.delegate_def: | |
sys.stdout.write('public static ') | |
self._write_jtype(return_type, False, False) | |
sys.stdout.write(' ') | |
sys.stdout.write(func_name) | |
sys.stdout.write('(') | |
for i, param in enumerate(n.args.params): | |
(param_name, (x, param_type)) = self._handle_param(param) | |
if i: | |
sys.stdout.write(', ') | |
if param_name is None and param_type == 'void': | |
continue | |
else: | |
self._write_jtype(param_type, False, False) | |
if param_name is not None: | |
sys.stdout.write(' ') | |
sys.stdout.write(param_name) | |
sys.stdout.write(') {\n') | |
sys.stdout.write(' ') | |
if return_type != 'void': | |
sys.stdout.write('return ') | |
sys.stdout.write('sodium().') | |
sys.stdout.write(func_name) | |
sys.stdout.write('(') | |
for i, param in enumerate(n.args.params): | |
(param_name, (x, param_type)) = self._handle_param(param) | |
if i: | |
sys.stdout.write(', ') | |
if param_name is not None: | |
sys.stdout.write(param_name) | |
sys.stdout.write(');\n}\n\n') | |
def _write_jtype(self, s, show_annot=True, show_qual=True): | |
if s == 'void': | |
self._write_type(None, None, 'void', show_annot, show_qual) | |
elif s == 'int': | |
self._write_type('@In', None, 'int', show_annot, show_qual) | |
elif s == 'const int': | |
self._write_type('@In', None, 'int', show_annot, show_qual) | |
elif s == 'long': | |
self._write_type('@In', '@int32_t', 'int', show_annot, show_qual) | |
elif s == 'const long': | |
self._write_type('@In', '@int32_t', 'int', show_annot, show_qual) | |
elif s == 'size_t': | |
self._write_type('@In', '@ssize_t', 'long', show_annot, show_qual) | |
elif s == 'const size_t': | |
self._write_type('@In', '@ssize_t', 'long', show_annot, show_qual) | |
elif s == 'ssize_t': | |
self._write_type('@In', '@ssize_t', 'long', show_annot, show_qual) | |
elif s == 'unsigned char': | |
self._write_type('@In', '@u_int8_t', 'char', show_annot, show_qual) | |
elif s == 'void *': | |
self._write_type(None, None, 'Pointer', show_annot, show_qual) | |
elif s == 'void *const': | |
self._write_type(None, None, 'Pointer', show_annot, show_qual) | |
elif s == 'const void *const': | |
self._write_type('@In', None, 'byte[]', show_annot, show_qual) | |
elif s == 'const char *': | |
self._write_type('@In', None, 'String', show_annot, show_qual) | |
elif s == 'const char *const': | |
self._write_type('@In', None, 'byte[]', show_annot, show_qual) | |
elif s == 'const uint8_t *': | |
self._write_type('@In', None, 'byte[]', show_annot, show_qual) | |
elif s == 'uint8_t *': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'const unsigned char *const': | |
self._write_type('@In', None, 'byte[]', show_annot, show_qual) | |
elif s == 'const char[]': | |
self._write_type('@In', None, 'byte[]', show_annot, show_qual) | |
elif s == 'char[]': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'char *': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'const unsigned char[]': | |
self._write_type('@In', None, 'byte[]', show_annot, show_qual) | |
elif s == 'unsigned char *': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'unsigned char *': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'unsigned char[]': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'unsigned char *const': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'const unsigned char *': | |
self._write_type('@In', None, 'byte[]', show_annot, show_qual) | |
elif s == 'char *const': | |
self._write_type(None, None, 'byte[]', show_annot, show_qual) | |
elif s == 'uint32_t': | |
self._write_type('@In', '@u_int32_t', 'int', show_annot, show_qual) | |
elif s == 'const uint32_t': | |
self._write_type('@In', '@u_int32_t', 'int', show_annot, show_qual) | |
elif s == 'unsigned long long': | |
self._write_type('@In', '@u_int64_t', 'long', show_annot, show_qual) | |
elif s == 'uint64_t': | |
self._write_type('@In', '@u_int64_t', 'long', show_annot, show_qual) | |
elif s == 'const unsigned long long': | |
self._write_type('@In', '@u_int64_t', 'long', show_annot, show_qual) | |
elif s == 'size_t *': | |
self._write_type('@Out', None, 'LongLongByReference', show_annot, show_qual) | |
elif s == 'size_t *const': | |
self._write_type('@Out', None, 'LongLongByReference', show_annot, show_qual) | |
elif s == 'unsigned long long *': | |
self._write_type('@Out', None, 'LongLongByReference', show_annot, show_qual) | |
elif s == 'const char * *const': | |
self._write_type('@Out', None, 'Pointer', show_annot, show_qual) | |
elif s == 'const crypto_aead_aes256gcm_state *': | |
self._write_type('@In', None, 'Pointer', show_annot, show_qual) | |
elif s == 'crypto_aead_aes256gcm_state *' or \ | |
s == 'crypto_hash_sha512_state *' or \ | |
s == 'crypto_auth_hmacsha512_state *' or \ | |
s == 'crypto_auth_hmacsha512256_state *' or \ | |
s == 'crypto_hash_sha256_state *' or \ | |
s == 'crypto_auth_hmacsha256_state *' or \ | |
s == 'crypto_generichash_blake2b_state *' or \ | |
s == 'crypto_generichash_state *' or \ | |
s == 'crypto_onetimeauth_poly1305_state *' or \ | |
s == 'crypto_onetimeauth_state *' or \ | |
s == 'crypto_secretstream_xchacha20poly1305_state *' or \ | |
s == 'crypto_sign_ed25519ph_state *' or \ | |
s == 'crypto_sign_state *' or \ | |
s == 'randombytes_implementation *': | |
self._write_type(None, None, 'Pointer', show_annot, show_qual) | |
else: | |
raise ValueError('Unknown \'%s\'' % s) | |
def _write_type(self, annotation, qual, typ, show_annot, show_qual): | |
if show_annot: | |
if annotation is not None: | |
sys.stdout.write(annotation); | |
else: | |
sys.stdout.write('/*@In @Out*/') | |
sys.stdout.write(' ') | |
if show_qual and qual is not None: | |
sys.stdout.write(qual) | |
sys.stdout.write(' ') | |
sys.stdout.write(typ) | |
def _handle_ptrdecl(self, p): | |
if type(p.type) == c_ast.PtrDecl: | |
(name, typ) = self._handle_ptrdecl(p.type) | |
typ += ' *' | |
if (p.type.quals): | |
typ += ' '.join(p.type.quals) | |
elif type(p.type) == c_ast.TypeDecl: | |
(name, typ) = self._handle_typedecl(p.type) | |
elif type(p.type) == c_ast.ArrayDecl: | |
(name, typ) = self._handle_ptrdecl(p.type) | |
typ += '[]' # '[' + p.type.dim.value + ']' | |
elif type(p.type) == c_ast.FuncDecl: | |
(name, typ) = self._handle_typedecl(p.type.type) | |
else: | |
raise ValueError("Unhandled type: %s" % p.type); | |
return (name, typ) | |
def _handle_typedecl(self, t): | |
type_name = '' | |
if (t.quals): | |
type_name += ' '.join(t.quals) + ' ' | |
type_name += ' '.join(t.type.names) | |
return (t.declname, type_name) | |
def _handle_param(self, p): | |
param_type = (None, None) | |
param_name = None | |
if type(p) == c_ast.Typename: | |
if p.name is None: | |
param_type = self._handle_ptrdecl(p) | |
else: | |
raise ValueError('Cant handle typename: %s' % typ) | |
elif type(p) == c_ast.Decl: | |
(param_name, param_type) = self._handle_ptrdecl(p) | |
param_type = (None, param_type) | |
else: | |
raise ValueError('Unknown param type: %s' % typ) | |
return (param_name, param_type) | |
if __name__ == "__main__": | |
if len(sys.argv) > 1: | |
ast = parse_file(sys.argv[1], use_cpp=True, | |
cpp_path='gcc', | |
cpp_args=['-E', r'-Iutils/fake_libc_include']) | |
print('public class Sodium {') | |
v = JNRRender(True, True, False) | |
print(' private interface LibSodium {') | |
v.visit(ast) | |
print(' }') | |
print('') | |
v = JNRRender(False, False, True) | |
v.visit(ast) | |
print('}') | |
else: | |
print("Please provide a filename as argument") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define __attribute__(x) | |
#define SODIUM_STATIC | |
#include "/usr/local/Cellar/libsodium/1.0.16/include/sodium.h" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment