Last active
May 28, 2019 21:45
-
-
Save cleishm/39fbad03378f5e1ad82521ad821cd065 to your computer and use it in GitHub Desktop.
JNR bindings generator for sodium
This file contains 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 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