mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-05-07 05:53:06 +00:00
C++ wrapper generator - intitial commit
This commit is contained in:
parent
19d47a6478
commit
d6d0cbf5a6
13 changed files with 54101 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -105,3 +105,5 @@ git-clang-format.diff
|
|||
.bc_tester_utils.tmp
|
||||
tools/lp-test-ecc
|
||||
tools/lp-sendmsg
|
||||
|
||||
*.pyc
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ cmake_dependent_option(ENABLE_ASSISTANT "Turn on assistant compiling." YES "ENAB
|
|||
option(ENABLE_DEBUG_LOGS "Turn on or off debug level logs." NO)
|
||||
option(ENABLE_NLS "Build with internationalisation support" YES)
|
||||
option(ENABLE_VCARD "Turn on compilation of vcard4 support." YES)
|
||||
option(CXX_WRAPPER "Build the C++ wrapper for Liblinphone." OFF)
|
||||
|
||||
|
||||
macro(apply_compile_flags SOURCE_FILES)
|
||||
|
|
@ -180,6 +181,10 @@ endif()
|
|||
if(ENABLE_LIME)
|
||||
set(HAVE_LIME 1)
|
||||
endif()
|
||||
if (CXX_WRAPPER)
|
||||
set(Python_ADDITIONAL_VERSIONS 2)
|
||||
find_package(PythonInterp REQUIRED)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
include(CheckIncludeFiles)
|
||||
|
|
@ -326,6 +331,9 @@ endif()
|
|||
if(ENABLE_UNIT_TESTS AND BCTOOLBOX_TESTER_FOUND)
|
||||
add_subdirectory(tester)
|
||||
endif()
|
||||
if(CXX_WRAPPER)
|
||||
add_subdirectory(wrappers/cpp)
|
||||
endif()
|
||||
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
|
|
|||
119
wrappers/cpp/CMakeLists.txt
Normal file
119
wrappers/cpp/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
set(GENERATED_SOURCES
|
||||
src/account_creator.cc
|
||||
src/address.cc
|
||||
src/auth_info.cc
|
||||
src/buffer.cc
|
||||
src/call.cc
|
||||
src/call_log.cc
|
||||
src/call_params.cc
|
||||
src/call_stats.cc
|
||||
src/chat_message.cc
|
||||
src/chat_room.cc
|
||||
src/conference.cc
|
||||
src/conference_params.cc
|
||||
src/config.cc
|
||||
src/content.cc
|
||||
src/core.cc
|
||||
src/core_v_table.cc
|
||||
src/error_info.cc
|
||||
src/event.cc
|
||||
src/factory.cc
|
||||
src/friend.cc
|
||||
src/friend_list.cc
|
||||
src/nat_policy.cc
|
||||
src/payload_type.cc
|
||||
src/player.cc
|
||||
src/presence_activity.cc
|
||||
src/presence_model.cc
|
||||
src/presence_note.cc
|
||||
src/presence_person.cc
|
||||
src/presence_service.cc
|
||||
src/proxy_config.cc
|
||||
src/sip_transports.cc
|
||||
src/tunnel.cc
|
||||
src/tunnel_config.cc
|
||||
src/vcard.cc
|
||||
src/video_policy.cc
|
||||
src/xml_rpc_request.cc
|
||||
src/xml_rpc_session.cc
|
||||
)
|
||||
set(SOURCES
|
||||
${GENERATED_SOURCES}
|
||||
object.cc
|
||||
)
|
||||
set(GENERATED_HEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/account_creator.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/account_creator_listener.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/address.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/auth_info.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/buffer.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/call.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/call_log.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/call_params.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/call_stats.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/chat_message.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/chat_message_listener.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/chat_room.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/conference.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/conference_params.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/config.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/content.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/core.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/core_listener.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/core_v_table.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/enums.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/error_info.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/event.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/factory.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/friend.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/friend_list.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/friend_list_listener.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/linphone.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/nat_policy.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/payload_type.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/player.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/presence_activity.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/presence_model.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/presence_note.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/presence_person.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/presence_service.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/proxy_config.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/sip_transports.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/tunnel_config.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/tunnel.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/vcard.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/video_policy.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/xml_rpc_request.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/xml_rpc_request_listener.hh
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/xml_rpc_session.hh
|
||||
)
|
||||
set(HEADERS
|
||||
${GENERATED_HEADERS}
|
||||
object.hh
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_SOURCES} ${GENERATED_HEADERS}
|
||||
COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/genheaders.py" "${PROJECT_BINARY_DIR}/coreapi/help/doc/xml"
|
||||
DEPENDS *.py *.mustache linphone-doc "${PROJECT_BINARY_DIR}/coreapi/help/doc/xml/index.xml"
|
||||
)
|
||||
|
||||
add_compile_options(-Wall -Wextra -Wno-deprecated-declarations -Wno-unused-parameter -Werror --std=c++11)
|
||||
add_definitions(-DWRAPPER_BUILD)
|
||||
|
||||
add_library(linphone++ SHARED ${SOURCES})
|
||||
target_link_libraries(linphone++ PRIVATE linphone)
|
||||
target_include_directories(linphone++
|
||||
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PRIVATE ${PROJECT_SOURCE_DIR}
|
||||
)
|
||||
set_target_properties(linphone++
|
||||
PROPERTIES SOVERSION ${LINPHONE_SO_VERSION}
|
||||
)
|
||||
|
||||
install(TARGETS linphone++
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
install(FILES ${HEADERS}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/linphone++
|
||||
)
|
||||
|
||||
760
wrappers/cpp/abstractapi.py
Normal file
760
wrappers/cpp/abstractapi.py
Normal file
|
|
@ -0,0 +1,760 @@
|
|||
import re
|
||||
import genapixml as CApi
|
||||
|
||||
class Error(RuntimeError):
|
||||
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 Name.to_snake_case(self, fullName=True) + suffix
|
||||
|
||||
|
||||
class ArgName(Name):
|
||||
def to_c(self):
|
||||
return Name.to_snake_case(self)
|
||||
|
||||
|
||||
class PropertyName(Name):
|
||||
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
|
||||
|
||||
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 EnumValue(DocumentableObject):
|
||||
pass
|
||||
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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']
|
||||
self.cListType = 'bctbx_list_t'
|
||||
self.regexFixedSizeInteger = '^(u?)int(\d?\d)_t$'
|
||||
self.methodBl = ['ref', 'unref', 'new', 'destroy', 'getCurrentCallbacks']
|
||||
self.functionBl = ['linphone_tunnel_get_http_proxy',
|
||||
'linphone_core_can_we_add_call',
|
||||
'linphone_core_get_default_proxy',
|
||||
'linphone_core_add_listener',
|
||||
'linphone_core_remove_listener',
|
||||
'linphone_core_get_current_callbacks',
|
||||
'linphone_proxy_config_normalize_number',
|
||||
'linphone_proxy_config_set_file_transfer_server',
|
||||
'linphone_proxy_config_get_file_transfer_server',
|
||||
'linphone_factory_create_core',
|
||||
'linphone_factory_create_core_with_config',
|
||||
'linphone_buffer_get_content',
|
||||
'linphone_chat_room_send_chat_message',
|
||||
'linphone_config_read_relative_file',
|
||||
'linphone_core_new_with_config']
|
||||
self.classBl = ['LinphoneImEncryptionEngine',
|
||||
'LinphoneImEncryptionEngineCbs',
|
||||
'LinphoneImNotifPolicy',
|
||||
'LpConfig']
|
||||
|
||||
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:
|
||||
CParser.parse_enum(self, enum)
|
||||
for _class in self.cProject.classes:
|
||||
try:
|
||||
CParser.parse_class(self, _class)
|
||||
except Error as e:
|
||||
print('Could not parse \'{0}\' class: {1}'.format(_class.name, e.args[0]))
|
||||
CParser._fix_all_types(self)
|
||||
|
||||
def _fix_all_types(self):
|
||||
for _class in self.classesIndex.values() + self.interfacesIndex.values():
|
||||
if _class is not None:
|
||||
if type(_class) is Class:
|
||||
CParser._fix_all_types_in_class(self, _class)
|
||||
else:
|
||||
CParser._fix_all_types_in_interface(self, _class)
|
||||
|
||||
def _fix_all_types_in_class(self, _class):
|
||||
for property in _class.properties:
|
||||
if property.setter is not None:
|
||||
CParser._fix_all_types_in_method(self, property.setter)
|
||||
if property.getter is not None:
|
||||
CParser._fix_all_types_in_method(self, property.getter)
|
||||
|
||||
for method in (_class.instanceMethods + _class.classMethods):
|
||||
CParser._fix_all_types_in_method(self, method)
|
||||
|
||||
def _fix_all_types_in_interface(self, interface):
|
||||
for method in interface.methods:
|
||||
CParser._fix_all_types_in_method(self, method)
|
||||
|
||||
def _fix_all_types_in_method(self, method):
|
||||
try:
|
||||
CParser._fix_type(self, method.returnType)
|
||||
for arg in method.args:
|
||||
CParser._fix_type(self, 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 = CParser.parse_c_base_type(self, 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)
|
||||
enum.add_value(aEnumValue)
|
||||
|
||||
self.enumsIndex[nameStr] = enum
|
||||
return enum
|
||||
|
||||
def parse_class(self, cclass):
|
||||
if cclass.name in self.classBl:
|
||||
raise Error('{0} is blacklisted'.format(cclass.name));
|
||||
|
||||
if cclass.name.endswith('Cbs'):
|
||||
_class = CParser._parse_listener(self, cclass)
|
||||
self.interfacesIndex[cclass.name] = _class
|
||||
else:
|
||||
_class = CParser._parse_class(self, 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)
|
||||
|
||||
for cproperty in cclass.properties.values():
|
||||
try:
|
||||
if cproperty.name != 'callbacks':
|
||||
absProperty = CParser._parse_property(self, 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 = CParser.parse_method(self, 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 Error as e:
|
||||
print('Could not parse {0} function: {1}'.format(cMethod.name, e.args[0]))
|
||||
|
||||
for cMethod in cclass.classMethods.values():
|
||||
try:
|
||||
method = CParser.parse_method(self, cMethod, type=Method.Type.Class, namespace=name)
|
||||
_class.add_class_method(method)
|
||||
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 = CParser.parse_method(self, cproperty.setter, namespace=namespace, type=methodType)
|
||||
aproperty.setter = method
|
||||
if cproperty.getter is not None:
|
||||
method = CParser.parse_method(self, 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 = CParser._parse_listener_property(self, 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 = CParser.parse_type(self, event.returnArgument)
|
||||
for arg in event.arguments:
|
||||
argName = ArgName()
|
||||
argName.from_snake_case(arg.name)
|
||||
argument = Argument(argName, CParser.parse_type(self, 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 CParser._is_blacklisted(self, name):
|
||||
raise Error('{0} is blacklisted'.format(name.to_c()));
|
||||
|
||||
method = Method(name, type=type)
|
||||
method.returnType = CParser.parse_type(self, 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 = CParser.parse_type(self, 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 = CParser.parse_c_base_type(self, 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:
|
||||
#params = {'classDesc': self.classesIndex[cType.ctype]}
|
||||
#if 'const' in cType.completeType.split(' '):
|
||||
#params['isconst'] = True
|
||||
absType = ClassType(cType.ctype)
|
||||
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 == '*':
|
||||
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))
|
||||
51976
wrappers/cpp/api.xml
Normal file
51976
wrappers/cpp/api.xml
Normal file
File diff suppressed because it is too large
Load diff
78
wrappers/cpp/class_header.mustache
Normal file
78
wrappers/cpp/class_header.mustache
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef {{define}}
|
||||
#define {{define}}
|
||||
|
||||
{{#includes}}
|
||||
{{#external}}
|
||||
#include <{{name}}>
|
||||
{{/external}}
|
||||
{{#internal}}
|
||||
#include "{{name}}.hh"
|
||||
{{/internal}}
|
||||
{{/includes}}
|
||||
|
||||
{{#_class}}{{#isfactory}}
|
||||
#include "config.hh"
|
||||
{{/isfactory}}{{/_class}}
|
||||
|
||||
#include "linphone/linphonecore.h"
|
||||
#include "linphone/linphone_tunnel.h"
|
||||
#include "linphone/linphonecore_utils.h"
|
||||
|
||||
namespace linphone {
|
||||
|
||||
{{#priorDeclarations}}
|
||||
class {{{name}}};
|
||||
{{/priorDeclarations}}
|
||||
|
||||
{{#_class}}
|
||||
class {{className}}: public {{{parentClassName}}} {
|
||||
{{#friendClasses}}
|
||||
friend class {{name}};
|
||||
{{/friendClasses}}
|
||||
|
||||
public:
|
||||
{{#isNotListener}}
|
||||
{{{className}}}(::belle_sip_object_t *ptr, bool takeRef=true);
|
||||
{{/isNotListener}}
|
||||
|
||||
{{#ismonolistenable}}
|
||||
void setListener(const std::shared_ptr<{{{listenerClassName}}}> &listener);
|
||||
{{/ismonolistenable}}
|
||||
|
||||
{{#ismultilistenable}}
|
||||
void addListener(std::shared_ptr<{{{listenerClassName}}}> &listener);
|
||||
void removeListener(std::shared_ptr<{{{listenerClassName}}}> &listener);
|
||||
{{/ismultilistenable}}
|
||||
|
||||
public:
|
||||
{{#isfactory}}
|
||||
std::shared_ptr<Core> createCore(const std::shared_ptr<CoreListener> & cbs, const std::string & configPath, const std::string & factoryConfigPath) const;
|
||||
std::shared_ptr<Core> createCoreWithConfig(const std::shared_ptr<CoreListener> & cbs, const std::shared_ptr<Config> & config) const;
|
||||
{{/isfactory}}
|
||||
|
||||
{{#methods}}
|
||||
{{{prototype}}}
|
||||
|
||||
{{/methods}}
|
||||
{{#staticMethods}}
|
||||
{{{prototype}}}
|
||||
|
||||
{{/staticMethods}}
|
||||
|
||||
{{#ismultilistenable}}
|
||||
private:
|
||||
static {{{cListenerName}}} *createCallbacks(const std::shared_ptr<{{{listenerClassName}}}> &listener);
|
||||
{{/ismultilistenable}}
|
||||
|
||||
{{#islistenable}}
|
||||
private:
|
||||
{{#wrapperCbs}}
|
||||
{{decl}}
|
||||
{{/wrapperCbs}}
|
||||
{{/islistenable}}
|
||||
};
|
||||
{{/_class}}
|
||||
|
||||
};
|
||||
|
||||
#endif // {{define}}
|
||||
106
wrappers/cpp/class_impl.mustache
Normal file
106
wrappers/cpp/class_impl.mustache
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include "linphone.hh"
|
||||
|
||||
using namespace {{{namespace}}};
|
||||
|
||||
{{#_class}}
|
||||
|
||||
{{#isNotListener}}
|
||||
{{{namespace}}}::{{{className}}}::{{{className}}}(::belle_sip_object_t *ptr, bool takeRef): {{{parentClassName}}}(ptr, takeRef) {}
|
||||
{{/isNotListener}}
|
||||
|
||||
{{#ismonolistenable}}
|
||||
void {{{namespace}}}::{{{className}}}::setListener(const std::shared_ptr<{{{listenerClassName}}}> & listener) {
|
||||
ListenableObject::setListener(std::static_pointer_cast<Listener>(listener));
|
||||
{{{cListenerName}}} *cbs = {{{cCbsGetter}}}(({{{cClassName}}} *)mPrivPtr);
|
||||
if (listener == nullptr) {
|
||||
{{#wrapperCbs}}
|
||||
{{{callbackSetter}}}(cbs, NULL);
|
||||
{{/wrapperCbs}}
|
||||
} else {
|
||||
{{#wrapperCbs}}
|
||||
{{{callbackSetter}}}(cbs, {{{cbName}}});
|
||||
{{/wrapperCbs}}
|
||||
}
|
||||
}
|
||||
{{/ismonolistenable}}
|
||||
|
||||
{{#ismultilistenable}}
|
||||
{{{cListenerName}}} *{{{className}}}::createCallbacks(const std::shared_ptr<{{{listenerClassName}}}> &listener) {
|
||||
{{{cListenerName}}} *cbs = {{{listenerCreator}}}(linphone_factory_get());
|
||||
{{{userDataSetter}}}(cbs, listener.get());
|
||||
{{#wrapperCbs}}
|
||||
{{{callbackSetter}}}(cbs, {{{cbName}}});
|
||||
{{/wrapperCbs}}
|
||||
return cbs;
|
||||
}
|
||||
|
||||
void {{{className}}}::addListener(std::shared_ptr<{{{listenerClassName}}}> &listener) {
|
||||
MultiListenableObject::addListener(std::static_pointer_cast<Listener,{{{listenerClassName}}}>(listener));
|
||||
{{{cListenerName}}} *cbs = createCallbacks(listener);
|
||||
{{{callbacksAdder}}}(({{{cClassName}}} *)mPrivPtr, cbs);
|
||||
listener->setCallbacks((::belle_sip_object_t *)cbs);
|
||||
belle_sip_object_unref(cbs);
|
||||
}
|
||||
|
||||
void {{{className}}}::removeListener(std::shared_ptr<{{{listenerClassName}}}> &listener) {
|
||||
::belle_sip_object_t *cbs = belle_sip_object_ref(listener->getCallbacks());
|
||||
{{{callbacksRemover}}}(({{{cClassName}}} *)mPrivPtr, ({{{cListenerName}}} *)cbs);
|
||||
listener->setCallbacks(NULL);
|
||||
belle_sip_object_unref(cbs);
|
||||
|
||||
MultiListenableObject::removeListener(listener);
|
||||
}
|
||||
{{/ismultilistenable}}
|
||||
|
||||
{{#isfactory}}
|
||||
std::shared_ptr<Core> Factory::createCore(const std::shared_ptr<CoreListener> & cbs, const std::string & configPath, const std::string & factoryConfigPath) const {
|
||||
::LinphoneFactory *factory = linphone_factory_get();
|
||||
::LinphoneCoreCbs *c_cbs = cbs != nullptr ? Core::createCallbacks(cbs) : NULL;
|
||||
::LinphoneCore *core_ptr = linphone_factory_create_core(factory, c_cbs, configPath.c_str(), factoryConfigPath.c_str());
|
||||
std::shared_ptr<Core> core = cPtrToSharedPtr<Core>((belle_sip_object_t *)core_ptr, false);
|
||||
if (core != nullptr && cbs != nullptr) {
|
||||
std::static_pointer_cast<MultiListenableObject,Core>(core)->addListener(cbs);
|
||||
cbs->setCallbacks((belle_sip_object_t *)c_cbs);
|
||||
}
|
||||
if (c_cbs) linphone_core_cbs_unref(c_cbs);
|
||||
return core;
|
||||
}
|
||||
|
||||
std::shared_ptr<Core> Factory::createCoreWithConfig(const std::shared_ptr<CoreListener> & cbs, const std::shared_ptr<Config> & config) const {
|
||||
::LinphoneFactory *factory = linphone_factory_get();
|
||||
::LinphoneCoreCbs *c_cbs = cbs != nullptr ? Core::createCallbacks(cbs) : NULL;
|
||||
::LinphoneCore *core_ptr = linphone_factory_create_core_with_config(factory, c_cbs, (::LinphoneConfig *)sharedPtrToCPtr(config));
|
||||
std::shared_ptr<Core> core = cPtrToSharedPtr<Core>((belle_sip_object_t *)core_ptr, false);
|
||||
if (core != nullptr && cbs != nullptr) {
|
||||
std::static_pointer_cast<MultiListenableObject,Core>(core)->addListener(cbs);
|
||||
cbs->setCallbacks((belle_sip_object_t *)c_cbs);
|
||||
}
|
||||
if (c_cbs) linphone_core_cbs_unref(c_cbs);
|
||||
return core;
|
||||
}
|
||||
{{/isfactory}}
|
||||
|
||||
{{#methods}}
|
||||
{{{implPrototype}}} {
|
||||
{{{sourceCode}}}
|
||||
}
|
||||
{{/methods}}
|
||||
|
||||
{{#staticMethods}}
|
||||
{{{implPrototype}}} {
|
||||
{{{sourceCode}}}
|
||||
}
|
||||
{{/staticMethods}}
|
||||
|
||||
{{#wrapperCbs}}
|
||||
{{{returnType}}} {{{className}}}::{{{cbName}}}({{{declArgs}}}) {
|
||||
{{#ismonolistenable}}std::shared_ptr<{{{cppListenerName}}}> listener = std::static_pointer_cast<{{{cppListenerName}}},Listener>(getListenerFromObject((::belle_sip_object_t *){{{firstArgName}}}));{{/ismonolistenable}}
|
||||
{{#ismultilistenable}}
|
||||
LinphoneCoreCbs *cbs = linphone_core_get_current_callbacks(lc);
|
||||
CoreListener *listener = (CoreListener *)linphone_core_cbs_get_user_data(cbs);
|
||||
{{/ismultilistenable}}
|
||||
{{#hasReturnValue}}return {{/hasReturnValue}}{{{cppMethodCallingLine}}}
|
||||
}
|
||||
{{/wrapperCbs}}
|
||||
|
||||
{{/_class}}
|
||||
16
wrappers/cpp/enums_header.mustache
Normal file
16
wrappers/cpp/enums_header.mustache
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _ENUMS_HH
|
||||
#define _ENUMS_HH
|
||||
|
||||
namespace linphone {
|
||||
|
||||
{{#enums}}
|
||||
enum {{name}} {
|
||||
{{#values}}
|
||||
{{name}}{{#notLast}},{{/notLast}}
|
||||
{{/values}}
|
||||
};
|
||||
|
||||
{{/enums}}
|
||||
};
|
||||
|
||||
#endif //_ENUMS_HH
|
||||
1
wrappers/cpp/genapixml.py
Symbolic link
1
wrappers/cpp/genapixml.py
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../tools/genapixml.py
|
||||
688
wrappers/cpp/genheaders.py
Executable file
688
wrappers/cpp/genheaders.py
Executable file
|
|
@ -0,0 +1,688 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
|
||||
import pystache
|
||||
import re
|
||||
import argparse
|
||||
import os
|
||||
import genapixml as CApi
|
||||
import abstractapi as AbsApi
|
||||
|
||||
|
||||
class CppTranslator(object):
|
||||
sharedPtrTypeExtractor = re.compile('^(const )?std::shared_ptr<(.+)>( &)?$')
|
||||
|
||||
def __init__(self):
|
||||
self.ignore = []
|
||||
self.ambigousTypes = ['LinphonePayloadType']
|
||||
|
||||
def is_ambigous_type(self, _type):
|
||||
return _type.name in self.ambigousTypes or (_type.name == 'list' and CppTranslator.is_ambigous_type(self, _type.containedTypeDesc))
|
||||
|
||||
@staticmethod
|
||||
def translate_enum(enum):
|
||||
enumDict = {}
|
||||
enumDict['name'] = enum.name.to_camel_case()
|
||||
enumDict['values'] = []
|
||||
i = 0
|
||||
for enumValue in enum.values:
|
||||
enumValDict = CppTranslator.translate_enum_value(enumValue)
|
||||
enumValDict['notLast'] = (i != len(enum.values)-1)
|
||||
enumDict['values'].append(enumValDict)
|
||||
i += 1
|
||||
return enumDict
|
||||
|
||||
@staticmethod
|
||||
def translate_enum_value(enumValue):
|
||||
enumValueDict = {}
|
||||
enumValueDict['name'] = CppTranslator.translate_enum_value_name(enumValue.name)
|
||||
return enumValueDict
|
||||
|
||||
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)))
|
||||
|
||||
islistenable = _class.listenerInterface is not None
|
||||
ismonolistenable = (islistenable and not _class.multilistener)
|
||||
ismultilistenable = (islistenable and _class.multilistener)
|
||||
|
||||
classDict = {}
|
||||
classDict['islistenable'] = islistenable
|
||||
classDict['isnotlistenable'] = not islistenable
|
||||
classDict['ismonolistenable'] = ismonolistenable
|
||||
classDict['ismultilistenable'] = ismultilistenable
|
||||
classDict['isNotListener'] = True
|
||||
classDict['isfactory'] = (_class.name.to_c() == 'LinphoneFactory')
|
||||
classDict['parentClassName'] = None
|
||||
classDict['className'] = CppTranslator.translate_class_name(_class.name)
|
||||
classDict['cClassName'] = '::' + _class.name.to_c()
|
||||
classDict['parentClassName'] = 'Object'
|
||||
classDict['methods'] = []
|
||||
classDict['staticMethods'] = []
|
||||
classDict['wrapperCbs'] = []
|
||||
classDict['friendClasses'] = []
|
||||
|
||||
if _class.name.to_c() == 'LinphoneCore':
|
||||
classDict['friendClasses'].append({'name': 'Factory'});
|
||||
|
||||
if islistenable:
|
||||
classDict['listenerClassName'] = CppTranslator.translate_class_name(_class.listenerInterface.name)
|
||||
classDict['cListenerName'] = _class.listenerInterface.name.to_c()
|
||||
for method in _class.listenerInterface.methods:
|
||||
classDict['wrapperCbs'].append(CppTranslator._generate_wrapper_callback(self, _class, method))
|
||||
|
||||
if ismonolistenable:
|
||||
classDict['cCbsGetter'] = _class.name.to_snake_case(fullName=True) + '_get_callbacks'
|
||||
classDict['cppListenerName'] = CppTranslator.translate_class_name(_class.listenerInterface.name)
|
||||
classDict['parentClassName'] = 'ListenableObject'
|
||||
elif ismultilistenable:
|
||||
classDict['parentClassName'] = 'MultiListenableObject'
|
||||
classDict['listenerCreator'] = 'linphone_factory_create_' + _class.listenerInterface.name.to_snake_case()[:-len('_listener')] + '_cbs'
|
||||
classDict['callbacksAdder'] = _class.name.to_snake_case(fullName=True)+ '_add_callbacks'
|
||||
classDict['callbacksRemover'] = _class.name.to_snake_case(fullName=True)+ '_remove_callbacks'
|
||||
classDict['userDataSetter'] = _class.listenerInterface.name.to_snake_case(fullName=True)[:-len('_listener')] + '_cbs_set_user_data'
|
||||
|
||||
for property in _class.properties:
|
||||
try:
|
||||
classDict['methods'] += CppTranslator.translate_property(self, property)
|
||||
except AbsApi.Error as e:
|
||||
print('error while translating {0} property: {1}'.format(property.name.to_snake_case(), e.args[0]))
|
||||
|
||||
for method in _class.instanceMethods:
|
||||
try:
|
||||
methodDict = CppTranslator.translate_method(self, method)
|
||||
classDict['methods'].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 method in _class.classMethods:
|
||||
try:
|
||||
methodDict = CppTranslator.translate_method(self, method)
|
||||
classDict['staticMethods'].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 _generate_wrapper_callback(self, listenedClass, method):
|
||||
namespace = method.find_first_ancestor_by_type(AbsApi.Namespace)
|
||||
listenedClass = method.find_first_ancestor_by_type(AbsApi.Interface).listenedClass
|
||||
|
||||
params = {}
|
||||
params['name'] = method.name.to_camel_case(lower=True)[2:] + 'Cb'
|
||||
params['name'] = params['name'][0].lower() + params['name'][1:]
|
||||
args = []
|
||||
wrappedArgs = []
|
||||
for arg in method.args:
|
||||
args.append(arg.type.cname + ' ' + arg.name.to_c())
|
||||
wrappedArgs.append(CppTranslator._wrap_c_expression_to_cpp(self, arg.name.to_c(), arg.type, usedNamespace=namespace))
|
||||
params['params'] = ', '.join(args)
|
||||
params['returnType'] = method.returnType.cname
|
||||
|
||||
wrapperCbDict = {}
|
||||
wrapperCbDict['decl'] = 'static {returnType} {name}({params});'.format(**params)
|
||||
wrapperCbDict['cbName'] = params['name']
|
||||
wrapperCbDict['declArgs'] = params['params']
|
||||
#wrapperCbDict['methodName'] = method.name.to_camel_case(lower=True)
|
||||
#wrapperCbDict['wrappedArgs'] = ', '.join(wrappedArgs)
|
||||
wrapperCbDict['firstArgName'] = method.args[0].name.to_c()
|
||||
wrapperCbDict['returnType'] = params['returnType']
|
||||
wrapperCbDict['hasReturnValue'] = (params['returnType'] != 'void')
|
||||
wrapperCbDict['hasNotReturnValue'] = not wrapperCbDict['hasReturnValue']
|
||||
wrapperCbDict['callbackSetter'] = listenedClass.name.to_snake_case(fullName=True) + '_cbs_set_' + method.name.to_snake_case()[3:]
|
||||
wrapperCbDict['cppMethodCallingLine'] = 'listener->{methodName}({wrappedArgs});'.format(
|
||||
methodName=method.name.to_camel_case(lower=True),
|
||||
wrappedArgs=', '.join(wrappedArgs))
|
||||
wrapperCbDict['cppMethodCallingLine'] = CppTranslator._wrap_cpp_expression_to_c(self,
|
||||
wrapperCbDict['cppMethodCallingLine'],
|
||||
method.returnType)
|
||||
return wrapperCbDict
|
||||
|
||||
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)))
|
||||
|
||||
intDict = {}
|
||||
intDict['inheritFrom'] = {'name': 'Listener'}
|
||||
intDict['className'] = CppTranslator.translate_class_name(interface.name)
|
||||
intDict['constructor'] = None
|
||||
intDict['parentClassName'] = 'Listener'
|
||||
intDict['isNotListener'] = False
|
||||
intDict['methods'] = []
|
||||
for method in interface.methods:
|
||||
try:
|
||||
methodDict = CppTranslator.translate_method(self, method, genImpl=False)
|
||||
intDict['methods'].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 intDict
|
||||
|
||||
def translate_property(self, property):
|
||||
res = []
|
||||
if property.getter is not None:
|
||||
res.append(CppTranslator.translate_method(self, property.getter))
|
||||
if property.setter is not None:
|
||||
res.append(CppTranslator.translate_method(self, property.setter))
|
||||
return res
|
||||
|
||||
def translate_method(self, method, 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)))
|
||||
|
||||
namespace = method.find_first_ancestor_by_type(AbsApi.Namespace)
|
||||
|
||||
methodElems = {}
|
||||
methodElems['return'] = CppTranslator.translate_type(self, method.returnType)
|
||||
methodElems['name'] = CppTranslator.translate_method_name(method.name)
|
||||
|
||||
methodElems['params'] = ''
|
||||
for arg in method.args:
|
||||
if arg is not method.args[0]:
|
||||
methodElems['params'] += ', '
|
||||
methodElems['params'] += CppTranslator.translate_argument(self, arg)
|
||||
|
||||
methodElems['const'] = ' const' if method.constMethod else ''
|
||||
methodElems['semicolon'] = ';'
|
||||
if type(method.parent) is AbsApi.Class and method.type == AbsApi.Method.Type.Class:
|
||||
methodElems['methodType'] = 'static '
|
||||
elif type(method.parent) is AbsApi.Interface:
|
||||
methodElems['methodType'] = 'virtual '
|
||||
if isinstance(method.returnType, AbsApi.BaseType) and method.returnType.name == 'void':
|
||||
methodElems['semicolon'] = ' {}'
|
||||
else:
|
||||
methodElems['semicolon'] = ' = 0;'
|
||||
else:
|
||||
methodElems['methodType'] = ''
|
||||
|
||||
methodDict = {}
|
||||
methodDict['prototype'] = '{methodType}{return} {name}({params}){const}{semicolon}'.format(**methodElems)
|
||||
|
||||
if genImpl:
|
||||
if not CppTranslator.is_ambigous_type(self, method.returnType):
|
||||
methodElems['implReturn'] = CppTranslator.translate_type(self, method.returnType, namespace=namespace)
|
||||
else:
|
||||
methodElems['implReturn'] = CppTranslator.translate_type(self, method.returnType, namespace=None)
|
||||
|
||||
methodElems['longname'] = CppTranslator.translate_method_name(method.name, recursive=True)
|
||||
methodElems['implParams'] = ''
|
||||
for arg in method.args:
|
||||
if arg is not method.args[0]:
|
||||
methodElems['implParams'] += ', '
|
||||
methodElems['implParams'] += CppTranslator.translate_argument(self, arg, namespace=namespace)
|
||||
|
||||
methodDict['implPrototype'] = '{implReturn} {longname}({implParams}){const}'.format(**methodElems)
|
||||
methodDict['sourceCode' ] = CppTranslator._generate_source_code(self, method, usedNamespace=namespace)
|
||||
|
||||
return methodDict
|
||||
|
||||
def _generate_source_code(self, method, usedNamespace=None):
|
||||
nsName = usedNamespace.name if usedNamespace is not None else None
|
||||
params = {
|
||||
'functionName': method.name.to_c(),
|
||||
'args': CppTranslator._generate_wrapped_arguments(self, method, usedNamespace=usedNamespace)
|
||||
}
|
||||
|
||||
if method.name.to_camel_case(lower=True) != 'setListener':
|
||||
cExpr = '{functionName}({args})'.format(**params)
|
||||
cppExpr = CppTranslator._wrap_c_expression_to_cpp(self, cExpr, method.returnType, usedNamespace=usedNamespace)
|
||||
else:
|
||||
cppExpr = 'ListenableObject::setListener(std::static_pointer_cast<Listener>({0}))'.format(method.args[0].name.to_snake_case())
|
||||
|
||||
if type(method.returnType) is AbsApi.BaseType and method.returnType.name == 'void' and not method.returnType.isref:
|
||||
return cppExpr + ';'
|
||||
else:
|
||||
return 'return {0};'.format(cppExpr)
|
||||
|
||||
def _generate_wrapped_arguments(self, method, usedNamespace=None):
|
||||
args = []
|
||||
if method.type == AbsApi.Method.Type.Instance:
|
||||
_class = method.find_first_ancestor_by_type(AbsApi.Class)
|
||||
argStr = '(::{0} *)mPrivPtr'.format(_class.name.to_camel_case(fullName=True))
|
||||
args.append(argStr)
|
||||
|
||||
for arg in method.args:
|
||||
paramName = arg.name.to_camel_case(lower=True)
|
||||
args.append(CppTranslator._wrap_cpp_expression_to_c(self, paramName, arg.type, usedNamespace=usedNamespace))
|
||||
|
||||
return ', '.join(args)
|
||||
|
||||
def _wrap_cpp_expression_to_c(self, cppExpr, exprtype, usedNamespace=None):
|
||||
if type(exprtype) is AbsApi.BaseType:
|
||||
if exprtype.name == 'string':
|
||||
cExpr = 'cppStringToC({0})'.format(cppExpr);
|
||||
elif exprtype not in ['void', 'string', 'string_array'] and exprtype.isref:
|
||||
cExpr = '&' + cppExpr
|
||||
else:
|
||||
cExpr = cppExpr
|
||||
elif type(exprtype) is AbsApi.EnumType:
|
||||
cExpr = '(::{0}){1}'.format(exprtype.desc.name.to_c(), cppExpr)
|
||||
elif type(exprtype) is AbsApi.ClassType:
|
||||
param = {}
|
||||
param['ptrType'] = CppTranslator.translate_class_type(self, exprtype, namespace=usedNamespace)
|
||||
param['ptrType'] = CppTranslator.sharedPtrTypeExtractor.match(param['ptrType']).group(2)
|
||||
param['cPtrType'] = exprtype.desc.name.to_c()
|
||||
param['cppExpr'] = cppExpr
|
||||
param['object'] = 'const Object' if exprtype.isconst else 'Object'
|
||||
cExpr = '(::{cPtrType} *)sharedPtrToCPtr(std::static_pointer_cast<{object},{ptrType}>({cppExpr}))'.format(**param)
|
||||
elif type(exprtype) is AbsApi.ListType:
|
||||
if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string':
|
||||
cExpr = 'StringBctbxListWrapper({0}).c_list()'.format(cppExpr)
|
||||
elif type(exprtype.containedTypeDesc) is AbsApi.Class:
|
||||
ptrType = CppTranslator.translate_class_type(exprtype, namespace=usedNamespace)
|
||||
ptrType = CppTranslator.sharedPtrTypeExtractor.match(ptrType).group(2)
|
||||
cExpr = 'ObjectBctbxListWrapper<{0}>({1}).c_list()'.format(ptrType, cppExpr)
|
||||
else:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of enums or basic C types is not supported')
|
||||
|
||||
return cExpr
|
||||
|
||||
def _wrap_c_expression_to_cpp(self, cExpr, exprtype, usedNamespace=None):
|
||||
if type(exprtype) is AbsApi.BaseType:
|
||||
if exprtype.name == 'void' and not exprtype.isref:
|
||||
return cExpr
|
||||
elif exprtype.name == 'string':
|
||||
return 'cStringToCpp({0})'.format(cExpr)
|
||||
elif exprtype.name == 'string_array':
|
||||
return 'cStringArrayToCppList({0})'.format(cExpr)
|
||||
else:
|
||||
return cExpr
|
||||
elif type(exprtype) is AbsApi.EnumType:
|
||||
cppEnumName = CppTranslator.translate_enum_type(self, exprtype, namespace=usedNamespace)
|
||||
return '({0}){1}'.format(cppEnumName, cExpr)
|
||||
elif type(exprtype) is AbsApi.ClassType:
|
||||
cppReturnType = CppTranslator.translate_class_type(self, exprtype, namespace=usedNamespace)
|
||||
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
|
||||
|
||||
if type(exprtype.parent) is AbsApi.Method and len(exprtype.parent.name.words) >=1 and (exprtype.parent.name.words == ['new'] or exprtype.parent.name.words[0] == 'create'):
|
||||
return 'cPtrToSharedPtr<{0}>((::belle_sip_object_t *){1}, false)'.format(cppReturnType, cExpr)
|
||||
else:
|
||||
return 'cPtrToSharedPtr<{0}>((::belle_sip_object_t *){1})'.format(cppReturnType, cExpr)
|
||||
elif type(exprtype) is AbsApi.ListType:
|
||||
if type(exprtype.containedTypeDesc) is AbsApi.BaseType and exprtype.containedTypeDesc.name == 'string':
|
||||
return 'bctbxStringListToCppList({0})'.format(cExpr)
|
||||
elif type(exprtype.containedTypeDesc) is AbsApi.ClassType:
|
||||
cppReturnType = CppTranslator.translate_class_type(self, exprtype.containedTypeDesc, namespace=usedNamespace)
|
||||
cppReturnType = CppTranslator.sharedPtrTypeExtractor.match(cppReturnType).group(2)
|
||||
return 'bctbxObjectListToCppList<{0}>({1})'.format(cppReturnType, cExpr)
|
||||
else:
|
||||
raise AbsApi.Error('translation of bctbx_list_t of enums or basic C types is not supported')
|
||||
else:
|
||||
return cExpr
|
||||
|
||||
def translate_argument(self, arg, **params):
|
||||
return '{0} {1}'.format(CppTranslator.translate_type(self, arg.type, **params), CppTranslator.translate_argument_name(arg.name))
|
||||
|
||||
def translate_type(self, aType, **params):
|
||||
if type(aType) is AbsApi.BaseType:
|
||||
return CppTranslator.translate_base_type(self, aType)
|
||||
elif type(aType) is AbsApi.EnumType:
|
||||
return CppTranslator.translate_enum_type(self, aType, **params)
|
||||
elif type(aType) is AbsApi.ClassType:
|
||||
return CppTranslator.translate_class_type(self, aType, **params)
|
||||
elif type(aType) is AbsApi.ListType:
|
||||
return CppTranslator.translate_list_type(self, aType, **params)
|
||||
else:
|
||||
CppTranslator.fail(aType)
|
||||
|
||||
def translate_base_type(self, _type):
|
||||
if _type.name == 'void':
|
||||
if _type.isref:
|
||||
return 'void *'
|
||||
else:
|
||||
return 'void'
|
||||
elif _type.name == 'boolean':
|
||||
res = 'bool'
|
||||
elif _type.name == 'character':
|
||||
res = 'char'
|
||||
elif _type.name == 'size':
|
||||
res = 'size_t'
|
||||
elif _type.name == 'time':
|
||||
res = 'time_t'
|
||||
elif _type.name == 'integer':
|
||||
if _type.size is None:
|
||||
res = 'int'
|
||||
elif isinstance(_type.size, str):
|
||||
res = _type.size
|
||||
else:
|
||||
res = 'int{0}_t'.format(_type.size)
|
||||
elif _type.name == 'floatant':
|
||||
if _type.size is not None and _type.size == 'double':
|
||||
res = 'double'
|
||||
else:
|
||||
res = 'float'
|
||||
elif _type.name == 'string':
|
||||
res = 'std::string'
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
res += ' &'
|
||||
elif _type.name == 'string_array':
|
||||
res = 'std::list<std::string>'
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
res += ' &'
|
||||
else:
|
||||
raise AbsApi.Error('\'{0}\' is not a base abstract type'.format(_type.name))
|
||||
|
||||
if _type.isUnsigned:
|
||||
if _type.name == 'integer' and isinstance(_type.size, int):
|
||||
res = 'u' + res
|
||||
else:
|
||||
res = 'unsigned ' + res
|
||||
|
||||
if _type.isconst:
|
||||
if _type.name not in ['string', 'string_array'] or type(_type.parent) is AbsApi.Argument:
|
||||
res = 'const ' + res
|
||||
|
||||
if _type.isref:
|
||||
res += ' &'
|
||||
return res
|
||||
|
||||
def translate_enum_type(self, _type, **params):
|
||||
if _type.name in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_type.name))
|
||||
|
||||
if _type.desc is None:
|
||||
raise AbsApi.Error('{0} has not been fixed'.format(_type.name.to_camel_case(fullName=True)))
|
||||
|
||||
if 'namespace' in params:
|
||||
nsName = params['namespace'].name if params['namespace'] is not None else None
|
||||
else:
|
||||
method = _type.find_first_ancestor_by_type(AbsApi.Method)
|
||||
nsName = AbsApi.Name.find_common_parent(_type.desc.name, method.name)
|
||||
|
||||
return CppTranslator.translate_enum_name(_type.desc.name, recursive=True, topAncestor=nsName)
|
||||
|
||||
def translate_class_type(self, _type, **params):
|
||||
if _type.name in self.ignore:
|
||||
raise AbsApi.Error('{0} has been escaped'.format(_type.name))
|
||||
|
||||
if _type.desc is None:
|
||||
raise AbsApi.Error('{0} has not been fixed'.format(_type.name))
|
||||
|
||||
if 'namespace' in params:
|
||||
nsName = params['namespace'].name if params['namespace'] is not None else None
|
||||
else:
|
||||
method = _type.find_first_ancestor_by_type(AbsApi.Method)
|
||||
nsName = AbsApi.Name.find_common_parent(_type.desc.name, method.name)
|
||||
|
||||
res = CppTranslator.translate_class_name(_type.desc.name, recursive=True, topAncestor=nsName)
|
||||
|
||||
if _type.isconst:
|
||||
res = 'const ' + res
|
||||
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
return 'const std::shared_ptr<{0}> &'.format(res)
|
||||
else:
|
||||
return 'std::shared_ptr<{0}>'.format(res)
|
||||
|
||||
def translate_list_type(self, _type, **params):
|
||||
if _type.containedTypeDesc is None:
|
||||
raise AbsApi.Error('{0} has not been fixed'.format(_type.containedTypeName))
|
||||
elif isinstance(_type.containedTypeDesc, AbsApi.BaseType):
|
||||
res = CppTranslator.translate_type(self, _type.containedTypeDesc)
|
||||
else:
|
||||
res = CppTranslator.translate_type(self, _type.containedTypeDesc, **params)
|
||||
|
||||
if type(_type.parent) is AbsApi.Argument:
|
||||
return 'const std::list<{0} > &'.format(res)
|
||||
else:
|
||||
return 'std::list<{0} >'.format(res)
|
||||
|
||||
@staticmethod
|
||||
def translate_name(aName, **params):
|
||||
if type(aName) is AbsApi.ClassName:
|
||||
return CppTranslator.translate_class_name(aName, **params)
|
||||
elif type(aName) is AbsApi.InterfaceName:
|
||||
return CppTranslator.translate_class_name(aName, **params)
|
||||
elif type(aName) is AbsApi.EnumName:
|
||||
return CppTranslator.translate_enum_name(aName, **params)
|
||||
elif type(aName) is AbsApi.EnumValueName:
|
||||
return CppTranslator.translate_enum_value_name(aName, **params)
|
||||
elif type(aName) is AbsApi.MethodName:
|
||||
return CppTranslator.translate_method_name(aName, **params)
|
||||
elif type(aName) is AbsApi.ArgName:
|
||||
return CppTranslator.translate_argument_name(aName, **params)
|
||||
elif type(aName) is AbsApi.NamespaceName:
|
||||
return CppTranslator.translate_namespace_name(aName, **params)
|
||||
elif type(aName) is AbsApi.PropertyName:
|
||||
return CppTranslator.translate_property_name(aName, **params)
|
||||
else:
|
||||
CppTranslator.fail(aName)
|
||||
|
||||
@staticmethod
|
||||
def translate_class_name(name, recursive=False, topAncestor=None):
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return name.to_camel_case()
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_name(name.prev, **params) + '::' + name.to_camel_case()
|
||||
|
||||
@staticmethod
|
||||
def translate_enum_name(name, recursive=False, topAncestor=None):
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_class_name(name, **params)
|
||||
|
||||
@staticmethod
|
||||
def translate_enum_value_name(name, recursive=False, topAncestor=None):
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_enum_name(name.prev, **params) + name.to_camel_case()
|
||||
|
||||
@staticmethod
|
||||
def translate_method_name(name, recursive=False, topAncestor=None):
|
||||
translatedName = name.to_camel_case(lower=True)
|
||||
if translatedName == 'new':
|
||||
translatedName = '_new'
|
||||
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return translatedName
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_name(name.prev, **params) + '::' + translatedName
|
||||
|
||||
@staticmethod
|
||||
def translate_namespace_name(name, recursive=False, topAncestor=None):
|
||||
if name.prev is None or not recursive or name.prev is topAncestor:
|
||||
return name.concatenate()
|
||||
else:
|
||||
params = {'recursive': recursive, 'topAncestor': topAncestor}
|
||||
return CppTranslator.translate_namespace_name(name.prev, **params) + '::' + name.concatenate()
|
||||
|
||||
@staticmethod
|
||||
def translate_argument_name(name):
|
||||
return name.to_camel_case(lower=True)
|
||||
|
||||
@staticmethod
|
||||
def translate_property_name(name):
|
||||
CppTranslator.translate_argument_name(name)
|
||||
|
||||
@staticmethod
|
||||
def fail(obj):
|
||||
raise AbsApi.Error('Cannot translate {0} type'.format(type(obj)))
|
||||
|
||||
|
||||
class EnumsHeader(object):
|
||||
def __init__(self, translator):
|
||||
self.translator = translator
|
||||
self.enums = []
|
||||
|
||||
def add_enum(self, enum):
|
||||
self.enums.append(self.translator.translate_enum(enum))
|
||||
|
||||
|
||||
class ClassHeader(object):
|
||||
def __init__(self, _class, translator, ignore=[]):
|
||||
if type(_class) is AbsApi.Class:
|
||||
self._class = translator.translate_class(_class)
|
||||
else:
|
||||
self._class = translator.translate_interface(_class)
|
||||
|
||||
self.define = '_{0}_HH'.format(_class.name.to_snake_case(upper=True, fullName=True))
|
||||
self.filename = '{0}.hh'.format(_class.name.to_snake_case())
|
||||
self.priorDeclarations = []
|
||||
self.private_type = _class.name.to_camel_case(fullName=True)
|
||||
self.ignore = ignore
|
||||
|
||||
self.includes = {'internal': [], 'external': []}
|
||||
includes = ClassHeader.needed_includes(self, _class)
|
||||
for include in includes['internal']:
|
||||
if _class.name.to_camel_case(fullName=True) == 'LinphoneCore' or (isinstance(_class, AbsApi.Interface) and _class.listenedClass is not None and include == _class.listenedClass.name.to_snake_case()):
|
||||
if include == 'enums':
|
||||
self.includes['internal'].append({'name': include})
|
||||
else:
|
||||
className = AbsApi.ClassName()
|
||||
className.from_snake_case(include)
|
||||
self.priorDeclarations.append({'name': className.to_camel_case()})
|
||||
else:
|
||||
self.includes['internal'].append({'name': include})
|
||||
|
||||
for include in includes['external']:
|
||||
self.includes['external'].append({'name': include})
|
||||
|
||||
def needed_includes(self, _class):
|
||||
includes = {'internal': set(), 'external': set()}
|
||||
|
||||
if type(_class) is AbsApi.Class:
|
||||
includes['internal'].add('object')
|
||||
|
||||
for property in _class.properties:
|
||||
if property.setter is not None:
|
||||
ClassHeader._needed_includes_from_method(self, property.setter, includes)
|
||||
if property.getter is not None:
|
||||
ClassHeader._needed_includes_from_method(self, property.getter, includes)
|
||||
|
||||
if type(_class) is AbsApi.Class:
|
||||
methods = _class.classMethods + _class.instanceMethods
|
||||
else:
|
||||
methods = _class.methods
|
||||
|
||||
for method in methods:
|
||||
ClassHeader._needed_includes_from_type(self, method.returnType, includes)
|
||||
for arg in method.args:
|
||||
ClassHeader._needed_includes_from_type(self, arg.type, includes)
|
||||
|
||||
if isinstance(_class, AbsApi.Class) and _class.listenerInterface is not None:
|
||||
includes['internal'].add(_class.listenerInterface.name.to_snake_case())
|
||||
|
||||
currentClassInclude = _class.name.to_snake_case()
|
||||
if currentClassInclude in includes['internal']:
|
||||
includes['internal'].remove(currentClassInclude)
|
||||
|
||||
return includes
|
||||
|
||||
def _needed_includes_from_method(self, method, includes):
|
||||
ClassHeader._needed_includes_from_type(self, method.returnType, includes)
|
||||
for arg in method.args:
|
||||
ClassHeader._needed_includes_from_type(self, arg.type, includes)
|
||||
|
||||
def _needed_includes_from_type(self, _type, includes):
|
||||
if isinstance(_type, AbsApi.ClassType):
|
||||
includes['external'].add('memory')
|
||||
if _type.desc is not None and _type.name not in self.ignore:
|
||||
includes['internal'].add(_type.desc.name.to_snake_case())
|
||||
elif isinstance(_type, AbsApi.EnumType):
|
||||
includes['internal'].add('enums')
|
||||
elif isinstance(_type, AbsApi.BaseType):
|
||||
if _type.name == 'integer' and isinstance(_type.size, int):
|
||||
includes['external'].add('cstdint')
|
||||
elif _type.name == 'string':
|
||||
includes['external'].add('string')
|
||||
elif isinstance(_type, AbsApi.ListType):
|
||||
includes['external'].add('list')
|
||||
ClassHeader._needed_includes_from_type(self, _type.containedTypeDesc, includes)
|
||||
|
||||
|
||||
class MainHeader(object):
|
||||
def __init__(self):
|
||||
self.includes = []
|
||||
self.define = '_LINPHONE_HH'
|
||||
|
||||
def add_include(self, include):
|
||||
self.includes.append({'name': include})
|
||||
|
||||
|
||||
class ClassImpl(object):
|
||||
def __init__(self, parsedClass, translatedClass):
|
||||
self._class = translatedClass
|
||||
self.filename = parsedClass.name.to_snake_case() + '.cc'
|
||||
self.internalIncludes = []
|
||||
self.internalIncludes.append({'name': parsedClass.name.to_snake_case() + '.hh'})
|
||||
self.internalIncludes.append({'name': 'coreapi/linphonecore.h'})
|
||||
|
||||
namespace = parsedClass.find_first_ancestor_by_type(AbsApi.Namespace)
|
||||
self.namespace = namespace.name.concatenate(fullName=True) if namespace is not None else None
|
||||
|
||||
|
||||
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='.')
|
||||
args = argparser.parse_args()
|
||||
|
||||
entries = os.listdir(args.outputdir)
|
||||
if 'include' not in entries:
|
||||
os.mkdir(args.outputdir + '/include')
|
||||
if 'src' not in entries:
|
||||
os.mkdir(args.outputdir + '/src')
|
||||
|
||||
project = CApi.Project()
|
||||
project.initFromDir(args.xmldir)
|
||||
project.check()
|
||||
|
||||
parser = AbsApi.CParser(project)
|
||||
parser.parse_all()
|
||||
translator = CppTranslator()
|
||||
#translator.ignore += ['linphone_tunnel_get_http_proxy',
|
||||
#'linphone_core_can_we_add_call',
|
||||
#'linphone_core_get_default_proxy',
|
||||
#'linphone_core_add_listener',
|
||||
#'linphone_core_remove_listener',
|
||||
#'linphone_core_get_current_callbacks',
|
||||
#'linphone_proxy_config_normalize_number',
|
||||
#'linphone_proxy_config_set_file_transfer_server',
|
||||
#'linphone_proxy_config_get_file_transfer_server',
|
||||
#'linphone_factory_create_core',
|
||||
#'linphone_factory_create_core_with_config',
|
||||
#'linphone_buffer_get_content',
|
||||
#'linphone_chat_room_send_chat_message',
|
||||
#'linphone_config_read_relative_file',
|
||||
#'linphone_core_new_with_config',
|
||||
#'LinphoneImEncryptionEngine',
|
||||
#'LinphoneImEncryptionEngineCbs',
|
||||
#'LinphoneImNotifPolicy',
|
||||
#'LpConfig']
|
||||
|
||||
renderer = pystache.Renderer()
|
||||
|
||||
header = EnumsHeader(translator)
|
||||
for item in parser.enumsIndex.items():
|
||||
if item[1] is not None:
|
||||
header.add_enum(item[1])
|
||||
else:
|
||||
print('warning: {0} enum won\'t be translated because of parsing errors'.format(item[0]))
|
||||
|
||||
with open(args.outputdir + '/include/enums.hh', mode='w') as f:
|
||||
f.write(renderer.render(header))
|
||||
|
||||
mainHeader = MainHeader()
|
||||
|
||||
for _class in parser.classesIndex.values() + parser.interfacesIndex.values():
|
||||
if _class is not None:
|
||||
try:
|
||||
header = ClassHeader(_class, translator, ignore=['LinphoneBuffer'])
|
||||
impl = ClassImpl(_class, header._class)
|
||||
mainHeader.add_include(_class.name.to_snake_case() + '.hh')
|
||||
with open(args.outputdir + '/include/' + header.filename, mode='w') as f:
|
||||
f.write(renderer.render(header))
|
||||
|
||||
if type(_class) is AbsApi.Class:
|
||||
with open(args.outputdir + '/src/' + impl.filename, mode='w') as f:
|
||||
f.write(renderer.render(impl))
|
||||
|
||||
except AbsApi.Error as e:
|
||||
print('Could not translate {0}: {1}'.format(_class.name.to_camel_case(fullName=True), e.args[0]))
|
||||
|
||||
with open(args.outputdir + '/include/linphone.hh', mode='w') as f:
|
||||
f.write(renderer.render(mainHeader))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
8
wrappers/cpp/main_header.mustache
Normal file
8
wrappers/cpp/main_header.mustache
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef {{{define}}}
|
||||
#define {{{define}}}
|
||||
|
||||
{{#includes}}
|
||||
#include "{{{name}}}"
|
||||
{{/includes}}
|
||||
|
||||
#endif // {{{define}}}
|
||||
173
wrappers/cpp/object.cc
Normal file
173
wrappers/cpp/object.cc
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
#include "object.hh"
|
||||
#include <bctoolbox/port.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace linphone;
|
||||
using namespace std;
|
||||
|
||||
template <class T>
|
||||
ObjectBctbxListWrapper<T>::ObjectBctbxListWrapper(const std::list<std::shared_ptr<T> > &cppList): AbstractBctbxListWrapper() {
|
||||
for(auto it=cppList.cbegin(); it!=cppList.cend(); it++) {
|
||||
::belle_sip_object_t *cPtr = Object::sharedPtrToCPtr(static_pointer_cast<Object,T>(*it));
|
||||
if (cPtr != NULL) belle_sip_object_ref(cPtr);
|
||||
mCList = bctbx_list_append(mCList, cPtr);
|
||||
}
|
||||
}
|
||||
|
||||
static void unrefData(void *data) {
|
||||
if (data != NULL) belle_sip_object_unref(data);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ObjectBctbxListWrapper<T>::~ObjectBctbxListWrapper() {
|
||||
mCList = bctbx_list_free_with_data(mCList, unrefData);
|
||||
}
|
||||
|
||||
StringBctbxListWrapper::StringBctbxListWrapper(const std::list<std::string> &cppList): AbstractBctbxListWrapper() {
|
||||
for(auto it=cppList.cbegin(); it!=cppList.cend(); it++) {
|
||||
char *buffer = (char *)malloc(it->length()+1);
|
||||
strcpy(buffer, it->c_str());
|
||||
mCList = bctbx_list_append(mCList, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
StringBctbxListWrapper::~StringBctbxListWrapper() {
|
||||
mCList = bctbx_list_free_with_data(mCList, free);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string Object::sUserDataKey = "cppUserData";
|
||||
|
||||
Object::Object(::belle_sip_object_t *ptr, bool takeRef):
|
||||
enable_shared_from_this<Object>(), mPrivPtr(ptr) {
|
||||
if(takeRef) belle_sip_object_ref(mPrivPtr);
|
||||
belle_sip_object_data_set(ptr, "cpp_object", this, NULL);
|
||||
}
|
||||
|
||||
Object::~Object() {
|
||||
if(mPrivPtr != NULL) {
|
||||
belle_sip_object_data_set(mPrivPtr, "cpp_object", NULL, NULL);
|
||||
belle_sip_object_unref(mPrivPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void Object::unsetData(const std::string &key) {
|
||||
map<string,void *> userData = getUserData();
|
||||
map<string,void *>::iterator it = userData.find(key);
|
||||
if (it != userData.end()) userData.erase(it);
|
||||
}
|
||||
|
||||
bool Object::dataExists(const std::string &key) {
|
||||
map<string,void *> userData = getUserData();
|
||||
return userData.find(key) != userData.end();
|
||||
}
|
||||
|
||||
::belle_sip_object_t *Object::sharedPtrToCPtr(const std::shared_ptr<const Object> &sharedPtr) {
|
||||
if (sharedPtr == nullptr) return NULL;
|
||||
else return sharedPtr->mPrivPtr;
|
||||
}
|
||||
|
||||
std::string Object::cStringToCpp(const char *cstr) {
|
||||
if (cstr == NULL) {
|
||||
return std::string();
|
||||
} else {
|
||||
return std::string(cstr);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Object::cStringToCpp(char *cstr) {
|
||||
if (cstr == NULL) {
|
||||
return std::string();
|
||||
} else {
|
||||
std::string cppStr = cstr;
|
||||
bctbx_free(cstr);
|
||||
return cppStr;
|
||||
}
|
||||
}
|
||||
|
||||
const char *Object::cppStringToC(const std::string &cppstr) {
|
||||
if (cppstr.empty()) {
|
||||
return NULL;
|
||||
} else {
|
||||
return cppstr.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
list<string> Object::bctbxStringListToCppList(const ::bctbx_list_t *bctbxList) {
|
||||
list<string> cppList;
|
||||
for(const ::bctbx_list_t *it=bctbxList; it!=NULL; it=it->next) {
|
||||
cppList.push_back(string((char *)it->data));
|
||||
}
|
||||
return cppList;
|
||||
}
|
||||
|
||||
std::list<std::string> Object::cStringArrayToCppList(const char **cArray) {
|
||||
list<string> cppList;
|
||||
int i;
|
||||
for(i=0; cArray[i]!=NULL; i++) {
|
||||
cppList.push_back(cArray[i]);
|
||||
}
|
||||
return cppList;
|
||||
}
|
||||
|
||||
static void deleteCppUserDataMap(std::map<std::string,void *> *userDataMap) {
|
||||
delete userDataMap;
|
||||
}
|
||||
|
||||
std::map<std::string,void *> &Object::getUserData() const {
|
||||
map<string,void *> *userData = (map<string,void *> *)belle_sip_object_data_get(mPrivPtr, sUserDataKey.c_str());
|
||||
if (userData == NULL) {
|
||||
userData = new map<string,void *>();
|
||||
belle_sip_object_data_set(mPrivPtr, sUserDataKey.c_str(), userData, (belle_sip_data_destroy)deleteCppUserDataMap);
|
||||
}
|
||||
return *userData;
|
||||
}
|
||||
|
||||
|
||||
std::string ListenableObject::sListenerDataName = "cpp_listener";
|
||||
|
||||
ListenableObject::ListenableObject(::belle_sip_object_t *ptr, bool takeRef): Object(ptr, takeRef) {
|
||||
shared_ptr<Listener> *cppListener = (shared_ptr<Listener> *)belle_sip_object_data_get(mPrivPtr, sListenerDataName.c_str());
|
||||
if (cppListener == NULL) {
|
||||
cppListener = new shared_ptr<Listener>();
|
||||
belle_sip_object_data_set(mPrivPtr, sListenerDataName.c_str(), cppListener, (belle_sip_data_destroy)deleteListenerPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void ListenableObject::setListener(const std::shared_ptr<Listener> &listener) {
|
||||
shared_ptr<Listener> &curListener = *(shared_ptr<Listener> *)belle_sip_object_data_get(mPrivPtr, sListenerDataName.c_str());
|
||||
curListener = listener;
|
||||
}
|
||||
|
||||
std::shared_ptr<Listener> & ListenableObject::getListenerFromObject(::belle_sip_object_t *object) {
|
||||
return *(std::shared_ptr<Listener> *)belle_sip_object_data_get(object, sListenerDataName.c_str());
|
||||
}
|
||||
|
||||
|
||||
std::string MultiListenableObject::sListenerListName = "cpp_listeners";
|
||||
|
||||
MultiListenableObject::MultiListenableObject(::belle_sip_object_t *ptr, bool takeRef): Object(ptr, takeRef) {
|
||||
if (ptr != NULL) {
|
||||
list<shared_ptr<Listener> > *listeners = new list<shared_ptr<Listener> >;
|
||||
belle_sip_object_data_set(ptr, sListenerListName.c_str(), listeners, (belle_sip_data_destroy)deleteListenerList);
|
||||
}
|
||||
}
|
||||
|
||||
MultiListenableObject::~MultiListenableObject() {
|
||||
if (mPrivPtr != NULL) {
|
||||
belle_sip_object_data_set(mPrivPtr, sListenerListName.c_str(), NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void MultiListenableObject::addListener(const std::shared_ptr<Listener> &listener) {
|
||||
std::list<std::shared_ptr<Listener> > &listeners = *(std::list<std::shared_ptr<Listener> > *)belle_sip_object_data_get(mPrivPtr, sListenerListName.c_str());
|
||||
listeners.push_back(listener);
|
||||
}
|
||||
|
||||
void MultiListenableObject::removeListener(const std::shared_ptr<Listener> &listener) {
|
||||
std::list<std::shared_ptr<Listener> > &listeners = *(std::list<std::shared_ptr<Listener> > *)belle_sip_object_data_get(mPrivPtr, sListenerListName.c_str());
|
||||
listeners.remove(listener);
|
||||
}
|
||||
166
wrappers/cpp/object.hh
Normal file
166
wrappers/cpp/object.hh
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#ifndef _LINPHONE_OBJECT_HH
|
||||
#define _LINPHONE_OBJECT_HH
|
||||
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <belle-sip/object.h>
|
||||
#include <bctoolbox/list.h>
|
||||
|
||||
namespace linphone {
|
||||
|
||||
class Object;
|
||||
class Listener;
|
||||
|
||||
|
||||
class AbstractBctbxListWrapper {
|
||||
public:
|
||||
AbstractBctbxListWrapper(): mCList(NULL) {}
|
||||
virtual ~AbstractBctbxListWrapper() {}
|
||||
::bctbx_list_t *c_list() {return mCList;}
|
||||
|
||||
protected:
|
||||
::bctbx_list_t *mCList;
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class ObjectBctbxListWrapper: public AbstractBctbxListWrapper {
|
||||
public:
|
||||
ObjectBctbxListWrapper(const std::list<std::shared_ptr<T> > &cppList);
|
||||
virtual ~ObjectBctbxListWrapper();
|
||||
};
|
||||
|
||||
|
||||
class StringBctbxListWrapper: public AbstractBctbxListWrapper {
|
||||
public:
|
||||
StringBctbxListWrapper(const std::list<std::string> &cppList);
|
||||
virtual ~StringBctbxListWrapper();
|
||||
};
|
||||
|
||||
|
||||
class Object: public std::enable_shared_from_this<Object> {
|
||||
public:
|
||||
Object(::belle_sip_object_t *ptr, bool takeRef=true);
|
||||
virtual ~Object();
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
void setData(const std::string &key, T &data) {
|
||||
std::map<std::string,void *> &userData = getUserData();
|
||||
userData[key] = &data;
|
||||
}
|
||||
template <class T>
|
||||
T &getData(const std::string &key) {
|
||||
std::map<std::string,void *> &userData = getUserData();
|
||||
void *ptr = userData[key];
|
||||
if (ptr == NULL) {
|
||||
throw std::out_of_range("unknown data key [" + key + "]");
|
||||
} else {
|
||||
return *(T *)ptr;
|
||||
}
|
||||
}
|
||||
void unsetData(const std::string &key);
|
||||
bool dataExists(const std::string &key);
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
static std::shared_ptr<T> cPtrToSharedPtr(::belle_sip_object_t *ptr, bool takeRef=true) {
|
||||
if (ptr == NULL) {
|
||||
return nullptr;
|
||||
} else {
|
||||
T *cppPtr = (T *)belle_sip_object_data_get(ptr, "cpp_object");
|
||||
if (cppPtr == NULL) {
|
||||
return std::make_shared<T>(ptr, takeRef);
|
||||
} else {
|
||||
return std::static_pointer_cast<T,Object>(cppPtr->shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
static ::belle_sip_object_t *sharedPtrToCPtr(const std::shared_ptr<const Object> &sharedPtr);
|
||||
|
||||
protected:
|
||||
static std::string cStringToCpp(const char *cstr);
|
||||
static std::string cStringToCpp(char *cstr);
|
||||
static const char *cppStringToC(const std::string &cppstr);
|
||||
|
||||
template <class T>
|
||||
static std::list<std::shared_ptr<T> > bctbxObjectListToCppList(const ::bctbx_list_t *bctbxList) {
|
||||
std::list<std::shared_ptr<T> > cppList;
|
||||
for(const ::bctbx_list_t *it=bctbxList; it!=NULL; it=it->next) {
|
||||
std::shared_ptr<T> newObj = Object::cPtrToSharedPtr<T>((::belle_sip_object_t *)it->data);
|
||||
cppList.push_back(newObj);
|
||||
}
|
||||
return cppList;
|
||||
}
|
||||
|
||||
static std::list<std::string> bctbxStringListToCppList(const ::bctbx_list_t *bctbxList);
|
||||
static std::list<std::string> cStringArrayToCppList(const char **cArray);
|
||||
|
||||
private:
|
||||
std::map<std::string,void *> &getUserData() const;
|
||||
template <class T> static void deleteSharedPtr(std::shared_ptr<T> *ptr) {if (ptr != NULL) delete ptr;}
|
||||
static void deleteString(std::string *str) {if (str != NULL) delete str;}
|
||||
|
||||
protected:
|
||||
::belle_sip_object_t *mPrivPtr;
|
||||
|
||||
private:
|
||||
static const std::string sUserDataKey;
|
||||
};
|
||||
|
||||
|
||||
class Listener {
|
||||
public:
|
||||
Listener(): mCbs(NULL) {}
|
||||
virtual ~Listener() {setCallbacks(NULL);}
|
||||
|
||||
public:
|
||||
void setCallbacks(::belle_sip_object_t *cbs) {
|
||||
if (mCbs != NULL) belle_sip_object_unref(mCbs);
|
||||
if (cbs == NULL) mCbs = NULL;
|
||||
else mCbs = belle_sip_object_ref(cbs);
|
||||
}
|
||||
belle_sip_object_t *getCallbacks() {return mCbs;}
|
||||
|
||||
private:
|
||||
::belle_sip_object_t *mCbs;
|
||||
};
|
||||
|
||||
|
||||
class ListenableObject: public Object {
|
||||
protected:
|
||||
ListenableObject(::belle_sip_object_t *ptr, bool takeRef=true);
|
||||
void setListener(const std::shared_ptr<Listener> &listener);
|
||||
|
||||
protected:
|
||||
static std::shared_ptr<Listener> & getListenerFromObject(::belle_sip_object_t *object);
|
||||
|
||||
private:
|
||||
static void deleteListenerPtr(std::shared_ptr<Listener> *ptr) {delete ptr;}
|
||||
|
||||
private:
|
||||
static std::string sListenerDataName;
|
||||
};
|
||||
|
||||
class MultiListenableObject: public Object {
|
||||
friend class Factory;
|
||||
|
||||
protected:
|
||||
MultiListenableObject(::belle_sip_object_t *ptr, bool takeRef=true);
|
||||
virtual ~MultiListenableObject();
|
||||
|
||||
protected:
|
||||
void addListener(const std::shared_ptr<Listener> &listener);
|
||||
void removeListener(const std::shared_ptr<Listener> &listener);
|
||||
|
||||
private:
|
||||
static void deleteListenerList(std::list<std::shared_ptr<Listener> > *listeners) {delete listeners;}
|
||||
|
||||
private:
|
||||
static std::string sListenerListName;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif // _LINPHONE_OBJECT_HH
|
||||
Loading…
Add table
Reference in a new issue