Skip to content

Instantly share code, notes, and snippets.

@atoulme
Forked from cleishm/sodium-jnr.py
Created May 28, 2019 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atoulme/d37e62545c68dcddd389f284f779311e to your computer and use it in GitHub Desktop.
Save atoulme/d37e62545c68dcddd389f284f779311e to your computer and use it in GitHub Desktop.
JNR bindings generator for sodium
#!/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")
#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