mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-18 11:38:08 +00:00
Added C# wrapper
This commit is contained in:
parent
eec47ba456
commit
e28468f05f
3 changed files with 1759 additions and 0 deletions
831
wrappers/csharp/abstractapi.py
Normal file
831
wrappers/csharp/abstractapi.py
Normal file
|
|
@ -0,0 +1,831 @@
|
|||
# Copyright (C) 2017 Belledonne Communications SARL
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
import re
|
||||
import genapixml as CApi
|
||||
|
||||
|
||||
class Error(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class BlacklistedException(Error):
|
||||
pass
|
||||
|
||||
|
||||
class Name(object):
|
||||
camelCaseParsingRegex = re.compile('[A-Z][a-z0-9]*')
|
||||
lowerCamelCaseSplitingRegex = re.compile('([a-z][a-z0-9]*)([A-Z][a-z0-9]*)')
|
||||
|
||||
def __init__(self):
|
||||
self.words = []
|
||||
self.prev = None
|
||||
|
||||
def copy(self):
|
||||
nameType = type(self)
|
||||
name = nameType()
|
||||
name.words = list(self.words)
|
||||
name.prev = None if self.prev is None else self.prev.copy()
|
||||
return name
|
||||
|
||||
def delete_prefix(self, prefix):
|
||||
it = self
|
||||
_next = None
|
||||
while it is not None and it.words != prefix.words:
|
||||
_next = it
|
||||
it = it.prev
|
||||
|
||||
if it is None or it != prefix:
|
||||
raise Error('no common prefix')
|
||||
elif _next is not None:
|
||||
_next.prev = None
|
||||
|
||||
def _set_namespace(self, namespace):
|
||||
self.prev = namespace
|
||||
if self.prev is not None:
|
||||
prefix = namespace.to_word_list()
|
||||
i = 0
|
||||
while i<len(self.words) and i<len(prefix) and self.words[i] == prefix[i]:
|
||||
i += 1
|
||||
if i == len(self.words):
|
||||
raise Error('name equal to namespace \'{0}\'', self.words)
|
||||
else:
|
||||
self.words = self.words[i:]
|
||||
|
||||
def _lower_all_words(self):
|
||||
i = 0
|
||||
while i<len(self.words):
|
||||
self.words[i] = self.words[i].lower()
|
||||
i += 1
|
||||
|
||||
def from_snake_case(self, name, namespace=None):
|
||||
self.words = name.split('_')
|
||||
Name._set_namespace(self, namespace)
|
||||
|
||||
def from_camel_case(self, name, islowercased=False, namespace=None):
|
||||
if not islowercased:
|
||||
self.words = Name.camelCaseParsingRegex.findall(name)
|
||||
else:
|
||||
match = Name.lowerCamelCaseSplitingRegex.match(name)
|
||||
self.words = [match.group(1)]
|
||||
self.words += Name.camelCaseParsingRegex.findall(match.group(2))
|
||||
|
||||
Name._lower_all_words(self)
|
||||
Name._set_namespace(self, namespace)
|
||||
|
||||
def to_snake_case(self, fullName=False, upper=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = '_'.join(self.words)
|
||||
if upper:
|
||||
res = res.upper()
|
||||
return res
|
||||
else:
|
||||
return Name.to_snake_case(self.prev, fullName=True, upper=upper) + '_' + Name.to_snake_case(self, upper=upper)
|
||||
|
||||
def to_camel_case(self, lower=False, fullName=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = ''
|
||||
for elem in self.words:
|
||||
if elem is self.words[0] and lower:
|
||||
res += elem
|
||||
else:
|
||||
res += elem.title()
|
||||
return res
|
||||
else:
|
||||
return Name.to_camel_case(self.prev, fullName=True, lower=lower) + Name.to_camel_case(self)
|
||||
|
||||
def concatenate(self, upper=False, fullName=False):
|
||||
if self.prev is None or not fullName:
|
||||
res = ''
|
||||
for elem in self.words:
|
||||
if upper:
|
||||
res += elem.upper()
|
||||
else:
|
||||
res += elem
|
||||
return res
|
||||
else:
|
||||
return Name.concatenate(self.prev, upper=upper, fullName=True) + Name.concatenate(self, upper=upper)
|
||||
|
||||
def to_word_list(self):
|
||||
if self.prev is None:
|
||||
return list(self.words)
|
||||
else:
|
||||
return Name.to_word_list(self.prev) + self.words
|
||||
|
||||
@staticmethod
|
||||
def find_common_parent(name1, name2):
|
||||
if name1.prev is None or name2.prev is None:
|
||||
return None
|
||||
elif name1.prev is name2.prev:
|
||||
return name1.prev
|
||||
else:
|
||||
commonParent = Name.find_common_parent(name1.prev, name2)
|
||||
if commonParent is not None:
|
||||
return commonParent
|
||||
else:
|
||||
return Name.find_common_parent(name1, name2.prev)
|
||||
|
||||
|
||||
class ClassName(Name):
|
||||
def to_c(self):
|
||||
return Name.to_camel_case(self, fullName=True)
|
||||
|
||||
|
||||
class InterfaceName(ClassName):
|
||||
def to_c(self):
|
||||
return ClassName.to_c(self)[:-8] + 'Cbs'
|
||||
|
||||
|
||||
class EnumName(ClassName):
|
||||
pass
|
||||
|
||||
|
||||
class EnumValueName(ClassName):
|
||||
pass
|
||||
|
||||
|
||||
class MethodName(Name):
|
||||
regex = re.compile('^\d+$')
|
||||
|
||||
def __init__(self):
|
||||
self.overloadRef = 0
|
||||
|
||||
def from_snake_case(self, name, namespace=None):
|
||||
Name.from_snake_case(self, name, namespace=namespace)
|
||||
if len(self.words) > 0:
|
||||
suffix = self.words[-1]
|
||||
if MethodName.regex.match(suffix) is not None:
|
||||
self.overloadRef = int(suffix)
|
||||
del self.words[-1]
|
||||
|
||||
def to_c(self):
|
||||
suffix = ('_' + str(self.overloadRef)) if self.overloadRef > 0 else ''
|
||||
return self.to_snake_case(fullName=True) + suffix
|
||||
|
||||
|
||||
class ArgName(Name):
|
||||
def to_c(self):
|
||||
return self.to_snake_case()
|
||||
|
||||
|
||||
class PropertyName(ArgName):
|
||||
pass
|
||||
|
||||
|
||||
class NamespaceName(Name):
|
||||
def __init__(self, *params):
|
||||
Name.__init__(self)
|
||||
if len(params) > 0:
|
||||
self.words = params[0]
|
||||
|
||||
|
||||
class Object(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.parent = None
|
||||
self.deprecated = False
|
||||
|
||||
def find_first_ancestor_by_type(self, _type):
|
||||
ancestor = self.parent
|
||||
while ancestor is not None and type(ancestor) is not _type:
|
||||
ancestor = ancestor.parent
|
||||
return ancestor
|
||||
|
||||
|
||||
class Type(Object):
|
||||
def __init__(self, name, isconst=False, isref=False):
|
||||
Object.__init__(self, name)
|
||||
self.isconst = isconst
|
||||
self.isref = isref
|
||||
self.cname = None
|
||||
|
||||
|
||||
class BaseType(Type):
|
||||
def __init__(self, name, isconst=False, isref=False, size=None, isUnsigned=False):
|
||||
Type.__init__(self, name, isconst=isconst, isref=isref)
|
||||
self.size = size
|
||||
self.isUnsigned = isUnsigned
|
||||
|
||||
|
||||
class EnumType(Type):
|
||||
def __init__(self, name, isconst=False, isref=False, enumDesc=None):
|
||||
Type.__init__(self, name, isconst=isconst, isref=isref)
|
||||
self.desc = enumDesc
|
||||
|
||||
|
||||
class ClassType(Type):
|
||||
def __init__(self, name, isconst=False, isref=False, classDesc=None):
|
||||
Type.__init__(self, name, isconst=isconst, isref=isref)
|
||||
self.desc = classDesc
|
||||
|
||||
|
||||
class ListType(Type):
|
||||
def __init__(self, containedTypeName, isconst=False, isref=False):
|
||||
Type.__init__(self, 'list', isconst=isconst, isref=isref)
|
||||
self.containedTypeName = containedTypeName
|
||||
self._containedTypeDesc = None
|
||||
|
||||
def set_contained_type_desc(self, desc):
|
||||
self._containedTypeDesc = desc
|
||||
desc.parent = self
|
||||
|
||||
def get_contained_type_desc(self):
|
||||
return self._containedTypeDesc
|
||||
|
||||
containedTypeDesc = property(fset=set_contained_type_desc, fget=get_contained_type_desc)
|
||||
|
||||
|
||||
class DocumentableObject(Object):
|
||||
def __init__(self, name):
|
||||
Object.__init__(self, name)
|
||||
self.briefDescription = None
|
||||
self.detailedDescription = None
|
||||
self.deprecated = None
|
||||
|
||||
def set_from_c(self, cObject, namespace=None):
|
||||
self.briefDescription = cObject.briefDescription
|
||||
self.detailedDescription = cObject.detailedDescription
|
||||
self.deprecated = cObject.deprecated
|
||||
self.parent = namespace
|
||||
|
||||
def get_namespace_object(self):
|
||||
if isinstance(self, (Namespace,Enum,Class)):
|
||||
return self
|
||||
elif self.parent is None:
|
||||
raise Error('{0} is not attached to a namespace object'.format(self))
|
||||
else:
|
||||
return self.parent.get_namespace_object()
|
||||
|
||||
|
||||
class Namespace(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.children = []
|
||||
|
||||
def add_child(self, child):
|
||||
self.children.append(child)
|
||||
child.parent = self
|
||||
|
||||
|
||||
class Flag:
|
||||
def __init__(self, position):
|
||||
self.position = position
|
||||
|
||||
|
||||
class EnumValue(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.value = None
|
||||
|
||||
def value_from_string(self, stringValue):
|
||||
m = re.match('^1\s*<<\s*([0-9]+)$', stringValue)
|
||||
if m is not None:
|
||||
self.value = Flag(int(m.group(1)))
|
||||
else:
|
||||
self.value = int(stringValue, base=0)
|
||||
|
||||
|
||||
class Enum(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.values = []
|
||||
|
||||
def add_value(self, value):
|
||||
self.values.append(value)
|
||||
value.parent = self
|
||||
|
||||
def set_from_c(self, cEnum, namespace=None):
|
||||
Object.set_from_c(self, cEnum, namespace=namespace)
|
||||
|
||||
if 'associatedTypedef' in dir(cEnum):
|
||||
name = cEnum.associatedTypedef.name
|
||||
else:
|
||||
name = cEnum.name
|
||||
|
||||
self.name = EnumName()
|
||||
self.name.prev = None if namespace is None else namespace.name
|
||||
self.name.set_from_c(name)
|
||||
|
||||
for cEnumValue in cEnum.values:
|
||||
aEnumValue = EnumValue()
|
||||
aEnumValue.set_from_c(cEnumValue, namespace=self)
|
||||
self.add_value(aEnumValue)
|
||||
|
||||
|
||||
class Argument(DocumentableObject):
|
||||
def __init__(self, name, argType, optional=False, default=None):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self._type = argType
|
||||
argType.parent = self
|
||||
self.optional = optional
|
||||
self.default = default
|
||||
|
||||
def _set_type(self, _type):
|
||||
self._type = _type
|
||||
_type.parent = self
|
||||
|
||||
def _get_type(self):
|
||||
return self._type
|
||||
|
||||
type = property(fset=_set_type, fget=_get_type)
|
||||
|
||||
|
||||
class Method(DocumentableObject):
|
||||
class Type:
|
||||
Instance = 0,
|
||||
Class = 1
|
||||
|
||||
def __init__(self, name, type=Type.Instance):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.type = type
|
||||
self.constMethod = False
|
||||
self.args = []
|
||||
self._returnType = None
|
||||
|
||||
def _set_return_type(self, returnType):
|
||||
self._returnType = returnType
|
||||
returnType.parent = self
|
||||
|
||||
def _get_return_type(self):
|
||||
return self._returnType
|
||||
|
||||
def add_arguments(self, arg):
|
||||
self.args.append(arg)
|
||||
arg.parent = self
|
||||
|
||||
returnType = property(fset=_set_return_type, fget=_get_return_type)
|
||||
|
||||
|
||||
class Property(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self._setter = None
|
||||
self._getter = None
|
||||
self._type = None
|
||||
|
||||
def set_setter(self, setter):
|
||||
self._setter = setter
|
||||
setter.parent = self
|
||||
|
||||
def get_setter(self):
|
||||
return self._setter
|
||||
|
||||
def set_getter(self, getter):
|
||||
self._getter = getter
|
||||
if self._type is None:
|
||||
self._type = getter.returnType
|
||||
getter.parent = self
|
||||
|
||||
def get_getter(self):
|
||||
return self._getter
|
||||
|
||||
setter = property(fset=set_setter, fget=get_setter)
|
||||
getter = property(fset=set_getter, fget=get_getter)
|
||||
|
||||
|
||||
class Class(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.properties = []
|
||||
self.instanceMethods = []
|
||||
self.classMethods = []
|
||||
self._listenerInterface = None
|
||||
self.multilistener = False
|
||||
self.refcountable = False
|
||||
|
||||
def add_property(self, property):
|
||||
self.properties.append(property)
|
||||
property.parent = self
|
||||
|
||||
def add_instance_method(self, method):
|
||||
self.instanceMethods.append(method)
|
||||
method.parent = self
|
||||
|
||||
def add_class_method(self, method):
|
||||
self.classMethods.append(method)
|
||||
method.parent = self
|
||||
|
||||
def set_listener_interface(self, interface):
|
||||
self._listenerInterface = interface
|
||||
interface._listenedClass = self
|
||||
|
||||
def get_listener_interface(self):
|
||||
return self._listenerInterface
|
||||
|
||||
listenerInterface = property(fget=get_listener_interface, fset=set_listener_interface)
|
||||
|
||||
|
||||
class Interface(DocumentableObject):
|
||||
def __init__(self, name):
|
||||
DocumentableObject.__init__(self, name)
|
||||
self.methods = []
|
||||
self._listenedClass = None
|
||||
|
||||
def add_method(self, method):
|
||||
self.methods.append(method)
|
||||
method.parent = self
|
||||
|
||||
def get_listened_class(self):
|
||||
return self._listenedClass
|
||||
|
||||
listenedClass = property(fget=get_listened_class)
|
||||
|
||||
|
||||
class CParser(object):
|
||||
def __init__(self, cProject):
|
||||
self.cBaseType = ['void', 'bool_t', 'char', 'short', 'int', 'long', 'size_t', 'time_t', 'float', 'double', 'LinphoneStatus']
|
||||
self.cListType = 'bctbx_list_t'
|
||||
self.regexFixedSizeInteger = '^(u?)int(\d?\d)_t$'
|
||||
self.methodBl = ['ref', 'unref', 'new', 'destroy', 'getCurrentCallbacks', 'setUserData', 'getUserData']
|
||||
self.functionBl = [
|
||||
'linphone_vcard_get_belcard'] # manualy wrapped
|
||||
|
||||
self.classBl = ['LpConfig',
|
||||
'LinphonePlayer',
|
||||
'LinphoneIntRange',
|
||||
'LinphoneCallStats',
|
||||
'LinphoneCoreVTable',
|
||||
'LinphoneVideoPolicy',
|
||||
'LinphoneSipTransports'] # temporarly blacklisted
|
||||
|
||||
# list of classes that must be concidered as refcountable even if
|
||||
# they are no ref()/unref() methods
|
||||
self.forcedRefcountableClasses = ['LinphoneFactory']
|
||||
|
||||
self.cProject = cProject
|
||||
|
||||
self.enumsIndex = {}
|
||||
for enum in self.cProject.enums:
|
||||
if enum.associatedTypedef is None:
|
||||
self.enumsIndex[enum.name] = None
|
||||
else:
|
||||
self.enumsIndex[enum.associatedTypedef.name] = None
|
||||
|
||||
self.classesIndex = {}
|
||||
self.interfacesIndex = {}
|
||||
for _class in self.cProject.classes:
|
||||
if _class.name not in self.classBl:
|
||||
if _class.name.endswith('Cbs'):
|
||||
self.interfacesIndex[_class.name] = None
|
||||
else:
|
||||
self.classesIndex[_class.name] = None
|
||||
|
||||
name = NamespaceName()
|
||||
name.from_snake_case('linphone')
|
||||
|
||||
self.namespace = Namespace(name)
|
||||
|
||||
def _is_blacklisted(self, name):
|
||||
if type(name) is MethodName:
|
||||
return name.to_camel_case(lower=True) in self.methodBl or name.to_c() in self.functionBl
|
||||
elif type(name) is ClassName:
|
||||
return name.to_c() in self.classBl
|
||||
else:
|
||||
return False
|
||||
|
||||
def parse_all(self):
|
||||
for enum in self.cProject.enums:
|
||||
try:
|
||||
self.parse_enum(enum)
|
||||
except Error as e:
|
||||
print('Could not parse \'{0}\' enum: {1}'.format(enum.name, e.args[0]))
|
||||
|
||||
for _class in self.cProject.classes:
|
||||
try:
|
||||
self.parse_class(_class)
|
||||
except BlacklistedException:
|
||||
pass
|
||||
except Error as e:
|
||||
print('Could not parse \'{0}\' class: {1}'.format(_class.name, e.args[0]))
|
||||
|
||||
self._fix_all_types()
|
||||
|
||||
|
||||
def _class_is_refcountable(self, _class):
|
||||
if _class.name in self.forcedRefcountableClasses:
|
||||
return True
|
||||
|
||||
for method in _class.instanceMethods:
|
||||
if method.startswith(_class.cFunctionPrefix) and method[len(_class.cFunctionPrefix):] == 'ref':
|
||||
return True
|
||||
return False
|
||||
|
||||
def _fix_all_types_in_class_or_interface(self, _class):
|
||||
if _class is not None:
|
||||
if type(_class) is Class:
|
||||
self._fix_all_types_in_class(_class)
|
||||
else:
|
||||
self._fix_all_types_in_interface(_class)
|
||||
|
||||
def _fix_all_types(self):
|
||||
for _class in self.interfacesIndex.values():
|
||||
self._fix_all_types_in_class_or_interface(_class)
|
||||
for _class in self.classesIndex.values():
|
||||
self._fix_all_types_in_class_or_interface(_class)
|
||||
|
||||
def _fix_all_types_in_class(self, _class):
|
||||
for property in _class.properties:
|
||||
if property.setter is not None:
|
||||
self._fix_all_types_in_method(property.setter)
|
||||
if property.getter is not None:
|
||||
self._fix_all_types_in_method(property.getter)
|
||||
|
||||
for method in (_class.instanceMethods + _class.classMethods):
|
||||
self._fix_all_types_in_method(method)
|
||||
|
||||
def _fix_all_types_in_interface(self, interface):
|
||||
for method in interface.methods:
|
||||
self._fix_all_types_in_method(method)
|
||||
|
||||
def _fix_all_types_in_method(self, method):
|
||||
try:
|
||||
self._fix_type(method.returnType)
|
||||
for arg in method.args:
|
||||
self._fix_type(arg.type)
|
||||
except Error as e:
|
||||
print('warning: some types could not be fixed in {0}() function: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
|
||||
|
||||
def _fix_type(self, _type):
|
||||
if isinstance(_type, EnumType) and _type.desc is None:
|
||||
_type.desc = self.enumsIndex[_type.name]
|
||||
elif isinstance(_type, ClassType) and _type.desc is None:
|
||||
if _type.name in self.classesIndex:
|
||||
_type.desc = self.classesIndex[_type.name]
|
||||
else:
|
||||
_type.desc = self.interfacesIndex[_type.name]
|
||||
elif isinstance(_type, ListType) and _type.containedTypeDesc is None:
|
||||
if _type.containedTypeName in self.classesIndex:
|
||||
_type.containedTypeDesc = ClassType(_type.containedTypeName, classDesc=self.classesIndex[_type.containedTypeName])
|
||||
elif _type.containedTypeName in self.interfacesIndex:
|
||||
_type.containedTypeDesc = ClassType(_type.containedTypeName, classDesc=self.interfacesIndex[_type.containedTypeName])
|
||||
elif _type.containedTypeName in self.enumsIndex:
|
||||
_type.containedTypeDesc = EnumType(_type.containedTypeName, enumDesc=self.enumsIndex[_type.containedTypeName])
|
||||
else:
|
||||
if _type.containedTypeName is not None:
|
||||
_type.containedTypeDesc = self.parse_c_base_type(_type.containedTypeName)
|
||||
else:
|
||||
raise Error('bctbx_list_t type without specified contained type')
|
||||
|
||||
def parse_enum(self, cenum):
|
||||
if 'associatedTypedef' in dir(cenum):
|
||||
nameStr = cenum.associatedTypedef.name
|
||||
else:
|
||||
nameStr = cenum.name
|
||||
|
||||
name = EnumName()
|
||||
name.from_camel_case(nameStr, namespace=self.namespace.name)
|
||||
enum = Enum(name)
|
||||
self.namespace.add_child(enum)
|
||||
|
||||
for cEnumValue in cenum.values:
|
||||
valueName = EnumValueName()
|
||||
valueName.from_camel_case(cEnumValue.name, namespace=name)
|
||||
aEnumValue = EnumValue(valueName)
|
||||
if cEnumValue.value is not None:
|
||||
try:
|
||||
aEnumValue.value_from_string(cEnumValue.value)
|
||||
except ValueError:
|
||||
raise Error('{0} enum value has an invalid definition ({1})'.format(cEnumValue.name, cEnumValue.value))
|
||||
enum.add_value(aEnumValue)
|
||||
|
||||
self.enumsIndex[nameStr] = enum
|
||||
return enum
|
||||
|
||||
def parse_class(self, cclass):
|
||||
if cclass.name in self.classBl:
|
||||
raise BlacklistedException('{0} is blacklisted'.format(cclass.name));
|
||||
|
||||
if cclass.name.endswith('Cbs'):
|
||||
_class = self._parse_listener(cclass)
|
||||
self.interfacesIndex[cclass.name] = _class
|
||||
else:
|
||||
_class = self._parse_class(cclass)
|
||||
self.classesIndex[cclass.name] = _class
|
||||
self.namespace.add_child(_class)
|
||||
return _class
|
||||
|
||||
def _parse_class(self, cclass):
|
||||
name = ClassName()
|
||||
name.from_camel_case(cclass.name, namespace=self.namespace.name)
|
||||
_class = Class(name)
|
||||
_class.refcountable = self._class_is_refcountable(cclass)
|
||||
|
||||
for cproperty in cclass.properties.values():
|
||||
try:
|
||||
if cproperty.name != 'callbacks':
|
||||
absProperty = self._parse_property(cproperty, namespace=name)
|
||||
_class.add_property(absProperty)
|
||||
else:
|
||||
_class.listenerInterface = self.interfacesIndex[cproperty.getter.returnArgument.ctype]
|
||||
except Error as e:
|
||||
print('Could not parse {0} property in {1}: {2}'.format(cproperty.name, cclass.name, e.args[0]))
|
||||
|
||||
for cMethod in cclass.instanceMethods.values():
|
||||
try:
|
||||
method = self.parse_method(cMethod, namespace=name)
|
||||
if method.name.to_snake_case() == 'add_callbacks' or method.name.to_snake_case() == 'remove_callbacks':
|
||||
if _class.listenerInterface is None or not _class.multilistener:
|
||||
_class.multilistener = True
|
||||
_class.listenerInterface = self.interfacesIndex[_class.name.to_camel_case(fullName=True) + 'Cbs']
|
||||
elif isinstance(method.returnType, ClassType) and method.returnType.name.endswith('Cbs'):
|
||||
pass
|
||||
else:
|
||||
_class.add_instance_method(method)
|
||||
|
||||
except BlacklistedException:
|
||||
pass
|
||||
except Error as e:
|
||||
print('Could not parse {0} function: {1}'.format(cMethod.name, e.args[0]))
|
||||
|
||||
for cMethod in cclass.classMethods.values():
|
||||
try:
|
||||
method = self.parse_method(cMethod, type=Method.Type.Class, namespace=name)
|
||||
_class.add_class_method(method)
|
||||
except BlacklistedException:
|
||||
pass
|
||||
except Error as e:
|
||||
print('Could not parse {0} function: {1}'.format(cMethod.name, e.args[0]))
|
||||
|
||||
return _class
|
||||
|
||||
def _parse_property(self, cproperty, namespace=None):
|
||||
name = PropertyName()
|
||||
name.from_snake_case(cproperty.name)
|
||||
if (cproperty.setter is not None and len(cproperty.setter.arguments) == 1) or (cproperty.getter is not None and len(cproperty.getter.arguments) == 0):
|
||||
methodType = Method.Type.Class
|
||||
else:
|
||||
methodType = Method.Type.Instance
|
||||
aproperty = Property(name)
|
||||
if cproperty.setter is not None:
|
||||
method = self.parse_method(cproperty.setter, namespace=namespace, type=methodType)
|
||||
aproperty.setter = method
|
||||
if cproperty.getter is not None:
|
||||
method = self.parse_method(cproperty.getter, namespace=namespace, type=methodType)
|
||||
aproperty.getter = method
|
||||
return aproperty
|
||||
|
||||
|
||||
def _parse_listener(self, cclass):
|
||||
name = InterfaceName()
|
||||
name.from_camel_case(cclass.name, namespace=self.namespace.name)
|
||||
|
||||
if name.words[len(name.words)-1] == 'cbs':
|
||||
name.words[len(name.words)-1] = 'listener'
|
||||
else:
|
||||
raise Error('{0} is not a listener'.format(cclass.name))
|
||||
|
||||
listener = Interface(name)
|
||||
|
||||
for property in cclass.properties.values():
|
||||
if property.name != 'user_data':
|
||||
try:
|
||||
method = self._parse_listener_property(property, listener, cclass.events)
|
||||
listener.add_method(method)
|
||||
except Error as e:
|
||||
print('Could not parse property \'{0}\' of listener \'{1}\': {2}'.format(property.name, cclass.name, e.args[0]))
|
||||
|
||||
return listener
|
||||
|
||||
def _parse_listener_property(self, property, listener, events):
|
||||
methodName = MethodName()
|
||||
methodName.from_snake_case(property.name)
|
||||
methodName.words.insert(0, 'on')
|
||||
methodName.prev = listener.name
|
||||
|
||||
if property.getter is not None:
|
||||
eventName = property.getter.returnArgument.ctype
|
||||
elif property.setter is not None and len(property.setter.arguments) == 2:
|
||||
eventName = property.setter.arguments[1].ctype
|
||||
else:
|
||||
raise Error('event name for {0} property of {1} listener not found'.format(property.name, listener.name.to_snake_case(fullName=True)))
|
||||
|
||||
try:
|
||||
event = events[eventName]
|
||||
except KeyError:
|
||||
raise Error('invalid event name \'{0}\''.format(eventName))
|
||||
|
||||
method = Method(methodName)
|
||||
method.returnType = self.parse_type(event.returnArgument)
|
||||
for arg in event.arguments:
|
||||
argName = ArgName()
|
||||
argName.from_snake_case(arg.name)
|
||||
argument = Argument(argName, self.parse_type(arg))
|
||||
method.add_arguments(argument)
|
||||
|
||||
return method
|
||||
|
||||
def parse_method(self, cfunction, namespace, type=Method.Type.Instance):
|
||||
name = MethodName()
|
||||
name.from_snake_case(cfunction.name, namespace=namespace)
|
||||
|
||||
if self._is_blacklisted(name):
|
||||
raise BlacklistedException('{0} is blacklisted'.format(name.to_c()));
|
||||
|
||||
method = Method(name, type=type)
|
||||
method.deprecated = cfunction.deprecated
|
||||
method.returnType = self.parse_type(cfunction.returnArgument)
|
||||
|
||||
for arg in cfunction.arguments:
|
||||
if type == Method.Type.Instance and arg is cfunction.arguments[0]:
|
||||
method.constMethod = ('const' in arg.completeType.split(' '))
|
||||
else:
|
||||
aType = self.parse_type(arg)
|
||||
argName = ArgName()
|
||||
argName.from_snake_case(arg.name)
|
||||
absArg = Argument(argName, aType)
|
||||
method.add_arguments(absArg)
|
||||
|
||||
return method
|
||||
|
||||
def parse_type(self, cType):
|
||||
if cType.ctype in self.cBaseType or re.match(self.regexFixedSizeInteger, cType.ctype):
|
||||
absType = self.parse_c_base_type(cType.completeType)
|
||||
elif cType.ctype in self.enumsIndex:
|
||||
absType = EnumType(cType.ctype, enumDesc=self.enumsIndex[cType.ctype])
|
||||
elif cType.ctype in self.classesIndex or cType.ctype in self.interfacesIndex:
|
||||
absType = ClassType(cType.ctype)
|
||||
absType.isconst = cType.completeType.startswith('const ')
|
||||
absType.isref = cType.completeType.endswith('*')
|
||||
elif cType.ctype == self.cListType:
|
||||
absType = ListType(cType.containedType)
|
||||
else:
|
||||
raise Error('Unknown C type \'{0}\''.format(cType.ctype))
|
||||
|
||||
absType.cname = cType.completeType
|
||||
return absType
|
||||
|
||||
def parse_c_base_type(self, cDecl):
|
||||
declElems = cDecl.split(' ')
|
||||
param = {}
|
||||
name = None
|
||||
for elem in declElems:
|
||||
if elem == 'const':
|
||||
if name is None:
|
||||
param['isconst'] = True
|
||||
elif elem == 'unsigned':
|
||||
param['isUnsigned'] = True
|
||||
elif elem == 'char':
|
||||
name = 'character'
|
||||
elif elem == 'void':
|
||||
name = 'void'
|
||||
elif elem == 'bool_t':
|
||||
name = 'boolean'
|
||||
elif elem in ['short', 'long']:
|
||||
param['size'] = elem
|
||||
elif elem == 'int':
|
||||
name = 'integer'
|
||||
elif elem == 'float':
|
||||
name = 'floatant'
|
||||
param['size'] = 'float'
|
||||
elif elem == 'size_t':
|
||||
name = 'size'
|
||||
elif elem == 'time_t':
|
||||
name = 'time'
|
||||
elif elem == 'double':
|
||||
name = 'floatant'
|
||||
if 'size' in param and param['size'] == 'long':
|
||||
param['size'] = 'long double'
|
||||
else:
|
||||
param['size'] = 'double'
|
||||
elif elem == 'LinphoneStatus':
|
||||
name = 'status'
|
||||
elif elem == '*':
|
||||
if name is not None:
|
||||
if name == 'character':
|
||||
name = 'string'
|
||||
elif name == 'string':
|
||||
name = 'string_array'
|
||||
elif 'isref' not in param or param['isref'] is False:
|
||||
param['isref'] = True
|
||||
else:
|
||||
raise Error('Unhandled double-pointer')
|
||||
else:
|
||||
matchCtx = re.match(self.regexFixedSizeInteger, elem)
|
||||
if matchCtx:
|
||||
name = 'integer'
|
||||
if matchCtx.group(1) == 'u':
|
||||
param['isUnsigned'] = True
|
||||
|
||||
param['size'] = int(matchCtx.group(2))
|
||||
if param['size'] not in [8, 16, 32, 64]:
|
||||
raise Error('{0} C basic type has an invalid size ({1})'.format(cDecl, param['size']))
|
||||
|
||||
|
||||
if name is not None:
|
||||
return BaseType(name, **param)
|
||||
else:
|
||||
raise Error('could not find type in \'{0}\''.format(cDecl))
|
||||
590
wrappers/csharp/genwrapper.py
Normal file
590
wrappers/csharp/genwrapper.py
Normal file
|
|
@ -0,0 +1,590 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) 2017 Belledonne Communications SARL
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import pystache
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'tools'))
|
||||
print sys.path
|
||||
import genapixml as CApi
|
||||
import abstractapi as AbsApi
|
||||
|
||||
class CsharpTranslator(object):
|
||||
def __init__(self):
|
||||
self.ignore = []
|
||||
|
||||
def init_method_dict(self):
|
||||
methodDict = {}
|
||||
methodDict['has_impl'] = True
|
||||
methodDict['impl'] = {}
|
||||
methodDict['is_string_list'] = False
|
||||
methodDict['is_class_list'] = False
|
||||
methodDict['list_type'] = None
|
||||
methodDict['is_string'] = False
|
||||
methodDict['is_bool'] = False
|
||||
methodDict['is_class'] = False
|
||||
methodDict['is_enum'] = False
|
||||
methodDict['is_generic'] = False
|
||||
methodDict['takeRef'] = 'true'
|
||||
return methodDict
|
||||
|
||||
def get_class_array_type(self, name):
|
||||
length = len(name)
|
||||
if length > 11 and name[:11] == 'IEnumerable':
|
||||
return name[12:length-1]
|
||||
return None
|
||||
|
||||
def is_generic(self, methodDict):
|
||||
return not methodDict['is_string'] and not methodDict['is_bool'] and not methodDict['is_class'] and not methodDict['is_enum'] and methodDict['list_type'] == None
|
||||
|
||||
def translate_method_name(self, name, recursive=False, topAncestor=None):
|
||||
translatedName = name.to_camel_case(lower=True)
|
||||
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return translatedName
|
||||
|
||||
def translate_argument_name(self, name):
|
||||
argname = name.to_camel_case(lower=True)
|
||||
arg = argname
|
||||
if argname == "params":
|
||||
arg = "parameters"
|
||||
elif argname == "event":
|
||||
arg = "ev"
|
||||
elif argname == "ref":
|
||||
arg = "reference"
|
||||
elif argname == "value":
|
||||
arg = "val"
|
||||
return arg
|
||||
|
||||
def translate_base_type(self, _type, isArg, dllImport=True):
|
||||
if _type.name == 'void':
|
||||
if _type.isref:
|
||||
return 'IntPtr'
|
||||
return 'void'
|
||||
elif _type.name == 'status':
|
||||
if dllImport:
|
||||
return 'int'
|
||||
else:
|
||||
return 'void'
|
||||
elif _type.name == 'boolean':
|
||||
if dllImport:
|
||||
res = 'int' # In C the bool_t is an integer
|
||||
else:
|
||||
res = 'bool'
|
||||
elif _type.name == 'integer':
|
||||
if _type.isUnsigned:
|
||||
res = 'uint'
|
||||
else:
|
||||
res = 'int'
|
||||
elif _type.name == 'string':
|
||||
if dllImport:
|
||||
if isArg:
|
||||
return 'string'
|
||||
else:
|
||||
res = 'IntPtr' # Return as IntPtr and get string with Marshal.PtrToStringAnsi()
|
||||
else:
|
||||
return 'string'
|
||||
elif _type.name == 'character':
|
||||
if _type.isUnsigned:
|
||||
res = 'byte'
|
||||
else:
|
||||
res = 'sbyte'
|
||||
elif _type.name == 'time':
|
||||
res = 'long' #TODO check
|
||||
elif _type.name == 'size':
|
||||
res = 'long' #TODO check
|
||||
elif _type.name == 'floatant':
|
||||
return 'float'
|
||||
elif _type.name == 'string_array':
|
||||
if dllImport or isArg:
|
||||
return 'IntPtr'
|
||||
else:
|
||||
return 'IEnumerable<string>'
|
||||
else:
|
||||
raise AbsApi.Error('\'{0}\' is not a base abstract type'.format(_type.name))
|
||||
|
||||
return res
|
||||
|
||||
def is_linphone_type(self, _type, isArg, dllImport=True):
|
||||
if type(_type) is AbsApi.ClassType:
|
||||
return False if dllImport else True
|
||||
elif type(_type) is AbsApi.EnumType:
|
||||
return False if dllImport else True
|
||||
|
||||
def translate_type(self, _type, isArg, dllImport=True):
|
||||
if type(_type) is AbsApi.EnumType:
|
||||
if dllImport and isArg:
|
||||
return 'int'
|
||||
return _type.desc.name.to_camel_case()
|
||||
elif type(_type) is AbsApi.ClassType:
|
||||
return "IntPtr" if dllImport else _type.desc.name.to_camel_case()
|
||||
elif type(_type) is AbsApi.BaseType:
|
||||
return self.translate_base_type(_type, isArg, dllImport)
|
||||
elif type(_type) is AbsApi.ListType:
|
||||
if isArg:
|
||||
raise AbsApi.Error('Lists as params are not supported yet')
|
||||
elif dllImport:
|
||||
return 'IntPtr'
|
||||
else:
|
||||
if type(_type.containedTypeDesc) is AbsApi.BaseType:
|
||||
if _type.containedTypeDesc.name == 'string':
|
||||
return 'IEnumerable<string>'
|
||||
else:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of basic C types is not supported')
|
||||
elif type(_type.containedTypeDesc) is AbsApi.ClassType:
|
||||
ptrType = _type.containedTypeDesc.desc.name.to_camel_case()
|
||||
return 'IEnumerable<' + ptrType + '>'
|
||||
else:
|
||||
if _type.containedTypeDesc:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of enums')
|
||||
else:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of unknow type !')
|
||||
|
||||
def translate_argument(self, arg, dllImport=True):
|
||||
return '{0} {1}'.format(self.translate_type(arg.type, True, dllImport), self.translate_argument_name(arg.name))
|
||||
|
||||
def throws_exception(self, return_type):
|
||||
if type(return_type) is AbsApi.BaseType:
|
||||
if return_type.name == 'status':
|
||||
return True
|
||||
return False
|
||||
|
||||
def translate_method(self, method, static=False, genImpl=True):
|
||||
if method.name.to_snake_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(method.name.to_snake_case(fullName=True)))
|
||||
|
||||
methodElems = {}
|
||||
methodElems['return'] = self.translate_type(method.returnType, False)
|
||||
methodElems['name'] = method.name.to_c()
|
||||
methodElems['params'] = '' if static else 'IntPtr thiz'
|
||||
for arg in method.args:
|
||||
if arg is not method.args[0] or not static:
|
||||
methodElems['params'] += ', '
|
||||
methodElems['params'] += self.translate_argument(arg)
|
||||
|
||||
methodDict = {}
|
||||
methodDict['prototype'] = "static extern {return} {name}({params});".format(**methodElems)
|
||||
|
||||
methodDict['has_impl'] = genImpl
|
||||
if genImpl:
|
||||
methodDict['impl'] = {}
|
||||
methodDict['impl']['static'] = 'static ' if static else ''
|
||||
methodDict['impl']['exception'] = self.throws_exception(method.returnType)
|
||||
methodDict['impl']['type'] = self.translate_type(method.returnType, False, False)
|
||||
methodDict['impl']['name'] = method.name.to_camel_case()
|
||||
methodDict['impl']['override'] = 'override ' if method.name.to_camel_case() == 'ToString' else ''
|
||||
methodDict['impl']['return'] = '' if methodDict['impl']['type'] == "void" else 'return '
|
||||
methodDict['impl']['c_name'] = method.name.to_c()
|
||||
methodDict['impl']['nativePtr'] = '' if static else ('nativePtr, ' if len(method.args) > 0 else 'nativePtr')
|
||||
|
||||
methodDict['list_type'] = self.get_class_array_type(methodDict['impl']['type'])
|
||||
methodDict['is_string_list'] = methodDict['list_type'] == 'string'
|
||||
methodDict['is_class_list'] = not methodDict['list_type'] == None and not methodDict['list_type'] == 'string'
|
||||
|
||||
methodDict['is_string'] = methodDict['impl']['type'] == "string"
|
||||
methodDict['is_bool'] = methodDict['impl']['type'] == "bool"
|
||||
methodDict['is_class'] = self.is_linphone_type(method.returnType, False, False) and type(method.returnType) is AbsApi.ClassType
|
||||
methodDict['is_enum'] = self.is_linphone_type(method.returnType, False, False) and type(method.returnType) is AbsApi.EnumType
|
||||
methodDict['is_generic'] = self.is_generic(methodDict)
|
||||
methodDict['takeRef'] = 'true'
|
||||
if type(method.returnType.parent) is AbsApi.Method and len(method.returnType.parent.name.words) >=1:
|
||||
if method.returnType.parent.name.words == ['new'] or method.returnType.parent.name.words[0] == 'create':
|
||||
methodDict['takeRef'] = 'false'
|
||||
|
||||
methodDict['impl']['args'] = ''
|
||||
methodDict['impl']['c_args'] = ''
|
||||
for arg in method.args:
|
||||
if arg is not method.args[0]:
|
||||
methodDict['impl']['args'] += ', '
|
||||
methodDict['impl']['c_args'] += ', '
|
||||
if self.is_linphone_type(arg.type, False, False):
|
||||
if type(arg.type) is AbsApi.ClassType:
|
||||
argname = self.translate_argument_name(arg.name)
|
||||
methodDict['impl']['c_args'] += argname + " != null ? " + argname + ".nativePtr : IntPtr.Zero"
|
||||
else:
|
||||
methodDict['impl']['c_args'] += '(int)' + self.translate_argument_name(arg.name)
|
||||
elif self.translate_type(arg.type, False, False) == "bool":
|
||||
methodDict['impl']['c_args'] += self.translate_argument_name(arg.name) + " ? 1 : 0"
|
||||
else:
|
||||
methodDict['impl']['c_args'] += self.translate_argument_name(arg.name)
|
||||
methodDict['impl']['args'] += self.translate_argument(arg, False)
|
||||
|
||||
return methodDict
|
||||
|
||||
###########################################################################################################################################
|
||||
|
||||
def translate_property_getter(self, prop, name, static=False):
|
||||
methodDict = self.translate_method(prop, static, False)
|
||||
|
||||
methodDict['property_static'] = 'static ' if static else ''
|
||||
methodDict['property_return'] = self.translate_type(prop.returnType, False, False)
|
||||
methodDict['property_name'] = (name[3:] if len(name) > 3 else 'Instance') if name[:3] == "Get" else name
|
||||
|
||||
methodDict['has_property'] = True
|
||||
methodDict['has_getter'] = True
|
||||
methodDict['has_setter'] = False
|
||||
methodDict['return'] = methodDict['property_return']
|
||||
methodDict['exception'] = self.throws_exception(prop.returnType)
|
||||
methodDict['getter_nativePtr'] = '' if static else 'nativePtr'
|
||||
methodDict['getter_c_name'] = prop.name.to_c()
|
||||
|
||||
methodDict['list_type'] = self.get_class_array_type(methodDict['return'])
|
||||
methodDict['is_string_list'] = methodDict['list_type'] == 'string'
|
||||
methodDict['is_class_list'] = not methodDict['list_type'] == None and not methodDict['list_type'] == 'string'
|
||||
|
||||
methodDict['is_string'] = methodDict['return'] == "string"
|
||||
methodDict['is_bool'] = methodDict['return'] == "bool"
|
||||
methodDict['is_class'] = self.is_linphone_type(prop.returnType, False, False) and type(prop.returnType) is AbsApi.ClassType
|
||||
methodDict['is_enum'] = self.is_linphone_type(prop.returnType, False, False) and type(prop.returnType) is AbsApi.EnumType
|
||||
methodDict['is_generic'] = self.is_generic(methodDict)
|
||||
methodDict['takeRef'] = 'true'
|
||||
if type(prop.returnType.parent) is AbsApi.Method and len(prop.returnType.parent.name.words) >=1:
|
||||
if prop.returnType.parent.name.words == ['new'] or prop.returnType.parent.name.words[0] == 'create':
|
||||
methodDict['takeRef'] = 'false'
|
||||
|
||||
return methodDict
|
||||
|
||||
def translate_property_setter(self, prop, name, static=False):
|
||||
methodDict = self.translate_method(prop, static, False)
|
||||
|
||||
methodDict['property_static'] = 'static ' if static else ''
|
||||
methodDict['property_return'] = self.translate_type(prop.args[0].type, True, False)
|
||||
methodDict['property_name'] = (name[3:] if len(name) > 3 else 'Instance') if name[:3] == "Set" else name
|
||||
|
||||
methodDict['has_property'] = True
|
||||
methodDict['has_getter'] = False
|
||||
methodDict['has_setter'] = True
|
||||
methodDict['return'] = methodDict['property_return']
|
||||
methodDict['exception'] = self.throws_exception(prop.returnType)
|
||||
methodDict['setter_nativePtr'] = '' if static else 'nativePtr, '
|
||||
methodDict['setter_c_name'] = prop.name.to_c()
|
||||
|
||||
methodDict['list_type'] = self.get_class_array_type(methodDict['return'])
|
||||
methodDict['is_string_list'] = methodDict['list_type'] == 'string'
|
||||
methodDict['is_class_list'] = not methodDict['list_type'] == None and not methodDict['list_type'] == 'string'
|
||||
|
||||
methodDict['is_string'] = methodDict['return'] == "string"
|
||||
methodDict['is_bool'] = methodDict['return'] == "bool"
|
||||
methodDict['is_class'] = self.is_linphone_type(prop.args[0].type, True, False) and type(prop.args[0].type) is AbsApi.ClassType
|
||||
methodDict['is_enum'] = self.is_linphone_type(prop.args[0].type, True, False) and type(prop.args[0].type) is AbsApi.EnumType
|
||||
methodDict['is_generic'] = self.is_generic(methodDict)
|
||||
|
||||
return methodDict
|
||||
|
||||
def translate_property_getter_setter(self, getter, setter, name, static=False):
|
||||
methodDict = self.translate_property_getter(getter, name, static)
|
||||
methodDictSet = self.translate_property_setter(setter, name, static)
|
||||
|
||||
protoElems = {}
|
||||
methodDict["prototype"] = methodDict['prototype']
|
||||
methodDict["has_second_prototype"] = True
|
||||
methodDict["second_prototype"] = methodDictSet['prototype']
|
||||
|
||||
methodDict['has_setter'] = True
|
||||
methodDict['exception'] = methodDictSet['exception']
|
||||
methodDict['setter_nativePtr'] = methodDictSet['setter_nativePtr']
|
||||
methodDict['setter_c_name'] = methodDictSet['setter_c_name']
|
||||
|
||||
return methodDict
|
||||
|
||||
def translate_property(self, prop):
|
||||
res = []
|
||||
name = prop.name.to_camel_case()
|
||||
if prop.getter is not None:
|
||||
if prop.setter is not None:
|
||||
res.append(self.translate_property_getter_setter(prop.getter, prop.setter, name))
|
||||
else:
|
||||
res.append(self.translate_property_getter(prop.getter, name))
|
||||
elif prop.setter is not None:
|
||||
res.append(self.translate_property_setter(prop.setter, name))
|
||||
return res
|
||||
|
||||
###########################################################################################################################################
|
||||
|
||||
def translate_listener(self, _class, method):
|
||||
listenedClass = method.find_first_ancestor_by_type(AbsApi.Interface).listenedClass
|
||||
|
||||
listenerDict = {}
|
||||
c_name_setter = listenedClass.name.to_snake_case(fullName=True) + '_cbs_set_' + method.name.to_snake_case()[3:]
|
||||
listenerDict['cb_setter'] = {}
|
||||
listenerDict['cb_setter']['name'] = c_name_setter
|
||||
|
||||
listenerDict['delegate'] = {}
|
||||
delegate_name_public = method.name.to_camel_case() + "Delegate"
|
||||
delegate_name_private = delegate_name_public + "Private"
|
||||
listenerDict['delegate']['name_public'] = delegate_name_public
|
||||
listenerDict['delegate']['name_private'] = delegate_name_private
|
||||
var_name_public = method.name.to_snake_case() + '_public'
|
||||
var_name_private = method.name.to_snake_case() + '_private'
|
||||
listenerDict['delegate']['var_public'] = var_name_public
|
||||
listenerDict['delegate']['var_private'] = var_name_private
|
||||
listenerDict['delegate']['cb_name'] = method.name.to_snake_case()
|
||||
listenerDict['delegate']['name'] = method.name.to_camel_case()
|
||||
|
||||
|
||||
listenerDict['delegate']['params_public'] = ""
|
||||
listenerDict['delegate']['params_private'] = ""
|
||||
listenerDict['delegate']['params'] = ""
|
||||
for arg in method.args:
|
||||
dllImportType = self.translate_type(arg.type, True, True)
|
||||
normalType = self.translate_type(arg.type, True, False)
|
||||
|
||||
argName = self.translate_argument_name(arg.name)
|
||||
if arg != method.args[0]:
|
||||
listenerDict['delegate']['params_public'] += ', '
|
||||
listenerDict['delegate']['params_private'] += ', '
|
||||
listenerDict['delegate']['params'] += ', '
|
||||
if normalType == dllImportType:
|
||||
listenerDict['delegate']['params'] += argName
|
||||
else:
|
||||
if normalType == "bool":
|
||||
listenerDict['delegate']['params'] += argName + " == 0"
|
||||
elif self.is_linphone_type(arg.type, True, False) and type(arg.type) is AbsApi.ClassType:
|
||||
listenerDict['delegate']['params'] += "fromNativePtr<" + normalType + ">(" + argName + ")"
|
||||
elif self.is_linphone_type(arg.type, True, False) and type(arg.type) is AbsApi.EnumType:
|
||||
listenerDict['delegate']['params'] += "(" + normalType + ")" + argName + ""
|
||||
else:
|
||||
raise("Error")
|
||||
listenerDict['delegate']['params_public'] += normalType + " " + argName
|
||||
listenerDict['delegate']['params_private'] += dllImportType + " " + argName
|
||||
|
||||
listenerDict['delegate']["c_name_setter"] = c_name_setter
|
||||
return listenerDict
|
||||
|
||||
def generate_getter_for_listener_callbacks(self, _class, classname):
|
||||
methodDict = self.init_method_dict()
|
||||
c_name = _class.name.to_snake_case(fullName=True) + '_get_callbacks'
|
||||
methodDict['prototype'] = "static extern IntPtr {c_name}(IntPtr thiz);".format(classname = classname, c_name = c_name)
|
||||
|
||||
methodDict['has_impl'] = False
|
||||
methodDict['has_property'] = True
|
||||
methodDict['property_static'] = ''
|
||||
methodDict['property_return'] = classname
|
||||
methodDict['property_name'] = 'Listener'
|
||||
methodDict['has_getter'] = True
|
||||
methodDict['return'] = classname
|
||||
methodDict['getter_nativePtr'] = 'nativePtr'
|
||||
methodDict['getter_c_name'] = c_name
|
||||
methodDict['is_class'] = True
|
||||
|
||||
return methodDict
|
||||
|
||||
def generate_add_for_listener_callbacks(self, _class, classname):
|
||||
methodDict = self.init_method_dict()
|
||||
c_name = _class.name.to_snake_case(fullName=True) + '_add_callbacks'
|
||||
methodDict['prototype'] = "static extern void {c_name}(IntPtr thiz, IntPtr cbs);".format(classname = classname, c_name = c_name)
|
||||
methodDict['impl']['static'] = ''
|
||||
methodDict['impl']['type'] = 'void'
|
||||
methodDict['impl']['name'] = 'AddListener'
|
||||
methodDict['impl']['return'] = ''
|
||||
methodDict['impl']['c_name'] = c_name
|
||||
methodDict['impl']['nativePtr'] = 'nativePtr, '
|
||||
methodDict['impl']['args'] = classname + ' cbs'
|
||||
methodDict['impl']['c_args'] = 'cbs != null ? cbs.nativePtr : IntPtr.Zero'
|
||||
methodDict['is_generic'] = True
|
||||
|
||||
return methodDict
|
||||
|
||||
def generate_remove_for_listener_callbacks(self, _class, classname):
|
||||
methodDict = self.init_method_dict()
|
||||
c_name = _class.name.to_snake_case(fullName=True) + '_remove_callbacks'
|
||||
methodDict['prototype'] = "static extern void {c_name}(IntPtr thiz, IntPtr cbs);".format(classname = classname, c_name = c_name)
|
||||
methodDict['impl']['static'] = ''
|
||||
methodDict['impl']['type'] = 'void'
|
||||
methodDict['impl']['name'] = 'RemoveListener'
|
||||
methodDict['impl']['return'] = ''
|
||||
methodDict['impl']['c_name'] = c_name
|
||||
methodDict['impl']['nativePtr'] = 'nativePtr, '
|
||||
methodDict['impl']['args'] = classname + ' cbs'
|
||||
methodDict['impl']['c_args'] = 'cbs != null ? cbs.nativePtr : IntPtr.Zero'
|
||||
methodDict['is_generic'] = True
|
||||
|
||||
return methodDict
|
||||
|
||||
###########################################################################################################################################
|
||||
|
||||
def translate_enum(self, enum):
|
||||
enumDict = {}
|
||||
enumDict['enumName'] = enum.name.to_camel_case()
|
||||
enumDict['values'] = []
|
||||
i = 0
|
||||
lastValue = None
|
||||
for enumValue in enum.values:
|
||||
enumValDict = {}
|
||||
enumValDict['name'] = enumValue.name.to_camel_case()
|
||||
if type(enumValue.value) is int:
|
||||
lastValue = enumValue.value
|
||||
enumValDict['value'] = str(enumValue.value)
|
||||
elif type(enumValue.value) is AbsApi.Flag:
|
||||
enumValDict['value'] = '1<<' + str(enumValue.value.position)
|
||||
else:
|
||||
if lastValue is not None:
|
||||
enumValDict['value'] = lastValue + 1
|
||||
lastValue += 1
|
||||
else:
|
||||
enumValDict['value'] = i
|
||||
enumDict['values'].append(enumValDict)
|
||||
i += 1
|
||||
return enumDict
|
||||
|
||||
def translate_class(self, _class):
|
||||
if _class.name.to_camel_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_class.name.to_camel_case(fullName=True)))
|
||||
|
||||
classDict = {}
|
||||
classDict['className'] = _class.name.to_camel_case()
|
||||
classDict['isLinphoneFactory'] = _class.name.to_camel_case() == "Factory"
|
||||
classDict['dllImports'] = []
|
||||
|
||||
islistenable = _class.listenerInterface is not None
|
||||
ismonolistenable = (islistenable and not _class.multilistener)
|
||||
if islistenable:
|
||||
listenerName = _class.listenerInterface.name.to_camel_case()
|
||||
if ismonolistenable:
|
||||
classDict['dllImports'].append(self.generate_getter_for_listener_callbacks(_class, listenerName))
|
||||
else:
|
||||
classDict['dllImports'].append(self.generate_add_for_listener_callbacks(_class, listenerName))
|
||||
classDict['dllImports'].append(self.generate_remove_for_listener_callbacks(_class, listenerName))
|
||||
|
||||
for method in _class.classMethods:
|
||||
try:
|
||||
if 'get' in method.name.to_word_list():
|
||||
methodDict = self.translate_property_getter(method, method.name.to_camel_case(), True)
|
||||
#The following doesn't work because there a at least one method that has both getter and setter,
|
||||
#and because it doesn't do both of them at once, property is declared twice
|
||||
#elif 'set' in method.name.to_word_list():
|
||||
# methodDict = self.translate_property_setter(method, method.name.to_camel_case(), True)
|
||||
else:
|
||||
methodDict = self.translate_method(method, static=True, genImpl=True)
|
||||
classDict['dllImports'].append(methodDict)
|
||||
except AbsApi.Error as e:
|
||||
print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
|
||||
|
||||
for prop in _class.properties:
|
||||
try:
|
||||
classDict['dllImports'] += self.translate_property(prop)
|
||||
except AbsApi.Error as e:
|
||||
print('error while translating {0} property: {1}'.format(prop.name.to_snake_case(), e.args[0]))
|
||||
|
||||
for method in _class.instanceMethods:
|
||||
try:
|
||||
methodDict = self.translate_method(method, static=False, genImpl=True)
|
||||
classDict['dllImports'].append(methodDict)
|
||||
except AbsApi.Error as e:
|
||||
print('Could not translate {0}: {1}'.format(method.name.to_snake_case(fullName=True), e.args[0]))
|
||||
|
||||
return classDict
|
||||
|
||||
def translate_interface(self, interface):
|
||||
if interface.name.to_camel_case(fullName=True) in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(interface.name.to_camel_case(fullName=True)))
|
||||
|
||||
interfaceDict = {}
|
||||
interfaceDict['interfaceName'] = interface.name.to_camel_case()
|
||||
interfaceDict['methods'] = []
|
||||
for method in interface.methods:
|
||||
interfaceDict['methods'].append(self.translate_listener(interface, method))
|
||||
|
||||
return interfaceDict
|
||||
|
||||
###########################################################################################################################################
|
||||
|
||||
class EnumImpl(object):
|
||||
def __init__(self, enum, translator):
|
||||
namespace = enum.find_first_ancestor_by_type(AbsApi.Namespace)
|
||||
self.namespace = namespace.name.concatenate(fullName=True) if namespace is not None else None
|
||||
self.enum = translator.translate_enum(enum)
|
||||
|
||||
class ClassImpl(object):
|
||||
def __init__(self, _class, translator):
|
||||
namespace = _class.find_first_ancestor_by_type(AbsApi.Namespace)
|
||||
self.namespace = namespace.name.concatenate(fullName=True) if namespace is not None else None
|
||||
self._class = translator.translate_class(_class)
|
||||
|
||||
class InterfaceImpl(object):
|
||||
def __init__(self, interface, translator):
|
||||
namespace = interface.find_first_ancestor_by_type(AbsApi.Namespace)
|
||||
self.namespace = namespace.name.concatenate(fullName=True) if namespace is not None else None
|
||||
self.interface = translator.translate_interface(interface)
|
||||
|
||||
class WrapperImpl(object):
|
||||
def __init__(self, enums, interfaces, classes):
|
||||
self.enums = enums
|
||||
self.interfaces = interfaces
|
||||
self.classes = classes
|
||||
|
||||
###########################################################################################################################################
|
||||
|
||||
def render(renderer, item, path):
|
||||
tmppath = path + '.tmp'
|
||||
content = ''
|
||||
with open(tmppath, mode='w') as f:
|
||||
f.write(renderer.render(item))
|
||||
with open(tmppath, mode='rU') as f:
|
||||
content = f.read()
|
||||
with open(path, mode='w') as f:
|
||||
f.write(content)
|
||||
os.unlink(tmppath)
|
||||
|
||||
def main():
|
||||
argparser = argparse.ArgumentParser(description='Generate source files for the C++ wrapper')
|
||||
argparser.add_argument('xmldir', type=str, help='Directory where the XML documentation of the Linphone\'s API generated by Doxygen is placed')
|
||||
argparser.add_argument('-o --output', type=str, help='the directory where to generate the source files', dest='outputdir', default='.')
|
||||
argparser.add_argument('-n --name', type=str, help='the name of the genarated source file', dest='outputfile', default='LinphoneWrapper.cs')
|
||||
args = argparser.parse_args()
|
||||
|
||||
entries = os.listdir(args.outputdir)
|
||||
|
||||
project = CApi.Project()
|
||||
project.initFromDir(args.xmldir)
|
||||
project.check()
|
||||
|
||||
parser = AbsApi.CParser(project)
|
||||
parser.parse_all()
|
||||
translator = CsharpTranslator()
|
||||
renderer = pystache.Renderer()
|
||||
|
||||
enums = []
|
||||
for item in parser.enumsIndex.items():
|
||||
if item[1] is not None:
|
||||
impl = EnumImpl(item[1], translator)
|
||||
enums.append(impl)
|
||||
else:
|
||||
print('warning: {0} enum won\'t be translated because of parsing errors'.format(item[0]))
|
||||
|
||||
interfaces = []
|
||||
classes = []
|
||||
for _class in parser.classesIndex.values() + parser.interfacesIndex.values():
|
||||
if _class is not None:
|
||||
try:
|
||||
if type(_class) is AbsApi.Class:
|
||||
impl = ClassImpl(_class, translator)
|
||||
classes.append(impl)
|
||||
else:
|
||||
impl = InterfaceImpl(_class, translator)
|
||||
interfaces.append(impl)
|
||||
except AbsApi.Error as e:
|
||||
print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0]))
|
||||
|
||||
wrapper = WrapperImpl(enums, interfaces, classes)
|
||||
render(renderer, wrapper, args.outputdir + "/" + args.outputfile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
338
wrappers/csharp/wrapper_impl.mustache
Normal file
338
wrappers/csharp/wrapper_impl.mustache
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
LinphoneWrapper.cs
|
||||
Copyright (C) 2017 Belledonne Communications SARL
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Linphone
|
||||
{
|
||||
#region Wrapper specifics
|
||||
public class LinphoneWrapper
|
||||
{
|
||||
public const string LIB_NAME = "linphone"; // With this, it automatically finds liblinphone.so
|
||||
}
|
||||
|
||||
[Serializable()]
|
||||
public class LinphoneException : System.Exception
|
||||
{
|
||||
public LinphoneException() : base() { }
|
||||
public LinphoneException(string message) : base(message) { }
|
||||
public LinphoneException(string message, System.Exception inner) : base(message, inner) { }
|
||||
protected LinphoneException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class LinphoneObject
|
||||
{
|
||||
internal IntPtr nativePtr;
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern int belle_sip_object_data_set(IntPtr ptr, string name, IntPtr data, IntPtr cb);
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern IntPtr belle_sip_object_data_get(IntPtr ptr, string name);
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern IntPtr belle_sip_object_ref(IntPtr ptr);
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern void belle_sip_object_unref(IntPtr ptr);
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern IntPtr bctbx_list_next(IntPtr ptr);
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern IntPtr bctbx_list_get_data(IntPtr ptr);
|
||||
|
||||
~LinphoneObject()
|
||||
{
|
||||
Console.WriteLine("Destroying" + this.ToString());
|
||||
if (nativePtr != IntPtr.Zero) {
|
||||
Console.WriteLine("Unreffing" + this.ToString());
|
||||
belle_sip_object_unref(nativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
internal static T fromNativePtr<T>(IntPtr ptr, bool takeRef=true) where T : LinphoneObject, new()
|
||||
{
|
||||
if (ptr == IntPtr.Zero) return null;
|
||||
IntPtr objPtr = belle_sip_object_data_get(ptr, "cs_obj");
|
||||
if (objPtr == IntPtr.Zero)
|
||||
{
|
||||
T obj = new T();
|
||||
Console.WriteLine("Creating" + obj.ToString());
|
||||
if (takeRef)
|
||||
{
|
||||
ptr = belle_sip_object_ref(ptr);
|
||||
Console.WriteLine("Reffing" + obj.ToString());
|
||||
}
|
||||
obj.nativePtr = ptr;
|
||||
objPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)));
|
||||
Marshal.StructureToPtr(obj, objPtr, false);
|
||||
belle_sip_object_data_set(ptr, "cs_obj", objPtr, IntPtr.Zero);
|
||||
return obj;
|
||||
}
|
||||
else
|
||||
{
|
||||
T obj = Marshal.PtrToStructure<T>(objPtr);
|
||||
if (takeRef)
|
||||
{
|
||||
obj.nativePtr = belle_sip_object_ref(obj.nativePtr);
|
||||
Console.WriteLine("Reffing" + obj.ToString());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<string> MarshalStringArray(IntPtr arrayPtr)
|
||||
{
|
||||
if (arrayPtr != IntPtr.Zero)
|
||||
{
|
||||
IntPtr ptr = Marshal.ReadIntPtr(arrayPtr);
|
||||
while (ptr != IntPtr.Zero)
|
||||
{
|
||||
string key = Marshal.PtrToStringAnsi(ptr);
|
||||
yield return key;
|
||||
arrayPtr = new IntPtr(arrayPtr.ToInt64() + IntPtr.Size);
|
||||
ptr = Marshal.ReadIntPtr(arrayPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<T> MarshalBctbxList<T>(IntPtr listPtr) where T : LinphoneObject, new()
|
||||
{
|
||||
if (listPtr != IntPtr.Zero)
|
||||
{
|
||||
IntPtr ptr = listPtr;
|
||||
while (ptr != IntPtr.Zero)
|
||||
{
|
||||
IntPtr dataPtr = bctbx_list_get_data(ptr);
|
||||
if (dataPtr == IntPtr.Zero)
|
||||
{
|
||||
break;
|
||||
}
|
||||
T obj = fromNativePtr<T>(dataPtr);
|
||||
yield return obj;
|
||||
ptr = bctbx_list_next(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LinphoneAndroid
|
||||
{
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern void ms_set_jvm_from_env(IntPtr jnienv);
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern void setAndroidLogHandler();
|
||||
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern void setMediastreamerAndroidContext(IntPtr jnienv, IntPtr context);
|
||||
|
||||
public static void setNativeLogHandler()
|
||||
{
|
||||
setAndroidLogHandler();
|
||||
}
|
||||
|
||||
public static void setAndroidContext(IntPtr jnienv, IntPtr context)
|
||||
{
|
||||
ms_set_jvm_from_env(jnienv);
|
||||
setMediastreamerAndroidContext(jnienv, context);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Enums
|
||||
{{#enums}}
|
||||
{{#enum}}
|
||||
public enum {{enumName}}
|
||||
{
|
||||
{{#values}}
|
||||
{{name}} = {{value}},
|
||||
{{/values}}
|
||||
}
|
||||
|
||||
{{/enum}}
|
||||
{{/enums}}
|
||||
#endregion
|
||||
|
||||
#region Listeners
|
||||
{{#interfaces}}
|
||||
{{#interface}}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class {{interfaceName}} : LinphoneObject
|
||||
{
|
||||
{{#methods}}
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
{{#cb_setter}}
|
||||
static extern void {{name}}(IntPtr thiz, IntPtr cb);
|
||||
{{/cb_setter}}
|
||||
|
||||
{{#delegate}}
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void {{name_private}}({{params_private}});
|
||||
|
||||
public delegate void {{name_public}}({{params_public}});
|
||||
private {{name_private}} {{var_private}};
|
||||
private {{name_public}} {{var_public}};
|
||||
|
||||
private void {{cb_name}}({{params_private}})
|
||||
{
|
||||
{{var_public}}?.Invoke({{{params}}});
|
||||
}
|
||||
public {{name_public}} {{name}}
|
||||
{
|
||||
set
|
||||
{
|
||||
{{var_private}} = {{cb_name}};
|
||||
{{var_public}} = value;
|
||||
IntPtr cb = Marshal.GetFunctionPointerForDelegate({{var_private}});
|
||||
{{c_name_setter}}(nativePtr, cb);
|
||||
}
|
||||
}
|
||||
{{/delegate}}
|
||||
{{/methods}}
|
||||
}
|
||||
|
||||
{{/interface}}
|
||||
{{/interfaces}}
|
||||
#endregion
|
||||
|
||||
#region Classes
|
||||
{{#classes}}
|
||||
{{#_class}}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class {{className}} : LinphoneObject
|
||||
{
|
||||
{{#isLinphoneFactory}}
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
static extern IntPtr linphone_factory_create_core_cbs(IntPtr factory);
|
||||
|
||||
public CoreListener CreateCoreListener()
|
||||
{
|
||||
IntPtr coreCbsPtr = linphone_factory_create_core_cbs(nativePtr);
|
||||
return fromNativePtr<CoreListener>(coreCbsPtr, false);
|
||||
}
|
||||
{{/isLinphoneFactory}}
|
||||
{{#dllImports}}
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
{{{prototype}}}
|
||||
{{#has_second_prototype}}
|
||||
[DllImport(LinphoneWrapper.LIB_NAME)]
|
||||
{{second_prototype}}
|
||||
{{/has_second_prototype}}
|
||||
|
||||
{{#has_property}}
|
||||
{{property_static}}public {{{property_return}}} {{property_name}}
|
||||
{
|
||||
{{#has_getter}}
|
||||
get
|
||||
{
|
||||
{{#is_string}}
|
||||
IntPtr stringPtr = {{getter_c_name}}({{getter_nativePtr}});
|
||||
return Marshal.PtrToStringAnsi(stringPtr);
|
||||
{{/is_string}}
|
||||
{{#is_bool}}
|
||||
return {{getter_c_name}}({{getter_nativePtr}}) == 0;
|
||||
{{/is_bool}}
|
||||
{{#is_class}}
|
||||
IntPtr ptr = {{getter_c_name}}({{getter_nativePtr}});
|
||||
return fromNativePtr<{{return}}>(ptr, {{takeRef}});
|
||||
{{/is_class}}
|
||||
{{#is_enum}}
|
||||
return {{getter_c_name}}({{getter_nativePtr}});
|
||||
{{/is_enum}}
|
||||
{{#is_generic}}
|
||||
return {{getter_c_name}}({{getter_nativePtr}});
|
||||
{{/is_generic}}
|
||||
{{#is_string_list}}
|
||||
return MarshalStringArray({{getter_c_name}}({{getter_nativePtr}}));
|
||||
{{/is_string_list}}
|
||||
{{#is_class_list}}
|
||||
return MarshalBctbxList<{{{list_type}}}>({{getter_c_name}}({{getter_nativePtr}}));
|
||||
{{/is_class_list}}
|
||||
}
|
||||
{{/has_getter}}
|
||||
{{#has_setter}}
|
||||
set
|
||||
{
|
||||
{{#is_string}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value);
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
|
||||
{{/is_string}}
|
||||
{{#is_bool}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value ? 1 : 0);
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
|
||||
{{/is_bool}}
|
||||
{{#is_class}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value.nativePtr);
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
|
||||
{{/is_class}}
|
||||
{{#is_enum}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}(int)value);
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
|
||||
{{/is_enum}}
|
||||
{{#is_generic}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{setter_c_name}}({{setter_nativePtr}}value);
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{property_name}} setter returned value " + exception_result);{{/exception}}
|
||||
{{/is_generic}}
|
||||
}
|
||||
{{/has_setter}}
|
||||
}
|
||||
{{/has_property}}
|
||||
{{#has_impl}}
|
||||
{{#impl}}
|
||||
public {{static}}{{override}}{{{type}}} {{name}}({{args}})
|
||||
{
|
||||
{{#is_string}}
|
||||
IntPtr stringPtr = {{c_name}}({{nativePtr}}{{c_args}});
|
||||
return Marshal.PtrToStringAnsi(stringPtr);
|
||||
{{/is_string}}
|
||||
{{#is_bool}}
|
||||
{{return}}{{c_name}}({{nativePtr}}{{c_args}}) == 0 ? false : true;
|
||||
{{/is_bool}}
|
||||
{{#is_class}}
|
||||
IntPtr ptr = {{c_name}}({{nativePtr}}{{c_args}});
|
||||
return fromNativePtr<{{type}}>(ptr, {{takeRef}});
|
||||
{{/is_class}}
|
||||
{{#is_enum}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{return}}{{c_name}}({{nativePtr}}{{c_args}});
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{name}} returned value " + exception_result);{{/exception}}
|
||||
{{/is_enum}}
|
||||
{{#is_generic}}
|
||||
{{#exception}}int exception_result = {{/exception}}{{return}}{{c_name}}({{nativePtr}}{{c_args}});
|
||||
{{#exception}}if (exception_result != 0) throw new LinphoneException("{{name}} returned value " + exception_result);{{/exception}}
|
||||
{{/is_generic}}
|
||||
{{#is_string_list}}
|
||||
return MarshalStringArray({{c_name}}({{nativePtr}}{{c_args}}));
|
||||
{{/is_string_list}}
|
||||
{{#is_class_list}}
|
||||
return MarshalBctbxList<{{{list_type}}}>({{c_name}}({{nativePtr}}{{c_args}}));
|
||||
{{/is_class_list}}
|
||||
}
|
||||
{{/impl}}
|
||||
{{/has_impl}}
|
||||
{{/dllImports}}
|
||||
}
|
||||
{{/_class}}
|
||||
{{/classes}}
|
||||
#endregion
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue