Merge branch 'dev'
|
@ -9,6 +9,9 @@
|
|||
*.aps
|
||||
**/ipch
|
||||
|
||||
*.tpr
|
||||
*.tpd
|
||||
|
||||
# for CMake
|
||||
CMakeFiles
|
||||
cmake_install.cmake
|
||||
|
@ -28,8 +31,10 @@ __pycache__
|
|||
**/.idea/misc.xml
|
||||
**/.idea/dictionaries
|
||||
**/.idea/watcherTasks.xml
|
||||
**/.idea/dataSources.*
|
||||
**/.idea/inspectionProfiles
|
||||
**/.idea/codeStyles
|
||||
**/.idea/dataSources
|
||||
**/.idea/inspectionProfiles
|
||||
**/.idea/vcs.xml
|
||||
**/.idea/modules.xml
|
||||
|
@ -65,7 +70,6 @@ __pycache__
|
|||
/server/share/db
|
||||
/server/share/log
|
||||
/server/share/replay
|
||||
/server/testssh
|
||||
|
||||
|
||||
# for generated files.
|
||||
|
@ -78,9 +82,7 @@ __pycache__
|
|||
/client/tp_rdp
|
||||
/server/tp_core/protocol/rdp
|
||||
/client/tools/tprdp
|
||||
/server/tp_core/testssh
|
||||
/client/tp_assist_win_it_doctor
|
||||
/dist/client/windows/assist-it-doctor
|
||||
/client/build-tp-player-*
|
||||
|
||||
# for MacOS.
|
||||
.DS_Store
|
||||
|
@ -102,3 +104,7 @@ profile
|
|||
*.moved-aside
|
||||
/server/share/tmp
|
||||
|
||||
/server/tp_core/testssh/Debug
|
||||
/server/tp_core/testssh/Release
|
||||
/external/zlib
|
||||
/client/tools/qt-redist
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<file url="file://$PROJECT_DIR$/server/tp_core/common/ts_membuf.h" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/common/ts_memstream.h" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/core/main.cpp" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/core/tp_tpp_mgr.h" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/core/ts_env.cpp" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/core/ts_http_rpc.cpp" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/core/ts_http_rpc.h" charset="GBK" />
|
||||
|
@ -31,6 +32,7 @@
|
|||
<file url="file://$PROJECT_DIR$/server/tp_core/core/ts_web_rpc.h" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/protocol/rdp/rdp_conn.cpp" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/protocol/rdp/rdp_conn.h" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/protocol/rdp/rdp_package.h" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/protocol/rdp/rdp_proxy.cpp" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/protocol/rdp/rdp_session.cpp" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/server/tp_core/protocol/rdp/rdp_session.h" charset="GBK" />
|
||||
|
|
|
@ -14,15 +14,16 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
|||
MESSAGE(STATUS "build on macOS...")
|
||||
set(OS_MACOS 1)
|
||||
set(OS_POSIX 1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(TP_EXTERNAL_RELEASE_DIR "${PROJECT_SOURCE_DIR}/external/macos/release")
|
||||
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
set(OS_LINUX 1)
|
||||
set(OS_POSIX 1)
|
||||
MESSAGE(STATUS "build on Linux...")
|
||||
# add_subdirectory(server/tp_web/src)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(TP_EXTERNAL_RELEASE_DIR "${PROJECT_SOURCE_DIR}/external/linux/release")
|
||||
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
|
||||
# MESSAGE(FATAL_ERROR "unsupported platform: Windows")
|
||||
MESSAGE(FATAL_ERROR "unsupported platform: Windows")
|
||||
else ()
|
||||
MESSAGE(FATAL_ERROR "unsupported platform: ${CMAKE_SYSTEM_NAME}")
|
||||
endif ()
|
||||
|
|
|
@ -36,7 +36,7 @@ endif()
|
|||
add_subdirectory(server/tp_core/core)
|
||||
add_subdirectory(server/tp_core/protocol/ssh)
|
||||
add_subdirectory(server/tp_core/protocol/telnet)
|
||||
#add_subdirectory(server/testssh/testssh)
|
||||
add_subdirectory(server/tp_core/testssh)
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/server/tp_core/protocol/rdp")
|
||||
add_subdirectory(server/tp_core/protocol/rdp)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$/builder" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<content url="file://$MODULE_DIR$/builder">
|
||||
<sourceFolder url="file://$MODULE_DIR$/builder" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="py37" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
################################################################
|
||||
# Basic settings.
|
||||
################################################################
|
||||
VER_PYTHON="3.7.0"
|
||||
VER_PYTHON="3.7.5"
|
||||
VER_PYTHON_SHORT="3.7"
|
||||
VER_OPENSSL="1.0.2p"
|
||||
VER_SQLITE="3250000"
|
||||
VER_OPENSSL="1.1.1d"
|
||||
VER_SQLITE="3300100"
|
||||
VER_ZLIB="1.2.11"
|
||||
VER_PYTHON_LIB="${VER_PYTHON_SHORT}m"
|
||||
|
||||
|
@ -38,15 +38,6 @@ function on_error()
|
|||
exit 1
|
||||
}
|
||||
|
||||
function setp_build_git()
|
||||
{
|
||||
# su -s
|
||||
# yum install zlib-devel expat-devel libcurl-devel
|
||||
# make prefix=/usr/local
|
||||
# make prefix=/usr/local install
|
||||
echo 'skip build git now.'
|
||||
}
|
||||
|
||||
function dlfile()
|
||||
{
|
||||
echo -n "Downloading $1 ..."
|
||||
|
@ -77,7 +68,7 @@ function step_download_files()
|
|||
|
||||
dlfile "python source tarball" "https://www.python.org/ftp/python/${VER_PYTHON}/" "Python-${VER_PYTHON}.tgz" ${PATH_DOWNLOAD}
|
||||
dlfile "openssl source tarball" "https://www.openssl.org/source/" "openssl-${VER_OPENSSL}.tar.gz" ${PATH_DOWNLOAD}
|
||||
dlfile "sqlite source tarball" "http://sqlite.org/2018/" "sqlite-autoconf-${VER_SQLITE}.tar.gz" ${PATH_DOWNLOAD}
|
||||
dlfile "sqlite source tarball" "http://sqlite.org/2019/" "sqlite-autoconf-${VER_SQLITE}.tar.gz" ${PATH_DOWNLOAD}
|
||||
dlfile "zlib source tarball" "https://www.zlib.net/" "zlib-${VER_ZLIB}.tar.gz" ${PATH_DOWNLOAD}
|
||||
}
|
||||
|
||||
|
@ -121,6 +112,16 @@ function step_prepare_source()
|
|||
on_error "Can not prepare source code for build sqlite3 module for Python."
|
||||
fi
|
||||
|
||||
if [ ! -f "${PATH_FIX}/Python-${VER_PYTHON}/Modules/Setup.dist" ]; then
|
||||
on_error "Can not fix source for build Python."
|
||||
fi
|
||||
if [ ! -f "${PATH_FIX}/Python-${VER_PYTHON}/Modules/_sqlite/cache.h" ]; then
|
||||
on_error "Can not fix source for build sqlite3 module for Python."
|
||||
fi
|
||||
if [ ! -f "${PATH_FIX}/Python-${VER_PYTHON}/Modules/_sqlite/prepare_protocol.h" ]; then
|
||||
on_error "Can not fix source for build sqlite3 module for Python."
|
||||
fi
|
||||
|
||||
cp "${PATH_FIX}/Python-${VER_PYTHON}/Modules/Setup.dist" "${PY_PATH_SRC}/Modules/Setup.dist"
|
||||
cp "${PATH_FIX}/Python-${VER_PYTHON}/Modules/Setup.dist" "${PY_PATH_SRC}/Modules/Setup"
|
||||
cp "${PATH_FIX}/Python-${VER_PYTHON}/Modules/_sqlite/cache.h" "${PY_PATH_SRC}/Modules/_sqlite/cache.h"
|
||||
|
|
|
@ -64,6 +64,9 @@ def main():
|
|||
elif x == 'a':
|
||||
clean_everything()
|
||||
continue
|
||||
elif x == 'e':
|
||||
clean_external()
|
||||
continue
|
||||
|
||||
try:
|
||||
x = int(x)
|
||||
|
@ -117,6 +120,27 @@ def clean_everything():
|
|||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libuv.a'))
|
||||
|
||||
|
||||
def clean_external():
|
||||
#utils.remove(os.path.join(env.root_path, 'out'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'jsoncpp'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'libuv'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'mbedtls'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'mongoose'))
|
||||
#utils.remove(os.path.join(env.root_path, 'external', 'openssl'))
|
||||
#utils.remove(os.path.join(env.root_path, 'external', 'python'))
|
||||
#utils.remove(os.path.join(env.root_path, 'external', 'libssh-win-static', 'lib'))
|
||||
#utils.remove(os.path.join(env.root_path, 'external', 'libssh-win-static', 'src'))
|
||||
#utils.remove(os.path.join(env.root_path, 'external', 'linux', 'tmp'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libmbedcrypto.a'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libmbedtls.a'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libmbedx509.a'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libsqlite3.a'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libssh.a'))
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libssh_threads.a'))
|
||||
|
||||
utils.remove(os.path.join(env.root_path, 'external', 'linux', 'release', 'lib', 'libuv.a'))
|
||||
|
||||
|
||||
def do_opt(opt):
|
||||
arg = ''
|
||||
|
||||
|
@ -155,6 +179,7 @@ def do_opt(opt):
|
|||
|
||||
# cmd = '"%s" -B "%s" %s' % (utils.cfg.py_exec, os.path.join(BUILDER_PATH, script), arg)
|
||||
cmd = '%s -B %s %s' % (env.py_exec, os.path.join(env.builder_path, script), arg)
|
||||
print(cmd)
|
||||
os.system(cmd)
|
||||
|
||||
|
||||
|
@ -248,6 +273,7 @@ def show_menu():
|
|||
cc.o((cc.CR_NORMAL, ' ['), (cc.CR_INFO, '%2d' % options[o]['id']), (cc.CR_NORMAL, '] ', options[o]['disp']))
|
||||
|
||||
cc.v(' -------------------------------------------------------')
|
||||
cc.o((cc.CR_NORMAL, ' ['), (cc.CR_INFO, ' E'), (cc.CR_NORMAL, '] clean external temp. files.'))
|
||||
cc.o((cc.CR_NORMAL, ' ['), (cc.CR_INFO, ' C'), (cc.CR_NORMAL, '] clean build and dist.'))
|
||||
cc.o((cc.CR_NORMAL, ' ['), (cc.CR_INFO, ' A'), (cc.CR_NORMAL, '] clean everything.'))
|
||||
|
||||
|
|
|
@ -13,21 +13,24 @@ class BuilderBase:
|
|||
def __init__(self):
|
||||
self.out_dir = ''
|
||||
|
||||
def build_exe(self):
|
||||
pass
|
||||
def build_assist(self):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
|
||||
def build_player(self):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
|
||||
def build_rdp(self):
|
||||
pass
|
||||
cc.e("this is a pure-virtual function.")
|
||||
|
||||
def build_installer(self):
|
||||
pass
|
||||
cc.e("this is a pure-virtual function.")
|
||||
|
||||
|
||||
class BuilderWin(BuilderBase):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def build_exe(self):
|
||||
def build_assist(self):
|
||||
cc.i('build tp_assist...')
|
||||
sln_file = os.path.join(env.root_path, 'client', 'tp_assist_win', 'tp_assist.vs2017.sln')
|
||||
out_file = os.path.join(env.root_path, 'out', 'client', ctx.bits_path, ctx.target_path, 'tp_assist.exe')
|
||||
|
@ -36,6 +39,15 @@ class BuilderWin(BuilderBase):
|
|||
utils.msvc_build(sln_file, 'tp_assist', ctx.target_path, ctx.bits_path, False)
|
||||
utils.ensure_file_exists(out_file)
|
||||
|
||||
def build_player(self):
|
||||
cc.i('build tp-player...')
|
||||
prj_path = os.path.join(env.root_path, 'client', 'tp-player')
|
||||
out_file = os.path.join(env.root_path, 'out', 'client', ctx.bits_path, ctx.target_path, 'tp-player.exe')
|
||||
if os.path.exists(out_file):
|
||||
utils.remove(out_file)
|
||||
utils.qt_build_win(prj_path, 'tp-player', ctx.bits_path, ctx.target_path)
|
||||
utils.ensure_file_exists(out_file)
|
||||
|
||||
# def build_rdp(self):
|
||||
# cc.n('build tp_rdp...')
|
||||
# sln_file = os.path.join(ROOT_PATH, 'client', 'tp_rdp', 'tp_rdp.2015.sln')
|
||||
|
@ -74,12 +86,14 @@ class BuilderWin(BuilderBase):
|
|||
utils.makedirs(tmp_cfg_path)
|
||||
|
||||
utils.copy_file(os.path.join(env.root_path, 'out', 'client', ctx.bits_path, ctx.target_path), tmp_app_path, 'tp_assist.exe')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'cfg'), tmp_cfg_path, ('tp-assist.windows.json', 'tp-assist.json'))
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tp_assist_win', 'runtime'), tmp_app_path, 'vcruntime140.dll')
|
||||
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'cfg'), tmp_cfg_path, ('tp-assist.windows.json', 'tp-assist.json'))
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'cfg'), tmp_cfg_path, 'cacert.cer')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'cfg'), tmp_cfg_path, 'localhost.key')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'cfg'), tmp_cfg_path, 'localhost.pem')
|
||||
|
||||
# assist configuration web page
|
||||
utils.copy_ex(os.path.join(env.root_path, 'client', 'tp_assist_win'), tmp_app_path, 'site')
|
||||
|
||||
utils.makedirs(os.path.join(tmp_app_path, 'tools', 'putty'))
|
||||
|
@ -90,14 +104,37 @@ class BuilderWin(BuilderBase):
|
|||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'winscp'), os.path.join(tmp_app_path, 'tools', 'winscp'), 'license.txt')
|
||||
|
||||
utils.makedirs(os.path.join(tmp_app_path, 'tools', 'tprdp'))
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'tprdp-client.exe')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'tprdp-replay.exe')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'libeay32.dll')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'ssleay32.dll')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'msvcr120.dll')
|
||||
# utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'tprdp-client.exe')
|
||||
# utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'tprdp-replay.exe')
|
||||
# utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'libeay32.dll')
|
||||
# utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'ssleay32.dll')
|
||||
# utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'msvcr120.dll')
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools', 'tprdp'), os.path.join(tmp_app_path, 'tools', 'tprdp'), 'wfreerdp.exe')
|
||||
|
||||
utils.copy_file(os.path.join(env.root_path, 'client', 'tools'), os.path.join(tmp_app_path, 'tools'), 'securecrt-telnet.vbs')
|
||||
|
||||
# tp-player
|
||||
utils.copy_file(os.path.join(env.root_path, 'out', 'client', ctx.bits_path, ctx.target_path), tmp_app_path, 'tp-player.exe')
|
||||
|
||||
# qt-redist
|
||||
qt_redist_path = os.path.join(env.root_path, 'client', 'tools', 'qt-redist')
|
||||
utils.copy_file(qt_redist_path, tmp_app_path, 'Qt5Core.dll')
|
||||
utils.copy_file(qt_redist_path, tmp_app_path, 'Qt5Gui.dll')
|
||||
utils.copy_file(qt_redist_path, tmp_app_path, 'Qt5Network.dll')
|
||||
utils.copy_file(qt_redist_path, tmp_app_path, 'Qt5Widgets.dll')
|
||||
utils.copy_ex(os.path.join(qt_redist_path, 'platforms'), os.path.join(tmp_app_path, 'platforms'))
|
||||
utils.copy_ex(os.path.join(qt_redist_path, 'styles'), os.path.join(tmp_app_path, 'styles'))
|
||||
utils.copy_ex(os.path.join(qt_redist_path, 'translations'), os.path.join(tmp_app_path, 'translations'))
|
||||
|
||||
# zlib
|
||||
suffix = 'd' if ctx.target_path == 'debug' else ''
|
||||
utils.copy_file(os.path.join(env.root_path, 'external', 'zlib', 'build', ctx.target_path), tmp_app_path, 'zlib{}.dll'.format(suffix))
|
||||
|
||||
# openssl
|
||||
utils.copy_file(os.path.join(env.root_path, 'external', 'openssl', 'bin'), tmp_app_path, 'libcrypto-1_1.dll')
|
||||
utils.copy_file(os.path.join(env.root_path, 'external', 'openssl', 'bin'), tmp_app_path, 'libssl-1_1.dll')
|
||||
|
||||
# final build
|
||||
utils.nsis_build(os.path.join(env.root_path, 'dist', 'client', 'windows', 'assist', 'installer.nsi'))
|
||||
|
||||
|
||||
|
@ -105,7 +142,7 @@ class BuilderMacOS(BuilderBase):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def build_exe(self):
|
||||
def build_assist(self):
|
||||
cc.i('build tp_assist...')
|
||||
|
||||
configuration = ctx.target_path.capitalize()
|
||||
|
@ -117,6 +154,9 @@ class BuilderMacOS(BuilderBase):
|
|||
utils.xcode_build(proj_file, 'TP-Assist', configuration, False)
|
||||
utils.ensure_file_exists(os.path.join(out_file, 'Contents', 'Info.plist'))
|
||||
|
||||
def build_player(self):
|
||||
cc.o('skip build tp_player now...')
|
||||
|
||||
def build_installer(self):
|
||||
cc.i('make tp_assist dmg file...')
|
||||
|
||||
|
@ -169,7 +209,7 @@ class BuilderLinux(BuilderBase):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def build_exe(self):
|
||||
def build_assist(self):
|
||||
cc.e('not support linux.')
|
||||
|
||||
# def build_rdp(self):
|
||||
|
@ -215,7 +255,8 @@ def main():
|
|||
builder = gen_builder(ctx.host_os)
|
||||
|
||||
if 'exe' in argv:
|
||||
builder.build_exe()
|
||||
builder.build_assist()
|
||||
builder.build_player()
|
||||
# elif 'rdp' in argv:
|
||||
# builder.build_rdp()
|
||||
elif 'installer' in argv:
|
||||
|
|
|
@ -23,70 +23,90 @@ class BuilderBase:
|
|||
self._init_path()
|
||||
|
||||
def _init_path(self):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
cc.e("_init_path() pure-virtual function.")
|
||||
|
||||
def build_jsoncpp(self):
|
||||
file_name = 'jsoncpp-{}.zip'.format(env.ver_jsoncpp)
|
||||
if not utils.download_file('jsoncpp source tarball', 'https://github.com/open-source-parsers/jsoncpp/archive/{}.zip'.format(env.ver_jsoncpp), PATH_DOWNLOAD, file_name):
|
||||
return
|
||||
self._build_jsoncpp(file_name)
|
||||
|
||||
def _download_jsoncpp(self, file_name):
|
||||
return utils.download_file('jsoncpp source tarball', 'https://github.com/open-source-parsers/jsoncpp/archive/{}.zip'.format(env.ver_jsoncpp), PATH_DOWNLOAD, file_name)
|
||||
|
||||
def _build_jsoncpp(self, file_name):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
cc.e("_build_jsoncpp() pure-virtual function.")
|
||||
|
||||
def build_mongoose(self):
|
||||
file_name = 'mongoose-{}.zip'.format(env.ver_mongoose)
|
||||
if not utils.download_file('mongoose source tarball', 'https://github.com/cesanta/mongoose/archive/{}.zip'.format(env.ver_mongoose), PATH_DOWNLOAD, file_name):
|
||||
return
|
||||
self._build_mongoose(file_name)
|
||||
|
||||
def _download_mongoose(self, file_name):
|
||||
return utils.download_file('mongoose source tarball', 'https://github.com/cesanta/mongoose/archive/{}.zip'.format(env.ver_mongoose), PATH_DOWNLOAD, file_name)
|
||||
|
||||
def _build_mongoose(self, file_name):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
cc.e("_build_mongoose() pure-virtual function.")
|
||||
|
||||
def build_openssl(self):
|
||||
file_name = 'openssl-{}.zip'.format(env.ver_ossl)
|
||||
self._build_openssl(file_name)
|
||||
|
||||
def _build_openssl(self, file_name):
|
||||
def _download_openssl(self, file_name):
|
||||
_alt_ver = '_'.join(env.ver_ossl.split('.'))
|
||||
if not utils.download_file('openssl source tarball', 'https://github.com/openssl/openssl/archive/OpenSSL_{}.zip'.format(_alt_ver), PATH_DOWNLOAD, file_name):
|
||||
cc.e("can not download openssl source tarball.")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
return utils.download_file('openssl source tarball', 'https://github.com/openssl/openssl/archive/OpenSSL_{}.zip'.format(_alt_ver), PATH_DOWNLOAD, file_name)
|
||||
|
||||
def _build_openssl(self, file_name):
|
||||
cc.e("_build_openssl() pure-virtual function.")
|
||||
# _alt_ver = '_'.join(env.ver_ossl.split('.'))
|
||||
# if not utils.download_file('openssl source tarball', 'https://github.com/openssl/openssl/archive/OpenSSL_{}.zip'.format(_alt_ver), PATH_DOWNLOAD, file_name):
|
||||
# cc.e("can not download openssl source tarball.")
|
||||
# return False
|
||||
# else:
|
||||
# return True
|
||||
|
||||
def build_libuv(self):
|
||||
file_name = 'libuv-{}.zip'.format(env.ver_libuv)
|
||||
if not utils.download_file('libuv source tarball', 'https://github.com/libuv/libuv/archive/v{}.zip'.format(env.ver_libuv), PATH_DOWNLOAD, file_name):
|
||||
return
|
||||
self._build_libuv(file_name)
|
||||
|
||||
def _download_libuv(self, file_name):
|
||||
return utils.download_file('libuv source tarball', 'https://github.com/libuv/libuv/archive/v{}.zip'.format(env.ver_libuv), PATH_DOWNLOAD, file_name)
|
||||
|
||||
def _build_libuv(self, file_name):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
|
||||
def build_mbedtls(self):
|
||||
file_name = 'mbedtls-mbedtls-{}.zip'.format(env.ver_mbedtls)
|
||||
if not utils.download_file('mbedtls source tarball', 'https://github.com/ARMmbed/mbedtls/archive/mbedtls-{}.zip'.format(env.ver_mbedtls), PATH_DOWNLOAD, file_name):
|
||||
return
|
||||
self._build_mbedtls(file_name)
|
||||
|
||||
def _download_mbedtls(self, file_name):
|
||||
return utils.download_file('mbedtls source tarball', 'https://github.com/ARMmbed/mbedtls/archive/mbedtls-{}.zip'.format(env.ver_mbedtls), PATH_DOWNLOAD, file_name)
|
||||
|
||||
def _build_mbedtls(self, file_name):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
|
||||
def build_zlib(self):
|
||||
file_name = 'zlilb{}.zip'.format(env.ver_zlib_number)
|
||||
self._build_zlib(file_name)
|
||||
|
||||
def _download_zlib(self, file_name):
|
||||
return utils.download_file('mbedtls source tarball', 'https://www.zlib.net/zlib{}.zip'.format(env.ver_zlib_number), PATH_DOWNLOAD, file_name)
|
||||
|
||||
def _build_zlib(self, file_name):
|
||||
cc.e("_build_zlib() pure-virtual function.")
|
||||
|
||||
def build_libssh(self):
|
||||
file_name = 'libssh-{}.zip'.format(env.ver_libssh)
|
||||
if not utils.download_file('libssh source tarball', 'https://git.libssh.org/projects/libssh.git/snapshot/libssh-{}.zip'.format(env.ver_libssh), PATH_DOWNLOAD, file_name):
|
||||
return
|
||||
self._build_libssh(file_name)
|
||||
|
||||
def _download_libssh(self, file_name):
|
||||
return utils.download_file('libssh source tarball', 'https://git.libssh.org/projects/libssh.git/snapshot/libssh-{}.zip'.format(env.ver_libssh), PATH_DOWNLOAD, file_name)
|
||||
|
||||
def _build_libssh(self, file_name):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
cc.e("_build_libssh() pure-virtual function.")
|
||||
|
||||
def prepare_python(self):
|
||||
self._prepare_python()
|
||||
|
||||
def _prepare_python(self):
|
||||
cc.e("this is a pure-virtual function.")
|
||||
cc.e("_prepare_python() pure-virtual function.")
|
||||
|
||||
def fix_output(self):
|
||||
pass
|
||||
|
@ -103,9 +123,10 @@ class BuilderWin(BuilderBase):
|
|||
self.MBEDTLS_PATH_SRC = os.path.join(PATH_EXTERNAL, 'mbedtls')
|
||||
self.LIBUV_PATH_SRC = os.path.join(PATH_EXTERNAL, 'libuv')
|
||||
self.LIBSSH_PATH_SRC = os.path.join(PATH_EXTERNAL, 'libssh')
|
||||
self.ZLIB_PATH_SRC = os.path.join(PATH_EXTERNAL, 'zlib')
|
||||
|
||||
def _prepare_python(self):
|
||||
cc.n('prepare python header files ...', end='')
|
||||
cc.n('prepare python header files ... ', end='')
|
||||
|
||||
if os.path.exists(os.path.join(PATH_EXTERNAL, 'python', 'include', 'Python.h')):
|
||||
cc.w('already exists, skip.')
|
||||
|
@ -125,69 +146,98 @@ class BuilderWin(BuilderBase):
|
|||
utils.copy_ex(_header_path, os.path.join(PATH_EXTERNAL, 'python', 'include'))
|
||||
|
||||
def _build_openssl(self, file_name):
|
||||
cc.n('build openssl static library from source code... ')
|
||||
|
||||
if not super()._build_openssl(file_name):
|
||||
return
|
||||
|
||||
_chk_output = [
|
||||
os.path.join(self.OPENSSL_PATH_SRC, 'out32', 'libeay32.lib'),
|
||||
os.path.join(self.OPENSSL_PATH_SRC, 'out32', 'ssleay32.lib'),
|
||||
os.path.join(self.OPENSSL_PATH_SRC, 'inc32', 'openssl', 'opensslconf.h'),
|
||||
]
|
||||
|
||||
need_build = False
|
||||
for f in _chk_output:
|
||||
if not os.path.exists(f):
|
||||
need_build = True
|
||||
break
|
||||
|
||||
if not need_build:
|
||||
cc.n('build openssl static library from source code... ', end='')
|
||||
cc.n('prepare OpenSSL pre-built package ... ', end='')
|
||||
if os.path.exists(self.OPENSSL_PATH_SRC):
|
||||
cc.w('already exists, skip.')
|
||||
return
|
||||
cc.v('')
|
||||
|
||||
cc.n('prepare openssl source code...')
|
||||
_alt_ver = '_'.join(env.ver_ossl.split('.'))
|
||||
if not os.path.exists(self.OPENSSL_PATH_SRC):
|
||||
utils.unzip(os.path.join(PATH_DOWNLOAD, file_name), PATH_EXTERNAL)
|
||||
os.rename(os.path.join(PATH_EXTERNAL, 'openssl-OpenSSL_{}'.format(_alt_ver)), self.OPENSSL_PATH_SRC)
|
||||
if not os.path.exists(self.OPENSSL_PATH_SRC):
|
||||
raise RuntimeError('can not prepare openssl source code.')
|
||||
else:
|
||||
cc.w('already exists, skip.')
|
||||
|
||||
os.chdir(self.OPENSSL_PATH_SRC)
|
||||
os.system('""{}" Configure VC-WIN32"'.format(env.perl))
|
||||
os.system(r'ms\do_nasm')
|
||||
# for vs2015
|
||||
# utils.sys_exec(r'"{}\VC\bin\vcvars32.bat" && nmake -f ms\nt.mak'.format(env.visual_studio_path), direct_output=True)
|
||||
# for vs2017 community
|
||||
utils.sys_exec(r'"{}VC\Auxiliary\Build\vcvars32.bat" && nmake -f ms\nt.mak'.format(env.visual_studio_path), direct_output=True)
|
||||
file_name = 'Win32OpenSSL-{}.msi'.format(_alt_ver)
|
||||
installer = os.path.join(PATH_DOWNLOAD, file_name)
|
||||
|
||||
for f in _chk_output:
|
||||
if not os.path.exists(f):
|
||||
raise RuntimeError('build openssl static library from source code failed.')
|
||||
if not os.path.exists(installer):
|
||||
if not utils.download_file('openssl installer', 'http://slproweb.com/download/{}'.format(filename), PATH_DOWNLOAD, file_name):
|
||||
cc.e('can not download pre-built installer of OpenSSL.')
|
||||
return
|
||||
|
||||
utils.ensure_file_exists(installer)
|
||||
|
||||
cc.w('On Windows, we use pre-built package of OpenSSL.')
|
||||
cc.w('The installer have been downloaded at "{}".'.format(installer))
|
||||
cc.w('please install OpenSSL into "{}".'.format(self.OPENSSL_PATH_SRC))
|
||||
cc.w('\nOnce the OpenSSL installed, press Enter to continue or Q to quit...', end='')
|
||||
try:
|
||||
x = env.input()
|
||||
except EOFError:
|
||||
x = 'q'
|
||||
if x == 'q':
|
||||
return
|
||||
|
||||
|
||||
# cc.n('build openssl static library from source code... ')
|
||||
|
||||
# if not super()._build_openssl(file_name):
|
||||
# return
|
||||
|
||||
# _chk_output = [
|
||||
# os.path.join(self.OPENSSL_PATH_SRC, 'out32', 'libeay32.lib'),
|
||||
# os.path.join(self.OPENSSL_PATH_SRC, 'out32', 'ssleay32.lib'),
|
||||
# os.path.join(self.OPENSSL_PATH_SRC, 'inc32', 'openssl', 'opensslconf.h'),
|
||||
# ]
|
||||
|
||||
# need_build = False
|
||||
# for f in _chk_output:
|
||||
# if not os.path.exists(f):
|
||||
# need_build = True
|
||||
# break
|
||||
|
||||
# if not need_build:
|
||||
# cc.n('build openssl static library from source code... ', end='')
|
||||
# cc.w('already exists, skip.')
|
||||
# return
|
||||
# cc.v('')
|
||||
|
||||
# cc.n('prepare openssl source code...')
|
||||
# _alt_ver = '_'.join(env.ver_ossl.split('.'))
|
||||
# if not os.path.exists(self.OPENSSL_PATH_SRC):
|
||||
# utils.unzip(os.path.join(PATH_DOWNLOAD, file_name), PATH_EXTERNAL)
|
||||
# os.rename(os.path.join(PATH_EXTERNAL, 'openssl-OpenSSL_{}'.format(_alt_ver)), self.OPENSSL_PATH_SRC)
|
||||
# if not os.path.exists(self.OPENSSL_PATH_SRC):
|
||||
# raise RuntimeError('can not prepare openssl source code.')
|
||||
# else:
|
||||
# cc.w('already exists, skip.')
|
||||
|
||||
# os.chdir(self.OPENSSL_PATH_SRC)
|
||||
# os.system('""{}" Configure VC-WIN32"'.format(env.perl))
|
||||
# os.system(r'ms\do_nasm')
|
||||
# # for vs2015
|
||||
# # utils.sys_exec(r'"{}\VC\bin\vcvars32.bat" && nmake -f ms\nt.mak'.format(env.visual_studio_path), direct_output=True)
|
||||
# # for vs2017 community
|
||||
# utils.sys_exec(r'"{}VC\Auxiliary\Build\vcvars32.bat" && nmake -f ms\nt.mak'.format(env.visual_studio_path), direct_output=True)
|
||||
|
||||
# for f in _chk_output:
|
||||
# if not os.path.exists(f):
|
||||
# raise RuntimeError('build openssl static library from source code failed.')
|
||||
|
||||
def _build_libssh(self, file_name):
|
||||
cc.n('build libssh static library from source code... ', end='')
|
||||
if not self._download_libssh(file_name):
|
||||
return
|
||||
cc.n('build libssh library from source code... ', end='')
|
||||
|
||||
if not os.path.exists(self.LIBSSH_PATH_SRC):
|
||||
cc.v('')
|
||||
utils.unzip(os.path.join(PATH_DOWNLOAD, file_name), PATH_EXTERNAL)
|
||||
os.rename(os.path.join(PATH_EXTERNAL, 'libssh-{}'.format(env.ver_libssh)), self.LIBSSH_PATH_SRC)
|
||||
|
||||
# cc.n('fix libssh source code... ', end='')
|
||||
# utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', 'src', 'sftp.c'))
|
||||
# utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'sftp.c')
|
||||
cc.n('fix libssh source code... ', end='')
|
||||
s_name = 'libssh-{}'.format(env.ver_libssh)
|
||||
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'session.c'))
|
||||
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'libcrypto.c'))
|
||||
# utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'libcrypto.c'))
|
||||
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'libcrypto-compat.c'))
|
||||
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'session.c')
|
||||
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'libcrypto.c')
|
||||
# utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'libcrypto.c')
|
||||
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'libcrypto-compat.c')
|
||||
|
||||
out_file_lib = os.path.join(self.LIBSSH_PATH_SRC, 'lib', ctx.target_path, 'ssh.lib')
|
||||
|
@ -210,7 +260,7 @@ class BuilderWin(BuilderBase):
|
|||
|
||||
cc.i('build libssh...')
|
||||
sln_file = os.path.join(self.LIBSSH_PATH_SRC, 'build', 'libssh.sln')
|
||||
utils.msvc_build(sln_file, 'ssh_shared', ctx.target_path, 'win32', False)
|
||||
utils.msvc_build(sln_file, 'ssh', ctx.target_path, 'win32', False)
|
||||
utils.ensure_file_exists(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src', ctx.target_path, 'ssh.lib'))
|
||||
utils.ensure_file_exists(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src', ctx.target_path, 'ssh.dll'))
|
||||
utils.copy_file(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src', ctx.target_path), os.path.join(self.LIBSSH_PATH_SRC, 'lib', ctx.target_path), 'ssh.lib')
|
||||
|
@ -218,7 +268,53 @@ class BuilderWin(BuilderBase):
|
|||
utils.ensure_file_exists(out_file_lib)
|
||||
utils.ensure_file_exists(out_file_dll)
|
||||
|
||||
def _build_zlib(self, file_name):
|
||||
if not self._download_zlib(file_name):
|
||||
return
|
||||
cc.n('build zlib library from source code... ', end='')
|
||||
|
||||
if not os.path.exists(self.ZLIB_PATH_SRC):
|
||||
cc.v('')
|
||||
utils.unzip(os.path.join(PATH_DOWNLOAD, file_name), PATH_EXTERNAL)
|
||||
os.rename(os.path.join(PATH_EXTERNAL, 'zlib-{}'.format(env.ver_zlib)), self.ZLIB_PATH_SRC)
|
||||
|
||||
if ctx.target_path == 'debug':
|
||||
olib = 'zlibd.lib'
|
||||
odll = 'zlibd.dll'
|
||||
else:
|
||||
olib = 'zlib.lib'
|
||||
odll = 'zlib.dll'
|
||||
out_file_lib = os.path.join(self.ZLIB_PATH_SRC, 'build', ctx.target_path, olib)
|
||||
out_file_dll = os.path.join(self.ZLIB_PATH_SRC, 'build', ctx.target_path, odll)
|
||||
|
||||
if os.path.exists(out_file_lib) and os.path.exists(out_file_dll):
|
||||
cc.w('already exists, skip.')
|
||||
return
|
||||
cc.v('')
|
||||
|
||||
cc.w('On Windows, when build zlib, need you use cmake-gui.exe to generate solution file')
|
||||
cc.w('for Visual Studio 2017. Visit https://docs.tp4a.com for more details.')
|
||||
cc.w('\nOnce the zlib.sln generated, press Enter to continue or Q to quit...', end='')
|
||||
try:
|
||||
x = env.input()
|
||||
except EOFError:
|
||||
x = 'q'
|
||||
if x == 'q':
|
||||
return
|
||||
|
||||
cc.i('build zlib...')
|
||||
sln_file = os.path.join(self.ZLIB_PATH_SRC, 'build', 'zlib.sln')
|
||||
utils.msvc_build(sln_file, 'zlib', ctx.target_path, 'win32', False)
|
||||
# utils.ensure_file_exists(os.path.join(self.ZLIB_PATH_SRC, 'build', ctx.target_path, 'zlib.lib'))
|
||||
# utils.ensure_file_exists(os.path.join(self.ZLIB_PATH_SRC, 'build', ctx.target_path, 'zlib.dll'))
|
||||
# utils.copy_file(os.path.join(self.ZLIB_PATH_SRC, 'build', ctx.target_path), os.path.join(self.ZLIB_PATH_SRC, 'lib', ctx.target_path), 'zlib.lib')
|
||||
# utils.copy_file(os.path.join(self.ZLIB_PATH_SRC, 'build', ctx.target_path), os.path.join(self.ZLIB_PATH_SRC, 'lib', ctx.target_path), 'zlib.dll')
|
||||
utils.ensure_file_exists(out_file_lib)
|
||||
utils.ensure_file_exists(out_file_dll)
|
||||
|
||||
def _build_jsoncpp(self, file_name):
|
||||
if not self._download_jsoncpp(file_name):
|
||||
return
|
||||
cc.n('prepare jsoncpp source code... ', end='')
|
||||
if not os.path.exists(self.JSONCPP_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -228,6 +324,8 @@ class BuilderWin(BuilderBase):
|
|||
cc.w('already exists, skip.')
|
||||
|
||||
def _build_mongoose(self, file_name):
|
||||
if not self._download_mongoose(file_name):
|
||||
return
|
||||
cc.n('prepare mongoose source code... ', end='')
|
||||
if not os.path.exists(self.MONGOOSE_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -237,6 +335,8 @@ class BuilderWin(BuilderBase):
|
|||
cc.w('already exists, skip.')
|
||||
|
||||
def _build_mbedtls(self, file_name):
|
||||
if not self._download_mbedtls(file_name):
|
||||
return
|
||||
cc.n('prepare mbedtls source code... ', end='')
|
||||
if not os.path.exists(self.MBEDTLS_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -254,6 +354,8 @@ class BuilderWin(BuilderBase):
|
|||
# utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'library'), os.path.join(self.MBEDTLS_PATH_SRC, 'library'), 'rsa.c')
|
||||
|
||||
def _build_libuv(self, file_name):
|
||||
if not self._download_libuv(file_name):
|
||||
return
|
||||
cc.n('prepare libuv source code... ', end='')
|
||||
if not os.path.exists(self.LIBUV_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -277,6 +379,7 @@ class BuilderLinux(BuilderBase):
|
|||
self.LIBUV_PATH_SRC = os.path.join(self.PATH_TMP, 'libuv-{}'.format(env.ver_libuv))
|
||||
self.MBEDTLS_PATH_SRC = os.path.join(self.PATH_TMP, 'mbedtls-mbedtls-{}'.format(env.ver_mbedtls))
|
||||
self.LIBSSH_PATH_SRC = os.path.join(self.PATH_TMP, 'libssh-{}'.format(env.ver_libssh))
|
||||
self.ZLIB_PATH_SRC = os.path.join(self.PATH_TMP, 'zlib-{}'.format(env.ver_zlib))
|
||||
|
||||
self.JSONCPP_PATH_SRC = os.path.join(PATH_EXTERNAL, 'jsoncpp')
|
||||
self.MONGOOSE_PATH_SRC = os.path.join(PATH_EXTERNAL, 'mongoose')
|
||||
|
@ -288,7 +391,7 @@ class BuilderLinux(BuilderBase):
|
|||
cc.n('prepare python header and lib files ...')
|
||||
|
||||
if os.path.exists(os.path.join(self.PATH_RELEASE, 'include', 'python', 'Python.h')):
|
||||
cc.w(' - header file already exists, skip.')
|
||||
cc.w('python header file already exists, skip.')
|
||||
else:
|
||||
utils.ensure_file_exists(os.path.join(self.PATH_RELEASE, 'include', 'python{}m'.format(ctx.py_dot_ver), 'Python.h'))
|
||||
utils.sys_exec('ln -s "{}" "{}"'.format(
|
||||
|
@ -300,6 +403,8 @@ class BuilderLinux(BuilderBase):
|
|||
utils.ensure_file_exists(os.path.join(self.PATH_RELEASE, 'lib', lib_file))
|
||||
|
||||
def _build_jsoncpp(self, file_name):
|
||||
if not self._download_jsoncpp(file_name):
|
||||
return
|
||||
cc.n('prepare jsoncpp source code...', end='')
|
||||
if not os.path.exists(self.JSONCPP_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -309,6 +414,8 @@ class BuilderLinux(BuilderBase):
|
|||
cc.w('already exists, skip.')
|
||||
|
||||
def _build_mongoose(self, file_name):
|
||||
if not self._download_mongoose(file_name):
|
||||
return
|
||||
cc.n('prepare mongoose source code...', end='')
|
||||
if not os.path.exists(self.MONGOOSE_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -318,9 +425,12 @@ class BuilderLinux(BuilderBase):
|
|||
cc.w('already exists, skip.')
|
||||
|
||||
def _build_openssl(self, file_name):
|
||||
pass # we do not need build openssl anymore, because first time run build.sh we built Python, it include openssl.
|
||||
# we do not need build openssl anymore, because first time run build.sh we built Python with openssl included.
|
||||
cc.w('skip build openssl again.')
|
||||
|
||||
def _build_libuv(self, file_name):
|
||||
if not self._download_libuv(file_name):
|
||||
return
|
||||
if not os.path.exists(self.LIBUV_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
||||
|
@ -347,7 +457,11 @@ class BuilderLinux(BuilderBase):
|
|||
# use os.unlink() because some file should be a link.
|
||||
os.unlink(os.path.join(self.PATH_RELEASE, 'lib', i))
|
||||
|
||||
utils.ensure_file_exists(os.path.join(self.PATH_RELEASE, 'lib', 'libuv.a'))
|
||||
|
||||
def _build_mbedtls(self, file_name):
|
||||
if not self._download_mbedtls(file_name):
|
||||
return
|
||||
if not os.path.exists(self.MBEDTLS_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
||||
|
@ -382,8 +496,6 @@ class BuilderLinux(BuilderBase):
|
|||
# fix source file
|
||||
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'include', 'mbedtls', 'config.h'))
|
||||
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'include', 'mbedtls'), os.path.join(self.MBEDTLS_PATH_SRC, 'include', 'mbedtls'), 'config.h')
|
||||
# utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'library', 'rsa.c'))
|
||||
# utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'mbedtls', 'library'), os.path.join(self.MBEDTLS_PATH_SRC, 'library'), 'rsa.c')
|
||||
|
||||
old_p = os.getcwd()
|
||||
os.chdir(self.MBEDTLS_PATH_SRC)
|
||||
|
@ -392,11 +504,14 @@ class BuilderLinux(BuilderBase):
|
|||
os.chdir(old_p)
|
||||
|
||||
def _build_libssh(self, file_name):
|
||||
if not self._download_libssh(file_name):
|
||||
return
|
||||
if not os.path.exists(self.LIBSSH_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
||||
cc.n('build libssh...', end='')
|
||||
if os.path.exists(os.path.join(self.PATH_RELEASE, 'lib', 'libssh.a')):
|
||||
out_file = os.path.join(self.PATH_RELEASE, 'lib64', 'libssh.a')
|
||||
if os.path.exists(out_file):
|
||||
cc.w('already exists, skip.')
|
||||
return
|
||||
cc.v('')
|
||||
|
@ -404,10 +519,10 @@ class BuilderLinux(BuilderBase):
|
|||
cc.n('fix libssh source code... ', end='')
|
||||
s_name = 'libssh-{}'.format(env.ver_libssh)
|
||||
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'session.c'))
|
||||
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'libcrypto.c'))
|
||||
# utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'libcrypto.c'))
|
||||
utils.ensure_file_exists(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src', 'libcrypto-compat.c'))
|
||||
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'session.c')
|
||||
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'libcrypto.c')
|
||||
# utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'libcrypto.c')
|
||||
utils.copy_file(os.path.join(PATH_EXTERNAL, 'fix-external', 'libssh', s_name, 'src'), os.path.join(self.LIBSSH_PATH_SRC, 'src'), 'libcrypto-compat.c')
|
||||
|
||||
build_path = os.path.join(self.LIBSSH_PATH_SRC, 'build')
|
||||
|
@ -417,14 +532,52 @@ class BuilderLinux(BuilderBase):
|
|||
' -DOPENSSL_LIBRARIES={path_release}/lib' \
|
||||
' -DWITH_SFTP=ON' \
|
||||
' -DWITH_SERVER=ON' \
|
||||
' -DWITH_STATIC_LIB=ON' \
|
||||
' -DWITH_GSSAPI=OFF' \
|
||||
' -DWITH_ZLIB=OFF' \
|
||||
' -DWITH_ZLIB=ON' \
|
||||
' -DWITH_PCAP=OFF' \
|
||||
' -DBUILD_SHARED_LIBS=OFF' \
|
||||
' -DUNIT_TESTING=OFF' \
|
||||
' -DWITH_EXAMPLES=OFF' \
|
||||
' -DWITH_BENCHMARKS=OFF' \
|
||||
' -DWITH_NACL=OFF' \
|
||||
''.format(path_release=self.PATH_RELEASE)
|
||||
|
||||
# ' -DWITH_STATIC_LIB=ON'
|
||||
|
||||
|
||||
old_p = os.getcwd()
|
||||
try:
|
||||
utils.cmake(build_path, 'Release', False, cmake_define=cmake_define, cmake_pre_define='CFLAGS="-fPIC"')
|
||||
os.chdir(build_path)
|
||||
utils.sys_exec('make install')
|
||||
except:
|
||||
pass
|
||||
os.chdir(old_p)
|
||||
|
||||
utils.ensure_file_exists(out_file)
|
||||
# files = os.listdir(os.path.join(self.PATH_RELEASE, 'lib'))
|
||||
# for i in files:
|
||||
# if i.startswith('libssh.so'):
|
||||
# # use os.unlink() because some file should be a link.
|
||||
# os.unlink(os.path.join(self.PATH_RELEASE, 'lib', i))
|
||||
|
||||
def _build_zlib(self, file_name):
|
||||
# cc.w('skip build zlib again.')
|
||||
if not self._download_zlib(file_name):
|
||||
return
|
||||
if not os.path.exists(self.ZLIB_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
||||
cc.n('build zlib...', end='')
|
||||
out_file = os.path.join(self.PATH_RELEASE, 'lib', 'libz.a')
|
||||
if os.path.exists(out_file):
|
||||
cc.w('already exists, skip.')
|
||||
return
|
||||
cc.v('')
|
||||
|
||||
build_path = os.path.join(self.ZLIB_PATH_SRC, 'build')
|
||||
|
||||
cmake_define = ' -DCMAKE_INSTALL_PREFIX={path_release}' \
|
||||
' ..'.format(path_release=self.PATH_RELEASE)
|
||||
|
||||
old_p = os.getcwd()
|
||||
|
@ -436,10 +589,10 @@ class BuilderLinux(BuilderBase):
|
|||
pass
|
||||
os.chdir(old_p)
|
||||
|
||||
utils.ensure_file_exists(os.path.join(self.PATH_RELEASE, 'lib', 'libssh.a'))
|
||||
utils.ensure_file_exists(out_file)
|
||||
files = os.listdir(os.path.join(self.PATH_RELEASE, 'lib'))
|
||||
for i in files:
|
||||
if i.startswith('libssh.so'):
|
||||
if i.startswith('libz.so'):
|
||||
# use os.unlink() because some file should be a link.
|
||||
os.unlink(os.path.join(self.PATH_RELEASE, 'lib', i))
|
||||
|
||||
|
@ -458,6 +611,7 @@ class BuilderMacOS(BuilderBase):
|
|||
self.LIBUV_PATH_SRC = os.path.join(self.PATH_TMP, 'libuv-{}'.format(env.ver_libuv))
|
||||
self.MBEDTLS_PATH_SRC = os.path.join(self.PATH_TMP, 'mbedtls-mbedtls-{}'.format(env.ver_mbedtls))
|
||||
self.LIBSSH_PATH_SRC = os.path.join(self.PATH_TMP, 'libssh-{}'.format(env.ver_libssh))
|
||||
self.ZLIB_PATH_SRC = os.path.join(self.PATH_TMP, 'zlib-{}'.format(env.ver_zlib))
|
||||
|
||||
self.JSONCPP_PATH_SRC = os.path.join(PATH_EXTERNAL, 'jsoncpp')
|
||||
self.MONGOOSE_PATH_SRC = os.path.join(PATH_EXTERNAL, 'mongoose')
|
||||
|
@ -466,6 +620,8 @@ class BuilderMacOS(BuilderBase):
|
|||
utils.makedirs(self.PATH_TMP)
|
||||
|
||||
def _build_jsoncpp(self, file_name):
|
||||
if not self._download_jsoncpp(file_name):
|
||||
return
|
||||
cc.n('prepare jsoncpp source code...', end='')
|
||||
if not os.path.exists(self.JSONCPP_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -475,6 +631,8 @@ class BuilderMacOS(BuilderBase):
|
|||
cc.w('already exists, skip.')
|
||||
|
||||
def _build_mongoose(self, file_name):
|
||||
if not self._download_mongoose(file_name):
|
||||
return
|
||||
cc.n('prepare mongoose source code...', end='')
|
||||
if not os.path.exists(self.MONGOOSE_PATH_SRC):
|
||||
cc.v('')
|
||||
|
@ -484,7 +642,10 @@ class BuilderMacOS(BuilderBase):
|
|||
cc.w('already exists, skip.')
|
||||
|
||||
def _build_openssl(self, file_name):
|
||||
if not super()._build_openssl(file_name):
|
||||
cc.w('skip build openssl again.')
|
||||
return
|
||||
|
||||
if not self._download_openssl(file_name):
|
||||
return
|
||||
|
||||
cc.n('prepare openssl source code...', end='')
|
||||
|
@ -512,6 +673,8 @@ class BuilderMacOS(BuilderBase):
|
|||
os.chdir(old_p)
|
||||
|
||||
def _build_libuv(self, file_name):
|
||||
if not self._download_libuv(file_name):
|
||||
return
|
||||
cc.n('prepare libuv source code...', end='')
|
||||
if not os.path.exists(self.LIBUV_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
@ -534,6 +697,8 @@ class BuilderMacOS(BuilderBase):
|
|||
os.chdir(old_p)
|
||||
|
||||
def _build_mbedtls(self, file_name):
|
||||
if not self._download_mbedtls(file_name):
|
||||
return
|
||||
if not os.path.exists(self.MBEDTLS_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
||||
|
@ -578,6 +743,11 @@ class BuilderMacOS(BuilderBase):
|
|||
os.chdir(old_p)
|
||||
|
||||
def _build_libssh(self, file_name):
|
||||
# cc.n('skip build libssh on macOS.')
|
||||
# return
|
||||
|
||||
if not self._download_libssh(file_name):
|
||||
return
|
||||
if not os.path.exists(self.LIBSSH_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
||||
|
@ -591,20 +761,24 @@ class BuilderMacOS(BuilderBase):
|
|||
build_path = os.path.join(self.LIBSSH_PATH_SRC, 'build')
|
||||
|
||||
cmake_define = ' -DCMAKE_INSTALL_PREFIX={path_release}' \
|
||||
' -DOPENSSL_INCLUDE_DIR={path_release}/include' \
|
||||
' -DOPENSSL_LIBRARIES={path_release}/lib' \
|
||||
' -DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include' \
|
||||
' -DOPENSSL_LIBRARIES=/usr/local/opt/openssl/lib' \
|
||||
' -DWITH_GCRYPT=OFF' \
|
||||
' -DWITH_GEX=OFF' \
|
||||
' -DWITH_SFTP=ON' \
|
||||
' -DWITH_SERVER=ON' \
|
||||
' -DWITH_STATIC_LIB=ON' \
|
||||
' -DWITH_GSSAPI=OFF' \
|
||||
' -DWITH_ZLIB=OFF' \
|
||||
' -DWITH_ZLIB=ON' \
|
||||
' -DWITH_PCAP=OFF' \
|
||||
' -DBUILD_SHARED_LIBS=OFF' \
|
||||
' -DUNIT_TESTING=OFF' \
|
||||
' -DWITH_EXAMPLES=OFF' \
|
||||
' -DWITH_BENCHMARKS=OFF' \
|
||||
' -DWITH_NACL=OFF' \
|
||||
''.format(path_release=self.PATH_RELEASE)
|
||||
|
||||
# ' -DWITH_STATIC_LIB=ON'
|
||||
|
||||
try:
|
||||
utils.cmake(build_path, 'Release', False, cmake_define)
|
||||
except:
|
||||
|
@ -618,6 +792,41 @@ class BuilderMacOS(BuilderBase):
|
|||
# utils.copy_file(os.path.join(self.LIBSSH_PATH_SRC, 'build', 'src', 'threads'), os.path.join(self.PATH_RELEASE, 'lib'), 'libssh_threads.a')
|
||||
utils.copy_ex(os.path.join(self.LIBSSH_PATH_SRC, 'include'), os.path.join(self.PATH_RELEASE, 'include'), 'libssh')
|
||||
|
||||
def _build_zlib(self, file_name):
|
||||
# cc.w('skip build zlib again.')
|
||||
if not self._download_zlib(file_name):
|
||||
return
|
||||
if not os.path.exists(self.ZLIB_PATH_SRC):
|
||||
os.system('unzip "{}/{}" -d "{}"'.format(PATH_DOWNLOAD, file_name, self.PATH_TMP))
|
||||
|
||||
cc.n('build zlib...', end='')
|
||||
out_file = os.path.join(self.PATH_RELEASE, 'lib', 'libz.a')
|
||||
if os.path.exists(out_file):
|
||||
cc.w('already exists, skip.')
|
||||
return
|
||||
cc.v('')
|
||||
|
||||
build_path = os.path.join(self.ZLIB_PATH_SRC, 'build')
|
||||
|
||||
cmake_define = ' -DCMAKE_INSTALL_PREFIX={path_release}' \
|
||||
' ..'.format(path_release=self.PATH_RELEASE)
|
||||
|
||||
old_p = os.getcwd()
|
||||
try:
|
||||
utils.cmake(build_path, 'Release', False, cmake_define=cmake_define, cmake_pre_define='CFLAGS="-fPIC"')
|
||||
os.chdir(build_path)
|
||||
utils.sys_exec('make install')
|
||||
except:
|
||||
pass
|
||||
os.chdir(old_p)
|
||||
|
||||
utils.ensure_file_exists(out_file)
|
||||
files = os.listdir(os.path.join(self.PATH_RELEASE, 'lib'))
|
||||
for i in files:
|
||||
if i.startswith('libz.so'):
|
||||
# use os.unlink() because some file should be a link.
|
||||
os.unlink(os.path.join(self.PATH_RELEASE, 'lib', i))
|
||||
|
||||
def _prepare_python(self):
|
||||
pass
|
||||
|
||||
|
@ -673,6 +882,7 @@ def main():
|
|||
builder.build_openssl()
|
||||
builder.build_libuv()
|
||||
builder.build_mbedtls()
|
||||
builder.build_zlib()
|
||||
builder.build_libssh()
|
||||
|
||||
builder.fix_output()
|
||||
|
|
|
@ -13,11 +13,11 @@ ctx = BuildContext()
|
|||
|
||||
MODULES_WIN = ['_asyncio', '_bz2', '_ctypes', '_hashlib', '_lzma', '_overlapped', '_socket', '_sqlite3', '_ssl', 'select', 'sqlite3',
|
||||
'libcrypto-1_1', 'libssl-1_1', 'unicodedata']
|
||||
PY_LIB_REMOVE_WIN = ['ctypes/test', 'curses', 'dbm', 'distutils', 'email/test', 'ensurepip', 'idlelib', 'lib2to3',
|
||||
PY_LIB_REMOVE_WIN = ['ctypes/test', 'curses', 'dbm', 'distutils/test', 'email/tests', 'ensurepip', 'idlelib', 'lib2to3',
|
||||
'lib-dynload', 'pydoc_data', 'site-packages', 'sqlite3/test', 'test', 'tkinter', 'turtledemo',
|
||||
'unittest', 'venv', 'wsgiref', 'doctest.py', 'pdb.py', 'py_compile.py', 'pydoc.py',
|
||||
'this.py', 'wave.py', 'webbrowser.py', 'zipapp.py']
|
||||
PY_LIB_REMOVE_LINUX = ['ctypes/test', 'curses', 'dbm', 'distutils', 'ensurepip', 'idlelib', 'lib2to3',
|
||||
PY_LIB_REMOVE_LINUX = ['ctypes/test', 'curses', 'dbm', 'distutils/tests', 'ensurepip', 'idlelib', 'lib2to3',
|
||||
'lib-dynload', 'pydoc_data', 'site-packages', 'sqlite3/test', 'test', 'tkinter', 'turtledemo', 'unittest', 'venv',
|
||||
'wsgiref', 'doctest.py', 'pdb.py', 'py_compile.py', 'pydoc.py', 'this.py', 'wave.py', 'webbrowser.py', 'zipapp.py']
|
||||
PY_MODULE_REMOVE_LINUX = ['_ctypes_test', '_testbuffer', '_testcapi', '_testimportmultiple', '_testmultiphase', '_xxtestfuzz']
|
||||
|
@ -46,7 +46,7 @@ class PYSBase:
|
|||
utils.sys_exec('{} -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pip --upgrade'.format(env.py_exec))
|
||||
|
||||
pip = self._get_pip()
|
||||
pypi_modules = ['ldap3', 'mako', 'Pillow', 'psutil', 'pymysql', 'qrcode', 'tornado', 'wheezy.captcha']
|
||||
pypi_modules = ['cffi', 'cryptography', 'ldap3', 'mako', 'Pillow', 'psutil', 'pyasn1', 'pymysql', 'qrcode', 'tornado', 'wheezy.captcha']
|
||||
for p in pypi_modules:
|
||||
cc.n('install {} ...'.format(p))
|
||||
utils.sys_exec('{} install -i https://pypi.tuna.tsinghua.edu.cn/simple {}'.format(pip, p), direct_output=True)
|
||||
|
@ -111,7 +111,7 @@ class PYSBase:
|
|||
utils.ensure_file_exists(out_file)
|
||||
|
||||
cc.v('remove temp folder...')
|
||||
utils.remove(_tmp_)
|
||||
# utils.remove(_tmp_)
|
||||
|
||||
def _make_py_ver_file(self):
|
||||
pass
|
||||
|
@ -250,7 +250,7 @@ class PYSLinux(PYSBase):
|
|||
|
||||
def _get_pip(self):
|
||||
_exec_path = os.path.dirname(env.py_exec)
|
||||
return os.path.join(_exec_path, 'pip')
|
||||
return os.path.join(_exec_path, 'pip3.7')
|
||||
|
||||
def _make_py_ver_file(self):
|
||||
# do nothing.
|
||||
|
|
|
@ -18,6 +18,7 @@ class Builder:
|
|||
self.VER_TP_TPCORE = ''
|
||||
self.VER_TP_TPWEB = ''
|
||||
self.VER_TP_ASSIST = ''
|
||||
self.VER_TP_ASSIST_REQUIRE = ''
|
||||
|
||||
def build(self):
|
||||
cc.n('update version...')
|
||||
|
@ -43,12 +44,17 @@ class Builder:
|
|||
x = l.split(' ')
|
||||
self.VER_TP_ASSIST = x[1].strip()
|
||||
# self.VER_TP_ASSIST += '.0'
|
||||
elif l.startswith('TP_ASSIST_REQUIRE '):
|
||||
x = l.split(' ')
|
||||
self.VER_TP_ASSIST_REQUIRE = x[1].strip()
|
||||
# self.VER_TP_ASSIST += '.0'
|
||||
|
||||
cc.v('new version:')
|
||||
cc.v(' Server : ', self.VER_TP_SERVER)
|
||||
cc.v(' - tp_core : ', self.VER_TP_TPCORE)
|
||||
cc.v(' - tp_web : ', self.VER_TP_TPWEB)
|
||||
cc.v(' Assist : ', self.VER_TP_ASSIST)
|
||||
cc.v(' - Require : ', self.VER_TP_ASSIST_REQUIRE)
|
||||
cc.v('')
|
||||
|
||||
self.make_builder_ver()
|
||||
|
@ -100,7 +106,12 @@ class Builder:
|
|||
def make_server_ver(self):
|
||||
ver_file = os.path.join(env.root_path, 'server', 'www', 'teleport', 'webroot', 'app', 'app_ver.py')
|
||||
# ver_content = '# -*- coding: utf8 -*-\n\nTS_VER = "{}"\n'.format(self.VER_TELEPORT_SERVER)
|
||||
ver_content = '# -*- coding: utf8 -*-\nTP_SERVER_VER = "{}"\n'.format(self.VER_TP_SERVER)
|
||||
# ver_content = '# -*- coding: utf8 -*-\nTP_SERVER_VER = "{}"\n'.format(self.VER_TP_SERVER)
|
||||
ver_content = '' \
|
||||
'# -*- coding: utf8 -*-\n' \
|
||||
'TP_SERVER_VER = "{}"\n' \
|
||||
'TP_ASSIST_REQUIRE_VER = "{}"\n' \
|
||||
''.format(self.VER_TP_SERVER, self.VER_TP_ASSIST_REQUIRE)
|
||||
|
||||
rewrite = False
|
||||
if not os.path.exists(ver_file):
|
||||
|
|
|
@ -148,6 +148,11 @@ class Env(object):
|
|||
if warn_miss_tool:
|
||||
cc.w(' - can not locate `nsis`, so I can not make installer.')
|
||||
|
||||
if 'qt' in _tmp:
|
||||
self.qt = _tmp['qt']
|
||||
else:
|
||||
self.qt = None
|
||||
|
||||
elif self.is_linux or self.is_macos:
|
||||
if 'cmake' in _tmp:
|
||||
self.cmake = _tmp['cmake']
|
||||
|
@ -178,6 +183,10 @@ class Env(object):
|
|||
self.ver_ossl = _v_openssl[0].strip()
|
||||
self.ver_ossl_number = _v_openssl[1].strip()
|
||||
|
||||
_v_zlib = _tmp['zlib'].split(',')
|
||||
self.ver_zlib = _v_zlib[0].strip()
|
||||
self.ver_zlib_number = _v_zlib[1].strip()
|
||||
|
||||
self.ver_libuv = _tmp['libuv']
|
||||
self.ver_mbedtls = _tmp['mbedtls']
|
||||
# self.ver_sqlite = _tmp['sqlite']
|
||||
|
|
|
@ -320,6 +320,21 @@ def msvc_build(sln_file, proj_name, target, platform, force_rebuild):
|
|||
raise RuntimeError('build MSVC project `{}` failed.'.format(proj_name))
|
||||
|
||||
|
||||
def qt_build_win(prj_path, prj_name, bit_path, target_path):
|
||||
cc.n(env.visual_studio_path)
|
||||
if env.qt is None:
|
||||
raise RuntimeError('where is `qt`?')
|
||||
|
||||
if env.is_win:
|
||||
tmp_path = os.path.join(env.root_path, 'out', '_tmp_', prj_name, bit_path)
|
||||
# C:\Windows\System32\cmd.exe /A /Q /K C:\Qt\Qt5.12.0\5.12.0\msvc2017\bin\qtenv2.bat
|
||||
cmd = 'C:\\Windows\\System32\\cmd.exe /A /Q /C ""{}\qt-helper.bat" "{}\\bin\\qtenv2.bat" "{}VC\\Auxiliary\\Build\\vcvarsall.bat" {} "{}" "{}" {}"'.format(env.build_path, env.qt, env.visual_studio_path, bit_path, tmp_path, prj_path, target_path)
|
||||
ret, _ = sys_exec(cmd, direct_output=True)
|
||||
if ret != 0:
|
||||
raise RuntimeError('build XCode project `{}` failed.'.format(proj_name))
|
||||
|
||||
|
||||
|
||||
def xcode_build(proj_file, proj_name, target, force_rebuild):
|
||||
if force_rebuild:
|
||||
cmd = 'xcodebuild -project "{}" -target {} -configuration {} clean'.format(proj_file, proj_name, target)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# -*- coding: utf8 -*-
|
||||
VER_TP_SERVER = "3.2.0"
|
||||
VER_TP_ASSIST = "3.2.0"
|
||||
# -*- coding: utf8 -*-
|
||||
VER_TP_SERVER = "3.5.5"
|
||||
VER_TP_ASSIST = "3.5.5"
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDxI1ZDRvuNnkVB
|
||||
JgTZmnwF97d7Ace+R0gSSkWi2l2oezakLSdUUkiysr1wx45u2Du36FNqMGg7LiCZ
|
||||
SX1e2Zba96PI6vwNGnlprCfXTe2eV3W8kMPKA6c9X8BTktMZINNHO3K591jGx+uM
|
||||
fyrl6/CFVPHNkl73Ium9u91JXIX9BOata4RTlphmHADc+hPXuC6oeN8qayZvV2rV
|
||||
Jfx1wMlWCMiGJM36JJO5pywteBCKQkVJuJ7y29XF2wT690o+i6ugk+yI2/2OpiET
|
||||
2E5SYdvyhlbcU+iBERsnY3X7IvFY8/m00YIjIc3reGSEwt9M5WTPRCjgonnpQGAx
|
||||
9xWXwqkzAgMBAAECggEAT9b2YdInye0EWxy+cFoBBGzPeE/PlcW+LCghRFlutzEM
|
||||
l3FH21hfL6OUq7m3BCZeJ3cp3zfl2upb6sT1WKlMlHV36jc7ew8v8fgJPPVVXp7w
|
||||
oZ2A5estvVltsX4knOZMbgJV6xLldvOMnvkf9/6VpV/Jq9nxzXvmzmZcT0TuLCaF
|
||||
uPk/g/yD5qQ8LkWXDVJeBiDrrOZYo5F+T8bveYKKIEZV0ZAlXwJqVOUFnhffIaDF
|
||||
fZVDOv4K3+q0aRDLTY2hxptHZiKzpLXgU634nBN3fiy0Fj88upNIus22gjaz+Jfx
|
||||
2pYv22iGNXAMFQwGaeuT7d4+qhgxze8C7YlLJsJWCQKBgQD8kkXbgYG+8NoKmovz
|
||||
ki9nuK1R6On5pNjZ344SJm6t/s4FaxQhE/4oHvODwgolqKyT2Sq1K8/5NInRGA29
|
||||
xPqqkkhwWk3Zf9VTXgmuXsOikPhbCOuiehO+6/ZthmHYy1jBMqkAIWYaL9Ytn2qb
|
||||
dKMHwzNdnppQNdQnwmXI2ZdRBQKBgQD0aVTSOmKfKdIxH9qFLdbi2CoyJMzjAjm9
|
||||
Ss5M0OhI9wZnCXyjPBx4hOs+M/BKx4lQ296u2Dh+gSK3L8K3x8lVqqx8gd614qaC
|
||||
EWzXZpAbd1S835o2vVYEWXU0iI9s0jkj+VnILEWBMRPYManRUATB2phwRPulimdu
|
||||
o+BWN0GG1wKBgCYBxO1hMasQB1+tHf5LM0MCcWJwEDV27wLqNzDYA7O/MjVyhZbs
|
||||
sURMVAyxuGEuXrno5hpZO3SeyVZjrj2uVKIyXSA7FpfyOqHO9tn8fKgL9LOORhcv
|
||||
E6WZUH3uyO6cuwBnpTLV082BAVPgN2SpSpcycppV8Za8Yu6QvExbIgAZAoGBALcq
|
||||
ANETxDj3hHggIQlRkwqpaOXvQkSVtGOxne1fWdTkmz24lFlYgRWotwsErX29D6Ez
|
||||
RSzPCXd0m2mhN1G3PaEfqOgeA6NXWeV73Y+HY1PSGAT7pXyEY+QajoVyGdo5qWzW
|
||||
P3yOAQCSoQaSIWulhgspILhyWgxzLpRx53t1KXw9AoGBAOxsrIrx/S6onTz58ncZ
|
||||
m99OWwJX4WmY5KKhc5dWrfgHrNfldSbhjRhjALy6hSPzkaVy01wXKeeIZl64rUbd
|
||||
S/r58yALQ5wuIHAi53BLStxgqEdHQHLg16GqL3b/+Waaf+Fy9y5eoUQ976HPr33G
|
||||
uDJ1AAnWjX3KvcyZeWLFTU2/
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+xdLVfN5IErS1
|
||||
UplYesMvkFZVBWlH2AojfJ8pSnaqfE6XeVWc/hoCpiqTSkGdoX4NLgy8cjAcvI9Z
|
||||
1E4Xdcuch161F4HH68V0CZsSK7LHHjXI9SLbjSyoUL0BvDIEGG9D2Zyqy8xTiVc6
|
||||
gBZBvR1pGRsh59KiRMNCPN67lT6PGTt+OxMJmh2laYBWh28Lbqx4R1nBl8/m1wZa
|
||||
QFhTTz0WBrBm4/3j95bQXIUjP0kW8uFcaIg0oA3/1EM5DrVQqJfp7ePEWevToP3H
|
||||
4Ny1/Wg/gWTpSiB/dgN8c3vXokWxabGJG/Oq5CWjtw9gWFyR0I/OmFh8cnWPf2vf
|
||||
QFVYQnv1AgMBAAECggEAeGs2ojuns6bbGnmBAjC7dBKP7Cr2QbtE6xGHBfFS5lqA
|
||||
4WxddjOPB40L4t1EfdOqVXdz4p/RbtI3SmSQxo48cBmi1nx4F1Hj2VMW52ld+AJB
|
||||
wQ+7aQq73aLZK3c3uw4Rbaq3EbiCyVgwD2U6p1RQdD68ubIzauostmrlzVJvorMZ
|
||||
1J0hz1gsJuH87WpkgRdp910hEYiM7eUBrOKG+K0trohVeStsjjJyV47LKxXDtf2F
|
||||
yUQvpbbIgHh2mXe29+d42hio2VrB5y1/+dc7wMiPlwBPG5xpv4eW1aaIGNTsHYCO
|
||||
1dy8KQirOsrGLIp0GzEej2XL/wTlHJfv3nSpYR2gIQKBgQD4I3lySzFqFUlrvZoX
|
||||
F9gYKbbH81gQakoAyk68qy4ENve5g+cChHTI6cO4fW8zIeEtLs/kDdpGuV20NmaD
|
||||
Pb8lcd7nONGhQ1l75aNAy978e2WuAYQ4xfMLR+8jKdTDG9ttIqhGFSNXetMGINLJ
|
||||
GkCl5fWAJ4p6oKBsUy2FgESECwKBgQDE0RWNQofR0UmxMPeHtD6i3pX2j3bb0GdM
|
||||
1yh8vqE1IqXJesVM//gIgSZ4n3hd93AXDQIvJ6xkdtNKbnGi5wJLf1OiYW3iSkfC
|
||||
l+Lgup10CVHJpOrBLxUGYZWjY4LsEX3z3MBNW4DQ6SNmIJN7xJAAewzq0UMMGk6P
|
||||
IIQ7rvT//wKBgQCqiDa+xc6ACYEb+oIbvNdWQ9TKNgMfxOx2/pJ+N2a4ns5BQNVS
|
||||
dZWNPpq0AACcM3x9gN5+7MZGNL6hS4HIUHc9VLTMU9A98/tbmsZHkdT90BBhNcmY
|
||||
+vG9nwJKOEVwkYSLzHW5NG3FgTPl0kkKzHABk7jVClexTxLxX3i5dx2fYQKBgCla
|
||||
bRbTJcp2GO+8BCZlPsvlzMiTeDvTXAEPLBiZzTFm6EKfIxl8ptbSnAy4JQhJVyng
|
||||
t9bElTo+pUJ8VjAOLbNDO4Vgxz/Gr7E5TJg/XZnl42Nk3VZd2CMRGenMnNOREU/N
|
||||
0DHwye4bLi7lJVfaAw+2yw4DjfzbAiqcgGwx5JRtAoGBAPFqMyLgZGtCBLrrJVxD
|
||||
kswm0gABU7l/UXS7OfLTWmfr0vDzoZEcVeBcabwmpRnsTaj1+EHcpl8kZogO4mcg
|
||||
0RiT+lc2E8TfZL5c4HEr4wSLbz8FEeKwhFa6ScNUOj5vVSnsFzW1xkVEBIM8akMR
|
||||
UI4+yvEjUIpuQt35cyE9K/nx
|
||||
-----END PRIVATE KEY-----
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEGTCCAwGgAwIBAgIEASUKPDANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJD
|
||||
MIIEHzCCAwegAwIBAgIEASUKQDANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJD
|
||||
TjENMAsGA1UECgwEVFA0QTEZMBcGA1UECwwQVFA0QSBUZWxlcG9ydCBDQTEZMBcG
|
||||
A1UEAwwQVFA0QSBUZWxlcG9ydCBDQTAgFw0xODExMDgxNzMyMjdaGA8yMTE4MTAx
|
||||
NTE3MzIyN1owXzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYDVQQHDAJ0
|
||||
A1UEAwwQVFA0QSBUZWxlcG9ydCBDQTAgFw0xOTAxMjUxMDM0MTVaGA8yMTE5MDEw
|
||||
MTEwMzQxNVowXzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkJKMQswCQYDVQQHDAJ0
|
||||
cDERMA8GA1UECgwIVGVsZXBvcnQxDzANBgNVBAsMBkFzc2lzdDESMBAGA1UEAwwJ
|
||||
bG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8SNWQ0b7
|
||||
jZ5FQSYE2Zp8Bfe3ewHHvkdIEkpFotpdqHs2pC0nVFJIsrK9cMeObtg7t+hTajBo
|
||||
Oy4gmUl9XtmW2vejyOr8DRp5aawn103tnld1vJDDygOnPV/AU5LTGSDTRztyufdY
|
||||
xsfrjH8q5evwhVTxzZJe9yLpvbvdSVyF/QTmrWuEU5aYZhwA3PoT17guqHjfKmsm
|
||||
b1dq1SX8dcDJVgjIhiTN+iSTuacsLXgQikJFSbie8tvVxdsE+vdKPouroJPsiNv9
|
||||
jqYhE9hOUmHb8oZW3FPogREbJ2N1+yLxWPP5tNGCIyHN63hkhMLfTOVkz0Qo4KJ5
|
||||
6UBgMfcVl8KpMwIDAQABo4HnMIHkMB0GA1UdDgQWBBRc5d0h39QISTM55kCqPyy1
|
||||
dohEHTB6BgNVHSMEczBxgBSh6jvPH2KfGq3ekij4vF+Bqa/roqFWpFQwUjELMAkG
|
||||
MTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvsXS1Xze
|
||||
SBK0tVKZWHrDL5BWVQVpR9gKI3yfKUp2qnxOl3lVnP4aAqYqk0pBnaF+DS4MvHIw
|
||||
HLyPWdROF3XLnIdetReBx+vFdAmbEiuyxx41yPUi240sqFC9AbwyBBhvQ9mcqsvM
|
||||
U4lXOoAWQb0daRkbIefSokTDQjzeu5U+jxk7fjsTCZodpWmAVodvC26seEdZwZfP
|
||||
5tcGWkBYU089FgawZuP94/eW0FyFIz9JFvLhXGiINKAN/9RDOQ61UKiX6e3jxFnr
|
||||
06D9x+Dctf1oP4Fk6Uogf3YDfHN716JFsWmxiRvzquQlo7cPYFhckdCPzphYfHJ1
|
||||
j39r30BVWEJ79QIDAQABo4HtMIHqMB0GA1UdDgQWBBQHRB+sP9RolTsf34gPFAJw
|
||||
6UKn2zB6BgNVHSMEczBxgBSh6jvPH2KfGq3ekij4vF+Bqa/roqFWpFQwUjELMAkG
|
||||
A1UEBhMCQ04xDTALBgNVBAoMBFRQNEExGTAXBgNVBAsMEFRQNEEgVGVsZXBvcnQg
|
||||
Q0ExGTAXBgNVBAMMEFRQNEEgVGVsZXBvcnQgQ0GCAQAwDAYDVR0TAQH/BAIwADAO
|
||||
BgNVHQ8BAf8EBAMCA4gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwFAYDVR0RBA0wC4IJ
|
||||
bG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQAfj/CpFDhv5CrnN2kxhtRAmesJ
|
||||
q6/KxxkBaimjbS/BpfvqfC9RxGH7MIqGUkbC4/ADkEt2OmVU4+f2R3+rCl+x+r1t
|
||||
9+3r/JSYYVBxFnF1GbDhiY9sKahgb4HoFjE2Fj8eVODcEzdApLr198p5IIIyfBys
|
||||
WHV4CYFMvq5qCKbSR/JMfrm9GArAh1J+B+JMIfm8xwerFi0tfK2YT+N4QkvbidjG
|
||||
sd+RKlR51GHo9m4iEQ7mDd9H8joVrVs2MVLGf2EoVU5y/Ahee4g7k3SKrn3GI/Ec
|
||||
6BRCht+INCLI3bnC3MtJHJRzv5Vmu4pSh3cwnVHfe+VWLGvGlp2+KeC02xZ2
|
||||
BgNVHQ8BAf8EBAMCA4gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGgYDVR0RBBMwEYIJ
|
||||
bG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQCagioxwrTdc9N5IVSH
|
||||
qbOXTGpUE4R7dvfCKatNJrGen7lAGdfqgomwM+fjRO5Jt0Kc15q8gxvQ3kePwaBY
|
||||
11f1FJ8iDMqxX7Hmb3KT0FeWKmUPgH3YtlitSAD7DrqMxBh5sr/28zN8XIjWWhY1
|
||||
huv7APQbuicxl/YZumPKa3r8FI1ca4pn4TKsm+YMN6Buy6k9CQV6POtNmawLNgNP
|
||||
axErEeTzNsis1JalHFAdr6mPWY0xaZsdrMeJHMx/7lvM7Qo+odEyswguoCS8Bc1Y
|
||||
6ZlEYZUev7lN0amqnoh25KrrGqpyHCXtXAEEwVyTmdpYDtqsetDYv7aCrfeITPBm
|
||||
GAyD
|
||||
-----END CERTIFICATE-----
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
"name": "FreeRDP",
|
||||
"display": "FreeRDP",
|
||||
"app": "",
|
||||
"cmdline": "",
|
||||
"cmdline": "/u:{user_name} /v:{host_ip} /port:{host_port}",
|
||||
"desc": [
|
||||
"建议使用homebrew安装freerdp,安装后freerdp默认路径在:/usr/local/Cellar/freerdp/x.y.z/bin/xfreerdp",
|
||||
"首次安装freerdp后需要重新启动计算机"
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
{
|
||||
"ssh": {
|
||||
"selected": "putty",
|
||||
"available": [
|
||||
{
|
||||
"name":"putty",
|
||||
"available": [{
|
||||
"name": "putty",
|
||||
"display": "PuTTY(内置)",
|
||||
"app": "{assist_tools_path}\\putty\\putty.exe",
|
||||
"cmdline": "-ssh -pw **** -P {host_port} -l {user_name} {host_ip}"
|
||||
|
@ -30,9 +29,8 @@
|
|||
},
|
||||
"scp": {
|
||||
"selected": "winscp",
|
||||
"available": [
|
||||
{
|
||||
"name":"winscp",
|
||||
"available": [{
|
||||
"name": "winscp",
|
||||
"display": "WinSCP(内置)",
|
||||
"app": "{assist_tools_path}\\winscp\\winscp.exe",
|
||||
"cmdline": "/sessionname=\"TP#{real_ip}\" {user_name}:****@{host_ip}:{host_port}"
|
||||
|
@ -47,9 +45,8 @@
|
|||
},
|
||||
"telnet": {
|
||||
"selected": "putty",
|
||||
"available": [
|
||||
{
|
||||
"name":"putty",
|
||||
"available": [{
|
||||
"name": "putty",
|
||||
"display": "PuTTY(内置)",
|
||||
"app": "{assist_tools_path}\\putty\\putty.exe",
|
||||
"cmdline": "telnet://{user_name}@{host_ip}:{host_port}"
|
||||
|
@ -68,15 +65,20 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"rdp" : {
|
||||
"available" : [
|
||||
{
|
||||
"app" : "{assist_tools_path}\\tprdp\\tprdp-client.exe",
|
||||
"cmdline" : "/v:{host_ip}:{host_port} /u:{user_name} /t:\"TP#{real_ip}\"",
|
||||
"display" : "FreeRDP(内置)",
|
||||
"name" : "freerdp"
|
||||
}
|
||||
],
|
||||
"selected" : "freerdp"
|
||||
}
|
||||
}
|
||||
"rdp": {
|
||||
"available": [{
|
||||
"app": "mstsc.exe",
|
||||
"cmdline": "\"{tmp_rdp_file}\"",
|
||||
"display": "微软RDP客户端(系统自带)",
|
||||
"name": "mstsc"
|
||||
},
|
||||
{
|
||||
"app": "{assist_tools_path}\\tprdp\\wfreerdp.exe",
|
||||
"cmdline": "/v:{host_ip}:{host_port} /u:{user_name} /t:\"TP#{real_ip}\"",
|
||||
"display": "FreeRDP(内置)",
|
||||
"name": "freerdp"
|
||||
}
|
||||
],
|
||||
"selected": "mstsc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,718 @@
|
|||
#include "bar.h"
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include "mainwindow.h"
|
||||
|
||||
|
||||
#define FONT_SIZE_DEFAULT 12
|
||||
#define FONT_SIZE_TIME 14
|
||||
#define TEXT_COLOR QColor(255,255,255,153)
|
||||
#define SPEED_BTN_WIDTH 42
|
||||
#define CHKBOX_RIGHT_PADDING 6
|
||||
#define PADDING_TIME_PROGRESS_BAR 10
|
||||
#define SPEED_BTN_PADDING_TOP 8
|
||||
#define SPEED_BTN_PADDING_RIGHT 8
|
||||
#define SKIP_PADDING_TOP 10
|
||||
|
||||
#define BAR_ALIGN_TOP 10
|
||||
#define BAR_PADDING_TOP 18
|
||||
#define BAR_PADDING_LEFT 15
|
||||
#define BAR_PADDING_RIGHT 15
|
||||
|
||||
typedef struct RES_MAP {
|
||||
RES_ID id;
|
||||
const char* name;
|
||||
}RES_MAP;
|
||||
|
||||
static RES_MAP img_res[res__max] = {
|
||||
{res_bg_left, "bg-left"},
|
||||
{res_bg_mid, "bg-mid"},
|
||||
{res_bg_right, "bg-right"},
|
||||
{res_btn_normal_left, "btn-normal-left"},
|
||||
{res_btn_normal_mid, "btn-normal-mid"},
|
||||
{res_btn_normal_right, "btn-normal-right"},
|
||||
{res_btn_sel_left, "btn-sel-left"},
|
||||
{res_btn_sel_mid, "btn-sel-mid"},
|
||||
{res_btn_sel_right, "btn-sel-right"},
|
||||
{res_btn_hover_left, "btn-hover-left"},
|
||||
{res_btn_hover_mid, "btn-hover-mid"},
|
||||
{res_btn_hover_right, "btn-hover-right"},
|
||||
|
||||
{res_prgbarh_left, "prgbarh-left"},
|
||||
{res_prgbarh_mid, "prgbarh-mid"},
|
||||
{res_prgbar_mid, "prgbar-mid"},
|
||||
{res_prgbar_right, "prgbar-right"},
|
||||
|
||||
{res_chkbox_normal, "chkbox-normal"},
|
||||
{res_chkbox_hover, "chkbox-hover"},
|
||||
{res_chkbox_sel_normal, "chkbox-sel-normal"},
|
||||
{res_chkbox_sel_hover, "chkbox-sel-hover"},
|
||||
};
|
||||
|
||||
typedef struct SPEED_MAP {
|
||||
int id;
|
||||
const char* title;
|
||||
}SPEED_MAP;
|
||||
|
||||
static SPEED_MAP speed[speed_count] = {
|
||||
{speed_1x, "1x"},
|
||||
{speed_2x, "2x"},
|
||||
{speed_4x, "4x"},
|
||||
{speed_8x, "8x"},
|
||||
};
|
||||
|
||||
static inline int min(int a, int b){
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static inline int max(int a, int b){
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
Bar::Bar() {
|
||||
m_img_ready = false;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_str_total_time = "00:00";
|
||||
m_str_passed_time = "00:00";
|
||||
m_str_passed_time_last_draw = "--:--";
|
||||
|
||||
m_percent = 0;
|
||||
m_percent_last_draw = -1;
|
||||
|
||||
m_play_hover = false;
|
||||
m_playing = true; // false=paused
|
||||
m_speed_selected = speed_1x;
|
||||
m_speed_hover = speed_count; // speed_count=no-hover
|
||||
m_skip_selected = false;
|
||||
m_skip_hover = false;
|
||||
m_progress_hover = false;
|
||||
m_progress_pressed = false;
|
||||
|
||||
m_resume_ms = 0;
|
||||
}
|
||||
|
||||
Bar::~Bar() {
|
||||
|
||||
}
|
||||
|
||||
bool Bar::init(MainWindow* owner) {
|
||||
m_owner = owner;
|
||||
|
||||
// 加载所需的图像资源
|
||||
int i = 0;
|
||||
for(i = 0; i < res__max; ++i) {
|
||||
QString name;
|
||||
name.sprintf(":/tp-player/res/bar/%s.png", img_res[i].name);
|
||||
if(!m_res[i].load(name))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 无需合成的图像
|
||||
if(!m_img_btn_play[play_running][widget_normal].load(":/tp-player/res/bar/play-normal.png")
|
||||
|| !m_img_btn_play[play_running][widget_hover].load(":/tp-player/res/bar/play-hover.png")
|
||||
|| !m_img_btn_play[play_paused][widget_normal].load(":/tp-player/res/bar/pause-normal.png")
|
||||
|| !m_img_btn_play[play_paused][widget_hover].load(":/tp-player/res/bar/pause-hover.png")
|
||||
|| !m_img_progress_pointer[widget_normal].load(":/tp-player/res/bar/prgpt-normal.png")
|
||||
|| !m_img_progress_pointer[widget_hover].load(":/tp-player/res/bar/prgpt-hover.png")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_height = m_res[res_bg_left].height();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bar::start(uint32_t total_ms, int width) {
|
||||
bool is_first_start = (m_width == 0);
|
||||
m_width = width;
|
||||
|
||||
m_total_ms = total_ms;
|
||||
_ms_to_str(total_ms, m_str_total_time);
|
||||
|
||||
|
||||
// 首次播放时,调整位置左右居中,距窗口顶部10点处。
|
||||
if(is_first_start) {
|
||||
_init_imgages();
|
||||
QRect rc = m_owner->rect();
|
||||
m_rc = QRect(0, 0, m_width, m_height);
|
||||
m_rc.moveTo((rc.width() - m_width)/2, BAR_ALIGN_TOP);
|
||||
}
|
||||
}
|
||||
|
||||
void Bar::end() {
|
||||
if(m_played_ms != m_total_ms)
|
||||
update_passed_time(m_total_ms);
|
||||
|
||||
m_playing = false;
|
||||
m_owner->update(m_rc.left()+m_rc_btn_play.left(), m_rc.top()+m_rc_btn_play.top(), m_rc_btn_play.width(), m_rc_btn_play.height());
|
||||
}
|
||||
|
||||
void Bar::_init_imgages() {
|
||||
m_img_bg = QPixmap(m_width, m_height);
|
||||
m_img_bg.fill(Qt::transparent);//用透明色填充
|
||||
QPainter pp(&m_img_bg);
|
||||
QFont font = pp.font();
|
||||
|
||||
// 合成背景图像
|
||||
{
|
||||
pp.drawPixmap(0, 0, m_res[res_bg_left].width(), m_res[res_bg_left].height(), m_res[res_bg_left]);
|
||||
pp.drawPixmap(m_res[res_bg_left].width(), 0, m_width - m_res[res_bg_left].width() - m_res[res_bg_right].width(), m_height, m_res[res_bg_mid]);
|
||||
pp.drawPixmap(m_width-m_res[res_bg_right].width(), 0, m_res[res_bg_right].width(), m_height, m_res[res_bg_right]);
|
||||
}
|
||||
|
||||
{
|
||||
m_rc_btn_play = QRect(BAR_PADDING_LEFT, (m_height - m_img_btn_play[play_running][widget_normal].height())/2 , m_img_btn_play[play_running][widget_normal].width(), m_img_btn_play[play_running][widget_normal].height());
|
||||
}
|
||||
|
||||
// 合成速度按钮
|
||||
{
|
||||
int w = SPEED_BTN_WIDTH, h = m_res[res_btn_normal_left].height();
|
||||
QRect rc(0, 0, w, h);
|
||||
QPixmap btn[btnspd_state_count];
|
||||
|
||||
// 未选中状态
|
||||
btn[btnspd_normal] = QPixmap(w, h);
|
||||
btn[btnspd_normal].fill(Qt::transparent);//用透明色填充
|
||||
QPainter pn(&btn[btnspd_normal]);
|
||||
pn.drawPixmap(0, 0, m_res[res_btn_normal_left].width(), m_res[res_btn_normal_left].height(), m_res[res_btn_normal_left]);
|
||||
pn.drawPixmap(m_res[res_btn_normal_left].width(), 0, w - m_res[res_btn_normal_left].width() - m_res[res_btn_normal_right].width(), h, m_res[res_btn_normal_mid]);
|
||||
pn.drawPixmap(w-m_res[res_btn_normal_right].width(), 0, m_res[res_btn_normal_right].width(), h, m_res[res_btn_normal_right]);
|
||||
// 选中状态
|
||||
btn[btnspd_sel] = QPixmap(w, h);
|
||||
btn[btnspd_sel].fill(Qt::transparent);//用透明色填充
|
||||
QPainter ps(&btn[btnspd_sel]);
|
||||
ps.drawPixmap(0, 0, m_res[res_btn_sel_left].width(), m_res[res_btn_sel_left].height(), m_res[res_btn_sel_left]);
|
||||
ps.drawPixmap(m_res[res_btn_sel_left].width(), 0, w - m_res[res_btn_sel_left].width() - m_res[res_btn_sel_right].width(), h, m_res[res_btn_sel_mid]);
|
||||
ps.drawPixmap(w-m_res[res_btn_sel_right].width(), 0, m_res[res_btn_sel_right].width(), h, m_res[res_btn_sel_right]);
|
||||
// 鼠标滑过状态
|
||||
btn[btnspd_hover] = QPixmap(w, h);
|
||||
btn[btnspd_hover].fill(Qt::transparent);//用透明色填充
|
||||
QPainter ph(&btn[btnspd_hover]);
|
||||
ph.drawPixmap(0, 0, m_res[res_btn_hover_left].width(), m_res[res_btn_hover_left].height(), m_res[res_btn_hover_left]);
|
||||
ph.drawPixmap(m_res[res_btn_hover_left].width(), 0, w - m_res[res_btn_hover_left].width() - m_res[res_btn_hover_right].width(), h, m_res[res_btn_hover_mid]);
|
||||
ph.drawPixmap(w-m_res[res_btn_hover_right].width(), 0, m_res[res_btn_hover_right].width(), h, m_res[res_btn_hover_right]);
|
||||
|
||||
for(int i = 0; i < btnspd_state_count; ++i) {
|
||||
for(int j = 0; j < speed_count; ++j) {
|
||||
m_img_btn_speed[j][i] = QPixmap(w, h);
|
||||
m_img_btn_speed[j][i].fill(Qt::transparent);
|
||||
QPainter ps(&m_img_btn_speed[j][i]);
|
||||
ps.setPen(TEXT_COLOR);
|
||||
QFont font = ps.font();
|
||||
font.setFamily("consolas");
|
||||
font.setPixelSize(FONT_SIZE_DEFAULT);
|
||||
ps.setFont(font);
|
||||
ps.drawPixmap(0, 0, w, h, btn[i]);
|
||||
ps.drawText(rc, Qt::AlignCenter, speed[j].title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 合成跳过无操作选项
|
||||
{
|
||||
// 计算显示跳过无操作选项字符串的宽高
|
||||
font.setFamily("微软雅黑");
|
||||
font.setBold(false);
|
||||
font.setPixelSize(FONT_SIZE_DEFAULT);
|
||||
pp.setFont(font);
|
||||
QFontMetrics fm = pp.fontMetrics();
|
||||
|
||||
{
|
||||
int h = fm.height();
|
||||
if(h < m_res[res_chkbox_normal].height())
|
||||
h = m_res[res_chkbox_normal].height();
|
||||
m_rc_skip = QRect(0, 0, fm.width(LOCAL8BIT("无操作则跳过")) + CHKBOX_RIGHT_PADDING + m_res[res_chkbox_normal].width(), h);
|
||||
}
|
||||
|
||||
int w = m_rc_skip.width();
|
||||
int h = m_rc_skip.height();
|
||||
int chkbox_top = (m_rc_skip.height() - m_res[res_chkbox_normal].height()) / 2;
|
||||
int text_left = m_res[res_chkbox_normal].width() + CHKBOX_RIGHT_PADDING;
|
||||
int text_top = (m_rc_skip.height() - fm.height()) / 2;
|
||||
|
||||
for(int i = 0; i < chkbox_state_count; ++i) {
|
||||
for(int j = 0; j < widget_state_count; ++j) {
|
||||
m_img_skip[i][j] = QPixmap(w,h);
|
||||
m_img_skip[i][j].fill(Qt::transparent);
|
||||
QPainter ps(&m_img_skip[i][j]);
|
||||
ps.setPen(TEXT_COLOR);
|
||||
QFont font = ps.font();
|
||||
font.setFamily("微软雅黑");
|
||||
font.setPixelSize(FONT_SIZE_DEFAULT);
|
||||
ps.setFont(font);
|
||||
|
||||
QPixmap* img = nullptr;
|
||||
if(i == chkbox_normal && j == widget_normal)
|
||||
img = &m_res[res_chkbox_normal];
|
||||
else if(i == chkbox_normal && j == widget_hover)
|
||||
img = &m_res[res_chkbox_hover];
|
||||
else if(i == chkbox_selected && j == widget_normal)
|
||||
img = &m_res[res_chkbox_sel_normal];
|
||||
else if(i == chkbox_selected && j == widget_hover)
|
||||
img = &m_res[res_chkbox_sel_hover];
|
||||
|
||||
if(img == nullptr) {
|
||||
qDebug("ERROR: can not load image for check-box.");
|
||||
img = &m_res[res_chkbox_normal];
|
||||
}
|
||||
ps.drawPixmap(0, chkbox_top, img->width(), img->height(), *img);
|
||||
ps.drawText(QRect(text_left, text_top, w-text_left, h-text_top), Qt::AlignCenter, LOCAL8BIT("无操作则跳过"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 定位进度条
|
||||
{
|
||||
// 计算显示时间所需的宽高
|
||||
font.setFamily("consolas");
|
||||
font.setBold(true);
|
||||
font.setPixelSize(FONT_SIZE_TIME);
|
||||
pp.setFont(font);
|
||||
{
|
||||
QFontMetrics fm = pp.fontMetrics();
|
||||
m_rc_time_passed = QRect(0, 0, fm.width("00:00:00"), fm.height());
|
||||
m_rc_time_total = m_rc_time_passed;
|
||||
}
|
||||
|
||||
m_img_time_total = QPixmap(m_rc_time_total.width(), m_rc_time_total.height());
|
||||
m_img_time_total.fill(Qt::transparent);
|
||||
QPainter pp(&m_img_time_total);
|
||||
pp.setPen(TEXT_COLOR);
|
||||
QFont font = pp.font();
|
||||
font.setFamily("consolas");
|
||||
font.setBold(true);
|
||||
font.setPixelSize(FONT_SIZE_TIME);
|
||||
pp.setFont(font);
|
||||
pp.drawText(m_rc_time_total, Qt::AlignLeft, m_str_total_time);
|
||||
|
||||
// 定位时间字符串的位置
|
||||
m_rc_time_passed.moveTo(BAR_PADDING_LEFT+m_img_btn_play[play_running][widget_normal].width()+PADDING_TIME_PROGRESS_BAR, BAR_PADDING_TOP);
|
||||
m_rc_time_total.moveTo(m_width - BAR_PADDING_RIGHT - m_rc_time_total.width(), BAR_PADDING_TOP);
|
||||
|
||||
int prog_width = m_rc_time_total.left() - PADDING_TIME_PROGRESS_BAR - PADDING_TIME_PROGRESS_BAR - m_rc_time_passed.right();
|
||||
int prog_height = max(m_res[res_prgbarh_left].height(), m_img_progress_pointer->height());
|
||||
m_rc_progress = QRect(0, 0, prog_width, prog_height);
|
||||
m_rc_progress.moveTo(m_rc_time_passed.right() + PADDING_TIME_PROGRESS_BAR, m_rc_time_passed.top() + (m_rc_time_passed.height() - prog_height)/2);
|
||||
}
|
||||
|
||||
|
||||
// 定位速度按钮
|
||||
{
|
||||
int left = m_rc_time_passed.right() + PADDING_TIME_PROGRESS_BAR;
|
||||
int top = m_rc_time_passed.bottom() + SPEED_BTN_PADDING_TOP;
|
||||
for(int i = 0; i < speed_count; i++) {
|
||||
m_rc_btn_speed[i] = QRect(left, top, m_img_btn_speed[i][widget_normal].width(), m_img_btn_speed[i][widget_normal].height());
|
||||
left += m_img_btn_speed[i][widget_normal].width() + SPEED_BTN_PADDING_RIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
// 定位跳过选项
|
||||
{
|
||||
int left = m_rc_time_total.left() - m_rc_skip.width() - PADDING_TIME_PROGRESS_BAR;
|
||||
int top = m_rc_time_passed.bottom() + SKIP_PADDING_TOP;//m_rc_btn_speed[0].top() + (m_rc_btn_speed[0].height() - m_rc_skip.height())/2;
|
||||
m_rc_skip.moveTo(left, top);
|
||||
}
|
||||
|
||||
m_img_ready = true;
|
||||
}
|
||||
|
||||
void Bar::_ms_to_str(uint32_t ms, QString& str) {
|
||||
int h = 0, m = 0, s = 0;
|
||||
s = ms / 1000;
|
||||
if(ms % 1000 > 500)
|
||||
s += 1;
|
||||
|
||||
h = s / 3600;
|
||||
s = s % 3600;
|
||||
m = s / 60;
|
||||
s = s % 60;
|
||||
|
||||
if(h > 0)
|
||||
str.sprintf("%02d:%02d:%02d", h, m, s);
|
||||
else
|
||||
str.sprintf("%02d:%02d", m, s);
|
||||
}
|
||||
|
||||
void Bar::update_passed_time(uint32_t ms) {
|
||||
QString str_passed;
|
||||
_ms_to_str(ms, str_passed);
|
||||
|
||||
if(m_str_passed_time != str_passed)
|
||||
{
|
||||
m_str_passed_time = str_passed;
|
||||
m_owner->update(m_rc.left()+m_rc_time_passed.left(), m_rc.top()+m_rc_time_passed.top(), m_rc_time_passed.width(), m_rc_time_passed.height());
|
||||
}
|
||||
|
||||
int percent = 0;
|
||||
if(ms >= m_total_ms) {
|
||||
percent = 100;
|
||||
m_played_ms = m_total_ms;
|
||||
}
|
||||
else {
|
||||
m_played_ms = ms;
|
||||
//percent = (int)(((double)m_played_ms / (double)m_total_ms) * 100);
|
||||
percent = m_played_ms * 100 / m_total_ms;
|
||||
}
|
||||
|
||||
if(percent != m_percent) {
|
||||
m_percent = percent;
|
||||
m_owner->update(m_rc.left()+m_rc_progress.left(), m_rc.top()+m_rc_progress.top(), m_rc_progress.width(), m_rc_progress.height());
|
||||
}
|
||||
}
|
||||
|
||||
void Bar::onMouseMove(int x, int y) {
|
||||
// 映射鼠标坐标点到本浮动窗内部的相对位置
|
||||
QPoint pt(x-m_rc.left(), y-m_rc.top());
|
||||
|
||||
if(m_progress_pressed) {
|
||||
// 重新设置进度条指示器位置
|
||||
int percent = 0;
|
||||
|
||||
if(pt.x() < m_rc_progress.left()) {
|
||||
percent = 0;
|
||||
m_resume_ms = 1;
|
||||
}
|
||||
else if(pt.x() > m_rc_progress.right()) {
|
||||
percent = 100;
|
||||
m_resume_ms = m_total_ms;
|
||||
}
|
||||
else {
|
||||
percent = (pt.x() + m_img_progress_pointer[widget_normal].width()/2 - m_rc_progress.left()) * 100 / m_rc_progress.width();
|
||||
m_resume_ms = m_total_ms * percent / 100;
|
||||
}
|
||||
update_passed_time(m_resume_ms);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool play_hover = m_rc_btn_play.contains(pt);
|
||||
if(play_hover != m_play_hover) {
|
||||
m_play_hover = play_hover;
|
||||
m_owner->update(m_rc.left()+m_rc_btn_play.left(), m_rc.top()+m_rc_btn_play.top(), m_rc_btn_play.width(), m_rc_btn_play.height());
|
||||
}
|
||||
if(play_hover)
|
||||
return;
|
||||
|
||||
int speed_hover = speed_count;
|
||||
for(int i = 0; i < speed_count; ++i) {
|
||||
if(m_rc_btn_speed[i].contains(pt)) {
|
||||
speed_hover = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(m_speed_hover != speed_hover) {
|
||||
if(m_speed_hover != speed_count) {
|
||||
m_owner->update(m_rc.left()+m_rc_btn_speed[m_speed_hover].left(), m_rc.top()+m_rc_btn_speed[m_speed_hover].top(), m_rc_btn_speed[m_speed_hover].width(), m_rc_btn_speed[m_speed_hover].height());
|
||||
}
|
||||
m_speed_hover = speed_hover;
|
||||
if(m_speed_hover != speed_count) {
|
||||
m_owner->update(m_rc.left()+m_rc_btn_speed[m_speed_hover].left(), m_rc.top()+m_rc_btn_speed[m_speed_hover].top(), m_rc_btn_speed[m_speed_hover].width(), m_rc_btn_speed[m_speed_hover].height());
|
||||
}
|
||||
}
|
||||
|
||||
bool skip_hover = m_rc_skip.contains(pt);
|
||||
if(skip_hover != m_skip_hover) {
|
||||
m_skip_hover = skip_hover;
|
||||
m_owner->update(m_rc.left()+m_rc_skip.left(), m_rc.top()+m_rc_skip.top(), m_rc_skip.width(), m_rc_skip.height());
|
||||
}
|
||||
if(skip_hover)
|
||||
return;
|
||||
}
|
||||
|
||||
void Bar::onMousePress(int x, int y, Qt::MouseButton button) {
|
||||
// 我们只关心左键按下
|
||||
if(button != Qt::LeftButton)
|
||||
return;
|
||||
|
||||
// 映射鼠标坐标点到本浮动窗内部的相对位置
|
||||
QPoint pt(x-m_rc.left(), y-m_rc.top());
|
||||
|
||||
if(m_rc_btn_play.contains(pt)) {
|
||||
if(m_playing)
|
||||
m_owner->pause();
|
||||
else
|
||||
m_owner->resume(false, 0);
|
||||
|
||||
m_playing = !m_playing;
|
||||
m_owner->update(m_rc.left()+m_rc_btn_play.left(), m_rc.top()+m_rc_btn_play.top(), m_rc_btn_play.width(), m_rc_btn_play.height());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int speed_sel = speed_count;
|
||||
for(int i = 0; i < speed_count; ++i) {
|
||||
if(m_rc_btn_speed[i].contains(pt)) {
|
||||
speed_sel = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(m_speed_selected != speed_sel && speed_sel != speed_count) {
|
||||
int old_sel = m_speed_selected;
|
||||
m_speed_selected = speed_sel;
|
||||
m_owner->set_speed(get_speed());
|
||||
m_owner->update(m_rc.left()+m_rc_btn_speed[old_sel].left(), m_rc.top()+m_rc_btn_speed[old_sel].top(), m_rc_btn_speed[old_sel].width(), m_rc_btn_speed[old_sel].height());
|
||||
m_owner->update(m_rc.left()+m_rc_btn_speed[m_speed_hover].left(), m_rc.top()+m_rc_btn_speed[m_speed_hover].top(), m_rc_btn_speed[m_speed_hover].width(), m_rc_btn_speed[m_speed_hover].height());
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_rc_skip.contains(pt)) {
|
||||
m_skip_selected = !m_skip_selected;
|
||||
m_owner->set_skip(m_skip_selected);
|
||||
m_owner->update(m_rc.left()+m_rc_skip.left(), m_rc.top()+m_rc_skip.top(), m_rc_skip.width(), m_rc_skip.height());
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
if(m_rc_progress.contains(pt)) {
|
||||
m_progress_pressed = true;
|
||||
// TODO: 暂停播放,按比例计算出点击位置占整个录像时长的百分比,定位到此位置准备播放。
|
||||
// TODO: 如果点击的位置是进度条指示标志,则仅暂停播放
|
||||
m_owner->pause();
|
||||
m_playing = false;
|
||||
m_owner->update(m_rc.left()+m_rc_btn_play.left(), m_rc.top()+m_rc_btn_play.top(), m_rc_btn_play.width(), m_rc_btn_play.height());
|
||||
|
||||
int percent = 0;
|
||||
|
||||
if(pt.x() < m_rc_progress.left()) {
|
||||
percent = 0;
|
||||
m_resume_ms = 0;
|
||||
}
|
||||
else if(pt.x() > m_rc_progress.right()) {
|
||||
percent = 100;
|
||||
m_resume_ms = m_total_ms;
|
||||
}
|
||||
else {
|
||||
percent = (pt.x() + m_img_progress_pointer[widget_normal].width()/2 - m_rc_progress.left()) * 100 / m_rc_progress.width();
|
||||
m_resume_ms = m_total_ms * percent / 100;
|
||||
}
|
||||
update_passed_time(m_resume_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void Bar::onMouseRelease(int, int, Qt::MouseButton button) {
|
||||
// 我们只关心左键释放
|
||||
if(button != Qt::LeftButton)
|
||||
return;
|
||||
if(m_progress_pressed) {
|
||||
m_progress_pressed = false;
|
||||
qDebug("resume at %dms.", m_resume_ms);
|
||||
m_owner->resume(true, m_resume_ms);
|
||||
m_playing = true;
|
||||
m_owner->update(m_rc.left()+m_rc_btn_play.left(), m_rc.top()+m_rc_btn_play.top(), m_rc_btn_play.width(), m_rc_btn_play.height());
|
||||
}
|
||||
}
|
||||
|
||||
int Bar::get_speed() {
|
||||
switch (m_speed_selected) {
|
||||
case speed_1x:
|
||||
return 1;
|
||||
case speed_2x:
|
||||
return 2;
|
||||
case speed_4x:
|
||||
return 4;
|
||||
case speed_8x:
|
||||
return 8;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Bar::draw(QPainter& painter, const QRect& rc_draw){
|
||||
if(!m_width)
|
||||
return;
|
||||
if(!rc_draw.intersects(m_rc))
|
||||
return;
|
||||
|
||||
// 绘制背景
|
||||
{
|
||||
QRect rc(m_rc);
|
||||
//rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
|
||||
int from_x = max(rc_draw.left(), m_rc.left()) - m_rc.left();
|
||||
int from_y = max(rc_draw.top(), m_rc.top()) - m_rc.top();
|
||||
int w = min(m_rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(m_rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = m_rc.left() + from_x;
|
||||
int to_y = m_rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_bg, from_x, from_y, w, h);
|
||||
}
|
||||
|
||||
// 绘制播放按钮
|
||||
{
|
||||
QRect rc(m_rc_btn_play);
|
||||
rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
if(rc_draw.intersects(rc)) {
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
if(m_playing){
|
||||
if(m_play_hover)
|
||||
painter.drawPixmap(to_x, to_y, m_img_btn_play[play_paused][widget_hover], from_x, from_y, w, h);
|
||||
else
|
||||
painter.drawPixmap(to_x, to_y, m_img_btn_play[play_paused][widget_normal], from_x, from_y, w, h);
|
||||
} else {
|
||||
if(m_play_hover)
|
||||
painter.drawPixmap(to_x, to_y, m_img_btn_play[play_running][widget_hover], from_x, from_y, w, h);
|
||||
else
|
||||
painter.drawPixmap(to_x, to_y, m_img_btn_play[play_running][widget_normal], from_x, from_y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制已播放时间
|
||||
{
|
||||
QRect rc(m_rc_time_passed);
|
||||
rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
if(rc_draw.intersects(rc)) {
|
||||
if(m_str_passed_time != m_str_passed_time_last_draw) {
|
||||
m_img_time_passed = QPixmap(m_rc_time_passed.width(), m_rc_time_passed.height());
|
||||
m_img_time_passed.fill(Qt::transparent);
|
||||
QPainter pp(&m_img_time_passed);
|
||||
pp.setPen(TEXT_COLOR);
|
||||
QFont font = pp.font();
|
||||
font.setFamily("consolas");
|
||||
font.setBold(true);
|
||||
font.setPixelSize(FONT_SIZE_TIME);
|
||||
pp.setFont(font);
|
||||
pp.drawText(QRect(0,0,m_rc_time_passed.width(), m_rc_time_passed.height()), Qt::AlignRight, m_str_passed_time);
|
||||
|
||||
m_str_passed_time_last_draw = m_str_passed_time;
|
||||
}
|
||||
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_time_passed, from_x, from_y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制总时间
|
||||
{
|
||||
QRect rc(m_rc_time_total);
|
||||
rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
if(rc_draw.intersects(rc)) {
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_time_total, from_x, from_y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制进度条
|
||||
{
|
||||
QRect rc(m_rc_progress);
|
||||
rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
|
||||
if(rc_draw.intersects(rc)) {
|
||||
if(m_percent_last_draw != m_percent) {
|
||||
m_img_progress = QPixmap(m_rc_progress.width(), m_rc_progress.height());
|
||||
m_img_progress.fill(Qt::transparent);
|
||||
QPainter pp(&m_img_progress);
|
||||
|
||||
// 进度条
|
||||
int top = (rc.height() - m_res[res_prgbarh_left].height())/2;
|
||||
int passed_width = rc.width() * m_percent / 100; // 已经播放的进度条宽度
|
||||
int remain_width = rc.width() - passed_width; // 剩下未播放的进度条宽度
|
||||
|
||||
if(passed_width >= m_res[res_prgbarh_left].width())
|
||||
pp.drawPixmap(0, top , m_res[res_prgbarh_left].width(), m_res[res_prgbarh_left].height(), m_res[res_prgbarh_left]);
|
||||
if(passed_width > 0) {
|
||||
//pp.drawPixmap(m_res[res_pbh_left].width(), top, passed_width - m_res[res_pbh_left].width(), m_res[res_pbh_mid].height(), m_res[res_pbh_mid]);
|
||||
if(remain_width > m_res[res_prgbar_right].width())
|
||||
pp.drawPixmap(m_res[res_prgbarh_left].width(), top, passed_width - m_res[res_prgbarh_left].width(), m_res[res_prgbarh_mid].height(), m_res[res_prgbarh_mid]);
|
||||
else
|
||||
pp.drawPixmap(m_res[res_prgbarh_left].width(), top, passed_width - m_res[res_prgbarh_left].width() - m_res[res_prgbar_right].width(), m_res[res_prgbarh_mid].height(), m_res[res_prgbarh_mid]);
|
||||
}
|
||||
if(remain_width > 0)
|
||||
pp.drawPixmap(passed_width, top, remain_width - m_res[res_prgbar_right].width(), m_res[res_prgbar_mid].height(), m_res[res_prgbar_mid]);
|
||||
if(remain_width >= m_res[res_prgbar_right].width())
|
||||
pp.drawPixmap(rc.width() - m_res[res_prgbar_right].width(), top , m_res[res_prgbar_right].width(), m_res[res_prgbar_right].height(), m_res[res_prgbar_right]);
|
||||
|
||||
// 进度位置指示
|
||||
int left = passed_width - m_img_progress_pointer->width() / 2;
|
||||
if(left < 0)
|
||||
left = 0;
|
||||
if(left + m_img_progress_pointer->width() > rc.width())
|
||||
left = rc.width() - m_img_progress_pointer->width();
|
||||
top = (rc.height() - m_img_progress_pointer[widget_normal].height())/2;
|
||||
pp.drawPixmap(left, top , m_img_progress_pointer[widget_normal].width(), m_img_progress_pointer[widget_normal].height(), m_img_progress_pointer[widget_normal]);
|
||||
|
||||
m_percent_last_draw = m_percent;
|
||||
}
|
||||
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_progress, from_x, from_y, w, h);
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制速度按钮
|
||||
{
|
||||
for(int i = 0; i < speed_count; i++) {
|
||||
QRect rc(m_rc_btn_speed[i]);
|
||||
rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
if(rc_draw.intersects(rc)) {
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
|
||||
if(m_speed_hover == i)
|
||||
painter.drawPixmap(to_x, to_y, m_img_btn_speed[i][btnspd_hover], from_x, from_y, w, h);
|
||||
else if(m_speed_selected == i)
|
||||
painter.drawPixmap(to_x, to_y, m_img_btn_speed[i][btnspd_sel], from_x, from_y, w, h);
|
||||
else
|
||||
painter.drawPixmap(to_x, to_y, m_img_btn_speed[i][btnspd_normal], from_x, from_y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制跳过选项
|
||||
{
|
||||
QRect rc(m_rc_skip);
|
||||
rc.moveTo(m_rc.left()+rc.left(), m_rc.top() + rc.top());
|
||||
|
||||
// painter.fillRect(rc, QColor(255, 255, 255));
|
||||
|
||||
if(rc_draw.intersects(rc)) {
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
//qDebug("skip (%d,%d), (%d,%d)/(%d,%d)", to_x, to_y, from_x, from_y, w, h);
|
||||
if(m_skip_selected) {
|
||||
if(m_skip_hover)
|
||||
painter.drawPixmap(to_x, to_y, m_img_skip[chkbox_selected][widget_hover], from_x, from_y, w, h);
|
||||
else
|
||||
painter.drawPixmap(to_x, to_y, m_img_skip[chkbox_selected][widget_normal], from_x, from_y, w, h);
|
||||
}
|
||||
else {
|
||||
if(m_skip_hover)
|
||||
painter.drawPixmap(to_x, to_y, m_img_skip[chkbox_normal][widget_hover], from_x, from_y, w, h);
|
||||
else
|
||||
painter.drawPixmap(to_x, to_y, m_img_skip[chkbox_normal][widget_normal], from_x, from_y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
#ifndef BAR_H
|
||||
#define BAR_H
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QWidget>
|
||||
|
||||
typedef enum {
|
||||
res_bg_left = 0, // 背景
|
||||
res_bg_mid,
|
||||
res_bg_right,
|
||||
res_btn_normal_left, // 按钮(速度选择),普通状态
|
||||
res_btn_normal_mid,
|
||||
res_btn_normal_right,
|
||||
res_btn_sel_left, // 按钮(速度选择),已选中
|
||||
res_btn_sel_mid,
|
||||
res_btn_sel_right,
|
||||
res_btn_hover_left, // 按钮(速度选择),鼠标滑过
|
||||
res_btn_hover_mid,
|
||||
res_btn_hover_right,
|
||||
|
||||
res_prgbarh_left, // 进度条(已经过)左侧
|
||||
res_prgbarh_mid, // 进度条(已经过)中间,拉伸填充
|
||||
res_prgbar_mid, // 进度条(未到达)中间,拉伸填充
|
||||
res_prgbar_right, // 进度条(未到达)右侧
|
||||
res_chkbox_normal, // 复选框
|
||||
res_chkbox_hover,
|
||||
res_chkbox_sel_normal,
|
||||
res_chkbox_sel_hover,
|
||||
|
||||
res__max
|
||||
}RES_ID;
|
||||
|
||||
//typedef enum {
|
||||
// widget_normal = 0,
|
||||
// widget_hover,
|
||||
// widget__max
|
||||
//}WIDGET_STAT;
|
||||
|
||||
#define widget_normal 0
|
||||
#define widget_hover 1
|
||||
#define widget_state_count 2
|
||||
|
||||
//typedef enum {
|
||||
// play_running = 0,
|
||||
// play_paused,
|
||||
// play__max
|
||||
//}PLAY_STAT;
|
||||
|
||||
#define play_running 0
|
||||
#define play_paused 1
|
||||
#define play_state_count 2
|
||||
|
||||
#define speed_1x 0
|
||||
#define speed_2x 1
|
||||
#define speed_4x 2
|
||||
#define speed_8x 3
|
||||
#define speed_count 4
|
||||
|
||||
#define btnspd_normal 0
|
||||
#define btnspd_sel 1
|
||||
#define btnspd_hover 2
|
||||
#define btnspd_state_count 3
|
||||
|
||||
#define chkbox_normal 0
|
||||
#define chkbox_selected 1
|
||||
#define chkbox_state_count 2
|
||||
|
||||
class MainWindow;
|
||||
|
||||
class Bar {
|
||||
public:
|
||||
Bar();
|
||||
~Bar();
|
||||
|
||||
bool init(MainWindow* owner);
|
||||
void start(uint32_t total_ms, int width);
|
||||
void end();
|
||||
void draw(QPainter& painter, const QRect& rc);
|
||||
void update_passed_time(uint32_t ms);
|
||||
|
||||
int get_speed();
|
||||
|
||||
QRect rc(){return m_rc;}
|
||||
|
||||
void onMouseMove(int x, int y);
|
||||
void onMousePress(int x, int y, Qt::MouseButton button);
|
||||
void onMouseRelease(int x, int y, Qt::MouseButton button);
|
||||
|
||||
private:
|
||||
void _init_imgages();
|
||||
void _ms_to_str(uint32_t ms, QString& str);
|
||||
|
||||
private:
|
||||
MainWindow* m_owner;
|
||||
|
||||
uint32_t m_total_ms; // 录像的总时长
|
||||
uint32_t m_played_ms; // 已经播放了的时长
|
||||
int m_percent; // 已经播放了的百分比(0~100)
|
||||
int m_percent_last_draw;
|
||||
QString m_str_total_time;
|
||||
QString m_str_passed_time;
|
||||
QString m_str_passed_time_last_draw;
|
||||
|
||||
bool m_img_ready;
|
||||
|
||||
// 从资源中加载的原始图像
|
||||
QPixmap m_res[res__max];
|
||||
QPixmap m_img_progress_pointer[widget_state_count];
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
// 此浮动窗相对于父窗口的坐标和大小
|
||||
QRect m_rc;
|
||||
|
||||
// 尺寸和定位(此浮动窗内部的相对坐标)
|
||||
QRect m_rc_btn_play;
|
||||
QRect m_rc_btn_speed[speed_count];
|
||||
QRect m_rc_time_passed;
|
||||
QRect m_rc_time_total;
|
||||
QRect m_rc_progress;
|
||||
QRect m_rc_skip;
|
||||
|
||||
// 画布,最终输出的图像
|
||||
//QPixmap m_canvas;
|
||||
|
||||
// 合成的图像
|
||||
QPixmap m_img_bg;
|
||||
QPixmap m_img_btn_play[play_state_count][widget_state_count];
|
||||
QPixmap m_img_btn_speed[speed_count][btnspd_state_count];
|
||||
QPixmap m_img_progress;
|
||||
QPixmap m_img_skip[chkbox_state_count][widget_state_count];
|
||||
QPixmap m_img_time_passed;
|
||||
QPixmap m_img_time_total;
|
||||
|
||||
// 各种状态
|
||||
bool m_playing; // 0=play, 2=pause
|
||||
bool m_play_hover;
|
||||
int m_speed_selected;
|
||||
int m_speed_hover; // speed__max=no-hover
|
||||
bool m_skip_selected;
|
||||
bool m_skip_hover;
|
||||
bool m_progress_hover;
|
||||
bool m_progress_pressed;
|
||||
|
||||
uint32_t m_resume_ms; // after drag progress-pointer, resume play from here.
|
||||
};
|
||||
|
||||
#endif // BAR_H
|
|
@ -0,0 +1,120 @@
|
|||
#include "downloader.h"
|
||||
#include "record_format.h"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <qelapsedtimer.h>
|
||||
|
||||
Downloader::Downloader() : QObject () {
|
||||
m_data = nullptr;
|
||||
m_reply = nullptr;
|
||||
m_result = false;
|
||||
}
|
||||
|
||||
Downloader::~Downloader() {
|
||||
}
|
||||
|
||||
bool Downloader::request(const QString& url, const QString& sid, const QString& filename) {
|
||||
return _request(url, sid, filename, nullptr);
|
||||
}
|
||||
|
||||
bool Downloader::request(const QString& url, const QString& sid, QByteArray* data) {
|
||||
QString fname;
|
||||
return _request(url, sid, fname, data);
|
||||
}
|
||||
|
||||
bool Downloader::_request(const QString& url, const QString& sid, const QString& filename, QByteArray* data) {
|
||||
if(filename.isEmpty() && data == nullptr)
|
||||
return false;
|
||||
if(!filename.isEmpty() && data != nullptr)
|
||||
return false;
|
||||
m_data = data;
|
||||
|
||||
if(!filename.isEmpty()) {
|
||||
m_file.setFileName(filename);
|
||||
if(!m_file.open(QIODevice::WriteOnly | QFile::Truncate)){
|
||||
qDebug("open file for write failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QString cookie = QString("_sid=%1\r\n").arg(sid);
|
||||
|
||||
QNetworkRequest req;
|
||||
req.setUrl(QUrl(url));
|
||||
req.setRawHeader("Cookie", cookie.toLatin1());
|
||||
|
||||
QNetworkAccessManager* nam = new QNetworkAccessManager();
|
||||
QEventLoop eloop;
|
||||
m_reply = nam->get(req);
|
||||
|
||||
connect(m_reply, &QNetworkReply::finished, &eloop, &QEventLoop::quit);
|
||||
connect(m_reply, &QNetworkReply::finished, this, &Downloader::_on_finished);
|
||||
connect(m_reply, &QIODevice::readyRead, this, &Downloader::_on_data_ready);
|
||||
|
||||
// qDebug("before eventLoop.exec(%p)", &eloop);
|
||||
eloop.exec();
|
||||
// qDebug("after eventLoop.exec()");
|
||||
|
||||
disconnect(m_reply, &QNetworkReply::finished, &eloop, &QEventLoop::quit);
|
||||
disconnect(m_reply, &QNetworkReply::finished, this, &Downloader::_on_finished);
|
||||
disconnect(m_reply, &QIODevice::readyRead, this, &Downloader::_on_data_ready);
|
||||
|
||||
delete m_reply;
|
||||
m_reply = nullptr;
|
||||
delete nam;
|
||||
|
||||
qDebug("Downloader::_request() end.");
|
||||
return m_result;
|
||||
}
|
||||
|
||||
void Downloader::_on_data_ready() {
|
||||
// qDebug("Downloader::_on_data_ready(%p).", this);
|
||||
QNetworkReply *reply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
|
||||
if(m_data != nullptr) {
|
||||
m_data->push_back(reply->readAll());
|
||||
}
|
||||
else {
|
||||
m_file.write(reply->readAll());
|
||||
}
|
||||
}
|
||||
|
||||
void Downloader::abort() {
|
||||
if(m_reply) {
|
||||
qDebug("Downloader::abort().");
|
||||
m_reply->abort();
|
||||
}
|
||||
}
|
||||
|
||||
void Downloader::_on_finished() {
|
||||
// qDebug("Downloader::_on_finished(%p).", this);
|
||||
QNetworkReply *reply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
|
||||
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
// reply->abort() got "Operation canceled"
|
||||
//QString strError = reply->errorString();
|
||||
qDebug() << "ERROR:" << reply->errorString();
|
||||
if(m_data == nullptr) {
|
||||
m_file.flush();
|
||||
m_file.close();
|
||||
}
|
||||
m_result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_data != nullptr) {
|
||||
m_data->push_back(reply->readAll());
|
||||
}
|
||||
else {
|
||||
m_file.write(reply->readAll());
|
||||
m_file.flush();
|
||||
m_file.close();
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
|
||||
m_result = true;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef DOWNLOADER_H
|
||||
#define DOWNLOADER_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class Downloader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// 从url下载数据,写入到filename文件中,或放入data中。
|
||||
Downloader();
|
||||
~Downloader();
|
||||
|
||||
bool request(const QString& url, const QString& sid, const QString& filename);
|
||||
bool request(const QString& url, const QString& sid, QByteArray* data);
|
||||
void abort();
|
||||
|
||||
private:
|
||||
bool _request(const QString& url, const QString& sid, const QString& filename, QByteArray* data);
|
||||
|
||||
private slots:
|
||||
void _on_data_ready(); // 有数据可读了,读取并写入文件
|
||||
void _on_finished(); // 下载结束了
|
||||
|
||||
private:
|
||||
QFile m_file;
|
||||
QByteArray* m_data;
|
||||
|
||||
bool m_result;
|
||||
QNetworkReply* m_reply;
|
||||
};
|
||||
|
||||
typedef struct DownloadParam {
|
||||
QString url;
|
||||
QString sid;
|
||||
QString fname;
|
||||
}DownloadParam;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QTextCodec>
|
||||
|
||||
// 编译出来的可执行程序复制到单独目录,然后执行 windeployqt 应用程序文件名
|
||||
// 即可自动将依赖的动态库等复制到此目录中。有些文件是多余的,可以酌情删除。
|
||||
|
||||
// 命令行参数格式:
|
||||
// ## 本地文件或目录
|
||||
// tp-player.exe path/of/tp-rdp.tpr 一个 .tpr 文件的文件名
|
||||
// tp-player.exe path/contains/tp-rdp.tpr 包含 .tpr 文件的路径
|
||||
//
|
||||
// ## 从TP服务器上下载
|
||||
// tp-player.exe http://teleport.domain.com:7190/{sub/path/}tp_1491560510_ca67fceb75a78c9d/1234 (注意,并不直接访问此URI,实际上其并不存在)
|
||||
// TP服务器地址(可能包含子路径,例如上例中的{sub/path}部分)/session-id(用于判断当前授权用户)/录像会话编号
|
||||
// 按 “/” 进行分割后,去掉最后两个项,剩下部分是TP服务器的WEB地址,用于合成后续的文件下载URL。
|
||||
// 根据下载的.tpr文件内容,本地合成类似于 "000000256-admin-administrator-123.45.77.88-20191109-020047" 的路径来存放下载的文件
|
||||
// 特别注意,如果账号是 domain\user 这种形式,需要将 "\" 替换为下划线,否则此符号作为路径分隔符,会导致路径不存在而无法保存下载的文件。
|
||||
// - 获取文件大小: http://127.0.0.1:7190/audit/get-file?act=size&type=rdp&rid=yyyyy&f=file-name
|
||||
// - 'act'为`size`表示获取文件大小(返回一个数字字符串,就是指定的文件大小)
|
||||
// - 'type'可以是`rdp`或`ssh`,目前仅用了`rdp`
|
||||
// - 'rid'是录像会话编号(在服务端,一个会话的录像文件均放在录像会话编号命名的目录下)
|
||||
// - 'f' 是文件名,即会话编号目录下的指定文件,例如 'tp-rdp.tpr'
|
||||
// - 读取文件内容: http://127.0.0.1:7190/audit/get-file?act=read&type=rdp&rid=yyyyy&f=file-name&offset=1234&length=1024
|
||||
// - 'act'为`read`表示获取文件内容
|
||||
// - 'offset'表示要读取的偏移,如果未指定,则表示从文件起始处开始读取,即默认为 offset=0
|
||||
// - 'length'表示要读取的大小,如果未指定,表示读取整个文件,即默认为 length=-1(服务端对length=-1做完全读取处理)
|
||||
// - 搭配使用 offst 和 length 可以做到分块下载、断点续传。
|
||||
|
||||
|
||||
void show_usage(QCommandLineParser& parser) {
|
||||
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
|
||||
"<html><head/><body><pre>"
|
||||
+ parser.helpText()
|
||||
+ "\n\n"
|
||||
+ "RESOURCE could be:\n"
|
||||
+ " - teleport record file (.tpr).\n"
|
||||
+ " - a directory contains .tpr file.\n"
|
||||
+ " - an URL to download teleport record file."
|
||||
+ "</pre></body></html>");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
//#endif
|
||||
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
//#ifdef __APPLE__
|
||||
// QString data_path_base = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
// data_path_base += "/tp-testdata/";
|
||||
//#else
|
||||
// QString data_path_base = QCoreApplication::applicationDirPath() + "/record";
|
||||
//#endif
|
||||
// qDebug("data-path-base: %s", data_path_base.toStdString().c_str());
|
||||
// return 0;
|
||||
|
||||
QGuiApplication::setApplicationDisplayName(LOCAL8BIT("[Teleport播放器]"));
|
||||
|
||||
QCommandLineParser parser;
|
||||
const QCommandLineOption opt_help = parser.addHelpOption();
|
||||
|
||||
parser.addPositionalArgument("RESOURCE", "teleport record resource to be play.");
|
||||
|
||||
if(!parser.parse(QCoreApplication::arguments())) {
|
||||
QMessageBox::warning(nullptr, QGuiApplication::applicationDisplayName(),
|
||||
//"<html><head/><body><h2 style=\"color:#ff0000;\">" + parser.errorText() + "</h2><pre>"
|
||||
"<html><head/><body><h2>" + parser.errorText() + "</h2><pre>"
|
||||
+ parser.helpText() + "</pre></body></html>");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(parser.isSet(opt_help)) {
|
||||
show_usage(parser);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if(0 == args.size()) {
|
||||
show_usage(parser);
|
||||
return 2;
|
||||
}
|
||||
|
||||
QString resource = args.at(0);
|
||||
qDebug() << resource;
|
||||
|
||||
|
||||
MainWindow w;
|
||||
w.set_resource(resource);
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
|
@ -0,0 +1,433 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <QMatrix>
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QDesktopWidget>
|
||||
#include <QPaintEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
static inline int min(int a, int b){
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static inline int max(int a, int b){
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
m_show_default = true;
|
||||
m_bar_shown = false;
|
||||
m_bar_fade_in = false;
|
||||
m_bar_fading = false;
|
||||
m_bar_opacity = 1.0;
|
||||
m_show_message = false;
|
||||
memset(&m_pt, 0, sizeof(TS_RECORD_RDP_POINTER));
|
||||
|
||||
m_thr_play = nullptr;
|
||||
m_play_state = PLAY_STATE_UNKNOWN;
|
||||
m_thr_data = nullptr;
|
||||
|
||||
m_disable_draw = false;
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->centralWidget->setMouseTracking(true);
|
||||
setMouseTracking(true);
|
||||
|
||||
// frame-less window.
|
||||
//#ifdef __APPLE__
|
||||
// setWindowFlags(Qt::FramelessWindowHint | Qt::MSWindowsFixedSizeDialogHint | Qt::Window);
|
||||
// OSXCode::fixWin(winId());
|
||||
//#else
|
||||
// setWindowFlags(Qt::FramelessWindowHint | Qt::MSWindowsFixedSizeDialogHint | windowFlags());
|
||||
//#endif //__APPLE__
|
||||
|
||||
m_pt_normal.load(":/tp-player/res/cursor.png");
|
||||
m_default_bg.load(":/tp-player/res/bg.png");
|
||||
|
||||
m_canvas = QPixmap(m_default_bg.width(), m_default_bg.height());
|
||||
QPainter pp(&m_canvas);
|
||||
pp.drawPixmap(0, 0, m_default_bg, 0, 0, m_default_bg.width(), m_default_bg.height());
|
||||
|
||||
|
||||
setWindowFlags(windowFlags()&~Qt::WindowMaximizeButtonHint); // 禁止最大化按钮
|
||||
setFixedSize(m_default_bg.width(), m_default_bg.height()); // 禁止拖动窗口大小
|
||||
|
||||
if(!m_bar.init(this)) {
|
||||
qDebug("bar init failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
connect(&m_timer_first_run, SIGNAL(timeout()), this, SLOT(_do_first_run()));
|
||||
connect(&m_timer_bar_fade, SIGNAL(timeout()), this, SLOT(_do_bar_fade()));
|
||||
connect(&m_timer_bar_delay_hide, SIGNAL(timeout()), this, SLOT(_do_bar_delay_hide()));
|
||||
|
||||
m_timer_first_run.setSingleShot(true);
|
||||
m_timer_first_run.start(500);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
if(m_thr_play) {
|
||||
m_thr_play->stop();
|
||||
|
||||
disconnect(m_thr_play, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
|
||||
delete m_thr_play;
|
||||
m_thr_play = nullptr;
|
||||
}
|
||||
|
||||
if(m_thr_data) {
|
||||
m_thr_data->stop();
|
||||
disconnect(m_thr_data, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
delete m_thr_data;
|
||||
m_thr_data = nullptr;
|
||||
}
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::set_resource(const QString &res) {
|
||||
m_res = res;
|
||||
}
|
||||
|
||||
void MainWindow::_do_first_run() {
|
||||
m_thr_data = new ThrData(this, m_res);
|
||||
connect(m_thr_data, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
m_thr_data->start(QThread::TimeCriticalPriority);
|
||||
|
||||
m_thr_play = new ThrPlay(this);
|
||||
connect(m_thr_play, SIGNAL(signal_update_data(UpdateData*)), this, SLOT(_do_update_data(UpdateData*)));
|
||||
|
||||
m_thr_play->speed(m_bar.get_speed());
|
||||
m_thr_play->start();
|
||||
}
|
||||
|
||||
void MainWindow::set_speed(int s) {
|
||||
if(m_thr_play)
|
||||
m_thr_play->speed(s);
|
||||
}
|
||||
|
||||
void MainWindow::set_skip(bool s) {
|
||||
if(m_thr_play)
|
||||
m_thr_play->skip(s);
|
||||
}
|
||||
|
||||
void MainWindow::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QPainter painter(this);
|
||||
|
||||
if(m_show_default) {
|
||||
painter.drawPixmap(e->rect(), m_default_bg, e->rect());
|
||||
}
|
||||
else {
|
||||
painter.drawPixmap(e->rect(), m_canvas, e->rect());
|
||||
|
||||
QRect rcpt(m_pt_normal.rect());
|
||||
rcpt.moveTo(m_pt.x - m_pt_normal.width()/2, m_pt.y-m_pt_normal.height()/2);
|
||||
if(e->rect().intersects(rcpt)) {
|
||||
painter.drawPixmap(m_pt.x-m_pt_normal.width()/2, m_pt.y-m_pt_normal.height()/2, m_pt_normal);
|
||||
}
|
||||
|
||||
// 绘制浮动控制窗
|
||||
if(m_bar_fading) {
|
||||
painter.setOpacity(m_bar_opacity);
|
||||
m_bar.draw(painter, e->rect());
|
||||
}
|
||||
else if(m_bar_shown) {
|
||||
m_bar.draw(painter, e->rect());
|
||||
}
|
||||
}
|
||||
|
||||
if(m_show_message) {
|
||||
QRect rc_draw = e->rect();
|
||||
QRect rc(m_rc_message);
|
||||
|
||||
if(e->rect().intersects(rc)) {
|
||||
int from_x = max(rc_draw.left(), rc.left()) - rc.left();
|
||||
int from_y = max(rc_draw.top(), rc.top()) - rc.top();
|
||||
int w = min(rc.right(), rc_draw.right()) - rc.left() - from_x + 1;
|
||||
int h = min(rc.bottom(), rc_draw.bottom()) - rc.top() - from_y + 1;
|
||||
int to_x = rc.left() + from_x;
|
||||
int to_y = rc.top() + from_y;
|
||||
painter.drawPixmap(to_x, to_y, m_img_message, from_x, from_y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::pause() {
|
||||
if(m_play_state != PLAY_STATE_RUNNING)
|
||||
return;
|
||||
m_thr_play->pause();
|
||||
m_play_state = PLAY_STATE_PAUSE;
|
||||
}
|
||||
|
||||
void MainWindow::resume(bool relocate, uint32_t ms) {
|
||||
if(m_play_state == PLAY_STATE_PAUSE) {
|
||||
if(relocate)
|
||||
m_thr_data->restart(ms);
|
||||
m_thr_play->resume(relocate, ms);
|
||||
}
|
||||
else if(m_play_state == PLAY_STATE_STOP) {
|
||||
m_thr_data->restart(ms);
|
||||
m_thr_play->resume(true, ms);
|
||||
}
|
||||
|
||||
m_play_state = PLAY_STATE_RUNNING;
|
||||
}
|
||||
|
||||
void MainWindow::_do_update_data(UpdateData* dat) {
|
||||
if(!dat)
|
||||
return;
|
||||
|
||||
UpdateDataHelper data_helper(dat);
|
||||
|
||||
if(dat->data_type() == TYPE_POINTER) {
|
||||
TS_RECORD_RDP_POINTER pt;
|
||||
memcpy(&pt, &m_pt, sizeof(TS_RECORD_RDP_POINTER));
|
||||
|
||||
// 更新虚拟鼠标信息,这样下一次绘制界面时就会在新的位置绘制出虚拟鼠标
|
||||
memcpy(&m_pt, dat->get_pointer(), sizeof(TS_RECORD_RDP_POINTER));
|
||||
update(m_pt.x - m_pt_normal.width()/2, m_pt.y - m_pt_normal.width()/2, m_pt_normal.width(), m_pt_normal.height());
|
||||
|
||||
update(pt.x - m_pt_normal.width()/2, pt.y - m_pt_normal.width()/2, m_pt_normal.width(), m_pt_normal.height());
|
||||
|
||||
return;
|
||||
}
|
||||
else if(dat->data_type() == TYPE_IMAGE) {
|
||||
const UpdateImages uimgs = dat->get_images();
|
||||
if(uimgs.size() == 0)
|
||||
return;
|
||||
|
||||
if(uimgs.size() > 1 && !m_disable_draw) {
|
||||
// 禁止界面更新
|
||||
setUpdatesEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
QPainter pp(&m_canvas);
|
||||
for(int i = 0; i < uimgs.size(); ++i) {
|
||||
pp.drawImage(uimgs[i].x, uimgs[i].y, *(uimgs[i].img), 0, 0, uimgs[i].w, uimgs[i].h, Qt::AutoColor);
|
||||
|
||||
if(!m_disable_draw)
|
||||
update(uimgs[i].x, uimgs[i].y, uimgs[i].w, uimgs[i].h);
|
||||
}
|
||||
|
||||
|
||||
if(uimgs.size() > 1 && !m_disable_draw) {
|
||||
// 允许界面更新
|
||||
setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if(dat->data_type() == TYPE_PLAYED_MS) {
|
||||
m_bar.update_passed_time(dat->played_ms());
|
||||
return;
|
||||
}
|
||||
|
||||
else if(dat->data_type() == TYPE_DISABLE_DRAW) {
|
||||
// 禁止界面更新
|
||||
m_disable_draw = true;
|
||||
setUpdatesEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
else if(dat->data_type() == TYPE_ENABLE_DRAW) {
|
||||
// 允许界面更新
|
||||
m_disable_draw = false;
|
||||
setUpdatesEnabled(true);
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
else if(dat->data_type() == TYPE_MESSAGE) {
|
||||
if(dat->message().isEmpty()) {
|
||||
m_show_message = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_show_message = true;
|
||||
|
||||
qDebug("1message, w=%d, h=%d", m_canvas.width(), m_canvas.height());
|
||||
|
||||
QPainter pp(&m_canvas);
|
||||
QRect rcWin(0, 0, m_canvas.width(), m_canvas.height());
|
||||
pp.drawText(rcWin, Qt::AlignLeft|Qt::TextDontPrint, dat->message(), &m_rc_message);
|
||||
|
||||
qDebug("2message, w=%d, h=%d", m_rc_message.width(), m_rc_message.height());
|
||||
m_rc_message.setWidth(m_rc_message.width()+60);
|
||||
m_rc_message.setHeight(m_rc_message.height()+60);
|
||||
|
||||
m_img_message = QPixmap(m_rc_message.width(), m_rc_message.height());
|
||||
m_img_message.fill(Qt::transparent);
|
||||
QPainter pm(&m_img_message);
|
||||
pm.setPen(QColor(255,255,255,153));
|
||||
pm.fillRect(m_rc_message, QColor(0,0,0,190));
|
||||
|
||||
QRect rcRect(m_rc_message);
|
||||
rcRect.setWidth(rcRect.width()-1);
|
||||
rcRect.setHeight(rcRect.height()-1);
|
||||
pm.drawRect(rcRect);
|
||||
|
||||
QRect rcText(m_rc_message);
|
||||
rcText.setLeft(30);
|
||||
rcText.setTop(30);
|
||||
pm.drawText(rcText, Qt::AlignLeft, dat->message());
|
||||
m_rc_message.moveTo(
|
||||
(m_canvas.width() - m_rc_message.width())/2,
|
||||
(m_canvas.height() - m_rc_message.height())/3
|
||||
);
|
||||
|
||||
update(m_rc_message.x(), m_rc_message.y(), m_rc_message.width(), m_rc_message.height());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else if(dat->data_type() == TYPE_ERROR) {
|
||||
QMessageBox::critical(this, QGuiApplication::applicationDisplayName(), dat->message());
|
||||
QApplication::instance()->exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// 这是播放开始时收到的第一个数据包
|
||||
else if(dat->data_type() == TYPE_HEADER_INFO) {
|
||||
TS_RECORD_HEADER* hdr = dat->get_header();
|
||||
if(hdr == nullptr)
|
||||
return;
|
||||
memcpy(&m_rec_hdr, hdr, sizeof(TS_RECORD_HEADER));
|
||||
|
||||
qDebug() << "resize (" << m_rec_hdr.basic.width << "," << m_rec_hdr.basic.height << ")";
|
||||
|
||||
m_canvas = QPixmap(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||
|
||||
QDesktopWidget *desktop = QApplication::desktop(); // =qApp->desktop();也可以
|
||||
qDebug("desktop w:%d,h:%d, this w:%d,h:%d", desktop->width(), desktop->height(), width(), height());
|
||||
move(10, (desktop->height() - m_rec_hdr.basic.height)/2);
|
||||
|
||||
setFixedSize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||
|
||||
m_canvas.fill(QColor(38, 73, 111));
|
||||
|
||||
m_show_default = false;
|
||||
repaint();
|
||||
|
||||
m_bar.start(m_rec_hdr.info.time_ms, 640);
|
||||
m_bar_shown = true;
|
||||
m_play_state = PLAY_STATE_RUNNING;
|
||||
|
||||
update(m_bar.rc());
|
||||
|
||||
m_bar_fade_in = false;
|
||||
m_bar_fading = true;
|
||||
m_timer_bar_delay_hide.start(2000);
|
||||
|
||||
QString title;
|
||||
if (m_rec_hdr.basic.conn_port == 3389) {
|
||||
title = QString(LOCAL8BIT("用户 %1 访问 %2 的 %3 账号").arg(m_rec_hdr.basic.user_username, m_rec_hdr.basic.conn_ip, m_rec_hdr.basic.acc_username));
|
||||
}
|
||||
else {
|
||||
QString _port;
|
||||
_port.sprintf("%d", m_rec_hdr.basic.conn_port);
|
||||
title = QString(LOCAL8BIT("用户 %1 访问 %2:%3 的 %4 账号").arg(m_rec_hdr.basic.user_username, m_rec_hdr.basic.conn_ip, _port, m_rec_hdr.basic.acc_username));
|
||||
}
|
||||
|
||||
setWindowTitle(title);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
else if(dat->data_type() == TYPE_END) {
|
||||
m_bar.end();
|
||||
m_play_state = PLAY_STATE_STOP;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::_do_bar_delay_hide() {
|
||||
m_bar_fading = true;
|
||||
m_timer_bar_delay_hide.stop();
|
||||
m_timer_bar_fade.stop();
|
||||
m_timer_bar_fade.start(50);
|
||||
}
|
||||
|
||||
void MainWindow::_do_bar_fade() {
|
||||
if(m_bar_fade_in) {
|
||||
if(m_bar_opacity < 1.0)
|
||||
m_bar_opacity += 0.3;
|
||||
if(m_bar_opacity >= 1.0) {
|
||||
m_bar_opacity = 1.0;
|
||||
m_bar_shown = true;
|
||||
m_bar_fading = false;
|
||||
m_timer_bar_fade.stop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(m_bar_opacity > 0.0)
|
||||
m_bar_opacity -= 0.2;
|
||||
if(m_bar_opacity <= 0.0) {
|
||||
m_bar_opacity = 0.0;
|
||||
m_bar_shown = false;
|
||||
m_bar_fading = false;
|
||||
m_timer_bar_fade.stop();
|
||||
}
|
||||
}
|
||||
|
||||
update(m_bar.rc());
|
||||
}
|
||||
|
||||
void MainWindow::mouseMoveEvent(QMouseEvent *e) {
|
||||
if(!m_show_default) {
|
||||
QRect rc = m_bar.rc();
|
||||
if(e->y() > rc.top() - 20 && e->y() < rc.bottom() + 20) {
|
||||
if((!m_bar_shown && !m_bar_fading) || (m_bar_fading && !m_bar_fade_in)) {
|
||||
m_bar_fade_in = true;
|
||||
m_bar_fading = true;
|
||||
|
||||
m_timer_bar_delay_hide.stop();
|
||||
m_timer_bar_fade.stop();
|
||||
m_timer_bar_fade.start(50);
|
||||
}
|
||||
|
||||
if(rc.contains(e->pos()))
|
||||
m_bar.onMouseMove(e->x(), e->y());
|
||||
}
|
||||
else {
|
||||
if((m_bar_shown && !m_bar_fading) || (m_bar_fading && m_bar_fade_in)) {
|
||||
m_bar_fade_in = false;
|
||||
m_bar_fading = true;
|
||||
m_timer_bar_fade.stop();
|
||||
m_timer_bar_delay_hide.stop();
|
||||
|
||||
if(m_bar_opacity != 1.0)
|
||||
m_timer_bar_fade.start(50);
|
||||
else
|
||||
m_timer_bar_delay_hide.start(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::mousePressEvent(QMouseEvent *e) {
|
||||
if(!m_show_default) {
|
||||
QRect rc = m_bar.rc();
|
||||
if(rc.contains(e->pos())) {
|
||||
m_bar.onMousePress(e->x(), e->y(), e->button());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::mouseReleaseEvent(QMouseEvent *e) {
|
||||
m_bar.onMouseRelease(e->x(), e->y(), e->button());
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
#include "bar.h"
|
||||
#include "thr_play.h"
|
||||
#include "thr_data.h"
|
||||
#include "update_data.h"
|
||||
#include "record_format.h"
|
||||
#include "util.h"
|
||||
#include "downloader.h"
|
||||
|
||||
#define PLAY_STATE_UNKNOWN 0
|
||||
#define PLAY_STATE_RUNNING 1
|
||||
#define PLAY_STATE_PAUSE 2
|
||||
#define PLAY_STATE_STOP 3
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
void set_resource(const QString& res);
|
||||
|
||||
void pause();
|
||||
void resume(bool relocate, uint32_t ms);
|
||||
void restart();
|
||||
void set_speed(int s);
|
||||
void set_skip(bool s);
|
||||
|
||||
// TODO: 将thr_data移动到thr_play线程,由play线程进行管理
|
||||
ThrData* get_thr_data() {return m_thr_data;}
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
private slots:
|
||||
void _do_first_run(); // 默认界面加载完成后,开始播放操作(可能会进行数据下载)
|
||||
void _do_update_data(UpdateData*);
|
||||
void _do_bar_fade();
|
||||
void _do_bar_delay_hide();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
bool m_show_default;
|
||||
bool m_bar_shown;
|
||||
QPixmap m_default_bg;
|
||||
|
||||
QString m_res;
|
||||
ThrPlay* m_thr_play;
|
||||
ThrData* m_thr_data;
|
||||
|
||||
QPixmap m_canvas;
|
||||
|
||||
Bar m_bar;
|
||||
|
||||
TS_RECORD_HEADER m_rec_hdr;
|
||||
|
||||
QPixmap m_pt_normal;
|
||||
TS_RECORD_RDP_POINTER m_pt;
|
||||
|
||||
QTimer m_timer_first_run;
|
||||
QTimer m_timer_bar_fade;
|
||||
QTimer m_timer_bar_delay_hide;
|
||||
bool m_bar_fade_in;
|
||||
bool m_bar_fading;
|
||||
qreal m_bar_opacity;
|
||||
|
||||
int m_play_state;
|
||||
|
||||
bool m_show_message;
|
||||
QPixmap m_img_message;
|
||||
QRect m_rc_message;
|
||||
bool m_disable_draw;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>微软雅黑 Light</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Teleport Replayer</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget"/>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef RECORD_FORMAT_H
|
||||
#define RECORD_FORMAT_H
|
||||
|
||||
#include <Qt>
|
||||
|
||||
#define TS_TPPR_TYPE_UNKNOWN 0x0000
|
||||
#define TS_TPPR_TYPE_SSH 0x0001
|
||||
#define TS_TPPR_TYPE_RDP 0x0101
|
||||
|
||||
|
||||
#define TS_RECORD_TYPE_RDP_POINTER 0x12 // 鼠标坐标位置改变,用于绘制虚拟鼠标
|
||||
#define TS_RECORD_TYPE_RDP_IMAGE 0x13 // 服务端返回的图像,用于展示
|
||||
#define TS_RECORD_TYPE_RDP_KEYFRAME 0x14 //
|
||||
|
||||
#define TS_RDP_BTN_FREE 0
|
||||
#define TS_RDP_BTN_PRESSED 1
|
||||
#define TS_RDP_IMG_RAW 0 // 未压缩,原始数据(根据bitsPerPixel,多个字节对应一个点的颜色)
|
||||
#define TS_RDP_IMG_BMP 1 // 压缩的BMP数据
|
||||
#define TS_RDP_IMG_ALT 2
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
// 录像文件头(随着录像数据写入,会改变的部分)
|
||||
typedef struct TS_RECORD_HEADER_INFO {
|
||||
uint32_t magic; // "TPPR" 标志 TelePort Protocol Record
|
||||
uint16_t ver; // 录像文件版本,从3.5.0开始,为4
|
||||
uint16_t type; //
|
||||
// uint32_t packages; // 总包数
|
||||
uint32_t time_ms; // 总耗时(毫秒)
|
||||
uint32_t dat_file_count; // 数据文件数量
|
||||
}TS_RECORD_HEADER_INFO;
|
||||
#define ts_record_header_info_size sizeof(TS_RECORD_HEADER_INFO)
|
||||
|
||||
// 录像文件头(固定不变部分)
|
||||
typedef struct TS_RECORD_HEADER_BASIC {
|
||||
uint16_t protocol_type; // 协议:1=RDP, 2=SSH, 3=Telnet
|
||||
uint16_t protocol_sub_type; // 子协议:100=RDP-DESKTOP, 200=SSH-SHELL, 201=SSH-SFTP, 300=Telnet
|
||||
uint64_t timestamp; // 本次录像的起始时间(UTC时间戳)
|
||||
uint16_t width; // 初始屏幕尺寸:宽
|
||||
uint16_t height; // 初始屏幕尺寸:高
|
||||
char user_username[64]; // teleport账号
|
||||
char acc_username[64]; // 远程主机用户名
|
||||
|
||||
char host_ip[40]; // 远程主机IP
|
||||
char conn_ip[40]; // 远程主机IP
|
||||
uint16_t conn_port; // 远程主机端口
|
||||
|
||||
char client_ip[40]; // 客户端IP
|
||||
|
||||
// // RDP专有
|
||||
// uint8_t rdp_security; // 0 = RDP, 1 = TLS
|
||||
}TS_RECORD_HEADER_BASIC;
|
||||
#define ts_record_header_basic_size sizeof(TS_RECORD_HEADER_BASIC)
|
||||
|
||||
typedef struct TS_RECORD_HEADER {
|
||||
TS_RECORD_HEADER_INFO info;
|
||||
uint8_t _reserve1[64 - ts_record_header_info_size];
|
||||
TS_RECORD_HEADER_BASIC basic;
|
||||
uint8_t _reserve2[512 - 64 - ts_record_header_basic_size];
|
||||
}TS_RECORD_HEADER;
|
||||
|
||||
// header部分(header-info + header-basic) = 512B
|
||||
#define ts_record_header_size sizeof(TS_RECORD_HEADER)
|
||||
|
||||
// 一个数据包的头
|
||||
typedef struct TS_RECORD_PKG {
|
||||
uint8_t type; // 包的数据类型
|
||||
uint32_t size; // 这个包的总大小(不含包头)
|
||||
uint32_t time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||
uint8_t _reserve[3]; // 保留
|
||||
}TS_RECORD_PKG;
|
||||
|
||||
|
||||
typedef struct TS_RECORD_RDP_POINTER {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint8_t button;
|
||||
uint8_t pressed;
|
||||
}TS_RECORD_RDP_POINTER;
|
||||
|
||||
// RDP图像更新
|
||||
typedef struct TS_RECORD_RDP_IMAGE_INFO {
|
||||
uint16_t destLeft;
|
||||
uint16_t destTop;
|
||||
uint16_t destRight;
|
||||
uint16_t destBottom;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint16_t bitsPerPixel;
|
||||
uint8_t format;
|
||||
uint8_t _reserved;
|
||||
uint32_t dat_len;
|
||||
uint32_t zip_len;
|
||||
}TS_RECORD_RDP_IMAGE_INFO;
|
||||
|
||||
// 关键帧索引
|
||||
typedef struct TS_RECORD_RDP_KEYFRAME_INFO {
|
||||
uint32_t time_ms; // 此关键帧的时间点
|
||||
uint32_t file_index; // 此关键帧图像数据位于哪一个数据文件中
|
||||
uint32_t offset; // 此关键帧图像数据在数据文件中的偏移
|
||||
}TS_RECORD_RDP_KEYFRAME_INFO;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#endif // RECORD_FORMAT_H
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1016 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1016 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1008 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1016 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1003 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1004 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,974 @@
|
|||
/* -*- c-basic-offset: 8 -*-
|
||||
rdesktop: A Remote Desktop Protocol client.
|
||||
Bitmap decompression routines
|
||||
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* three seperate function for speed when decompressing the bitmaps
|
||||
when modifing one function make the change in the others
|
||||
jay.sorg@gmail.com */
|
||||
|
||||
/* indent is confused by this file */
|
||||
/* *INDENT-OFF* */
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "rle.h"
|
||||
|
||||
/* Specific rename for RDPY integration */
|
||||
#define unimpl(str, code)
|
||||
|
||||
//#define RD_BOOL int
|
||||
//#define False 0
|
||||
//#define True 1
|
||||
/* end specific rename */
|
||||
|
||||
#define CVAL(p) (*(p++))
|
||||
//#ifdef NEED_ALIGN
|
||||
//#ifdef L_ENDIAN
|
||||
#define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
|
||||
//#else
|
||||
//#define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
|
||||
//#endif /* L_ENDIAN */
|
||||
//#else
|
||||
//#define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
|
||||
//#endif /* NEED_ALIGN */
|
||||
|
||||
#define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
|
||||
|
||||
#define REPEAT(statement) \
|
||||
{ \
|
||||
while((count & ~0x7) && ((x+8) < width)) \
|
||||
UNROLL8( statement; count--; x++; ); \
|
||||
\
|
||||
while((count > 0) && (x < width)) \
|
||||
{ \
|
||||
statement; \
|
||||
count--; \
|
||||
x++; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MASK_UPDATE() \
|
||||
{ \
|
||||
mixmask <<= 1; \
|
||||
if (mixmask == 0) \
|
||||
{ \
|
||||
mask = fom_mask ? fom_mask : CVAL(input); \
|
||||
mixmask = 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* 1 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress1(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
const uint8 *end = input + size;
|
||||
uint8 *prevline = NULL, *line = NULL;
|
||||
int opcode, count, offset, isfillormix, x = width;
|
||||
int lastopcode = -1, insertmix = False, bicolour = False;
|
||||
uint8 code;
|
||||
uint8 colour1 = 0, colour2 = 0;
|
||||
uint8 mixmask, mask = 0;
|
||||
uint8 mix = 0xff;
|
||||
int fom_mask = 0;
|
||||
|
||||
while (input < end)
|
||||
{
|
||||
fom_mask = 0;
|
||||
code = CVAL(input);
|
||||
opcode = code >> 4;
|
||||
/* Handle different opcode forms */
|
||||
switch (opcode)
|
||||
{
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
opcode -= 6;
|
||||
count = code & 0xf;
|
||||
offset = 16;
|
||||
break;
|
||||
case 0xf:
|
||||
opcode = code & 0xf;
|
||||
if (opcode < 9)
|
||||
{
|
||||
count = CVAL(input);
|
||||
count |= CVAL(input) << 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (opcode < 0xb) ? 8 : 1;
|
||||
}
|
||||
offset = 0;
|
||||
break;
|
||||
default:
|
||||
opcode >>= 1;
|
||||
count = code & 0x1f;
|
||||
offset = 32;
|
||||
break;
|
||||
}
|
||||
/* Handle strange cases for counts */
|
||||
if (offset != 0)
|
||||
{
|
||||
isfillormix = ((opcode == 2) || (opcode == 7));
|
||||
if (count == 0)
|
||||
{
|
||||
if (isfillormix)
|
||||
count = CVAL(input) + 1;
|
||||
else
|
||||
count = CVAL(input) + offset;
|
||||
}
|
||||
else if (isfillormix)
|
||||
{
|
||||
count <<= 3;
|
||||
}
|
||||
}
|
||||
/* Read preliminary data */
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: /* Fill */
|
||||
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
||||
insertmix = True;
|
||||
break;
|
||||
case 8: /* Bicolour */
|
||||
colour1 = CVAL(input);
|
||||
case 3: /* Colour */
|
||||
colour2 = CVAL(input);
|
||||
break;
|
||||
case 6: /* SetMix/Mix */
|
||||
case 7: /* SetMix/FillOrMix */
|
||||
mix = CVAL(input);
|
||||
opcode -= 5;
|
||||
break;
|
||||
case 9: /* FillOrMix_1 */
|
||||
mask = 0x03;
|
||||
opcode = 0x02;
|
||||
fom_mask = 3;
|
||||
break;
|
||||
case 0x0a: /* FillOrMix_2 */
|
||||
mask = 0x05;
|
||||
opcode = 0x02;
|
||||
fom_mask = 5;
|
||||
break;
|
||||
}
|
||||
lastopcode = opcode;
|
||||
mixmask = 0;
|
||||
/* Output body */
|
||||
while (count > 0)
|
||||
{
|
||||
if (x >= width)
|
||||
{
|
||||
if (height <= 0)
|
||||
return False;
|
||||
x = 0;
|
||||
height--;
|
||||
prevline = line;
|
||||
line = output + height * width;
|
||||
}
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: /* Fill */
|
||||
if (insertmix)
|
||||
{
|
||||
if (prevline == NULL)
|
||||
line[x] = mix;
|
||||
else
|
||||
line[x] = prevline[x] ^ mix;
|
||||
insertmix = False;
|
||||
count--;
|
||||
x++;
|
||||
}
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT(line[x] = 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT(line[x] = prevline[x])
|
||||
}
|
||||
break;
|
||||
case 1: /* Mix */
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT(line[x] = mix)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT(line[x] = prevline[x] ^ mix)
|
||||
}
|
||||
break;
|
||||
case 2: /* Fill or Mix */
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
MASK_UPDATE();
|
||||
if (mask & mixmask)
|
||||
line[x] = mix;
|
||||
else
|
||||
line[x] = 0;
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
MASK_UPDATE();
|
||||
if (mask & mixmask)
|
||||
line[x] = prevline[x] ^ mix;
|
||||
else
|
||||
line[x] = prevline[x];
|
||||
)
|
||||
}
|
||||
break;
|
||||
case 3: /* Colour */
|
||||
REPEAT(line[x] = colour2)
|
||||
break;
|
||||
case 4: /* Copy */
|
||||
REPEAT(line[x] = CVAL(input))
|
||||
break;
|
||||
case 8: /* Bicolour */
|
||||
REPEAT
|
||||
(
|
||||
if (bicolour)
|
||||
{
|
||||
line[x] = colour2;
|
||||
bicolour = False;
|
||||
}
|
||||
else
|
||||
{
|
||||
line[x] = colour1;
|
||||
bicolour = True; count++;
|
||||
}
|
||||
)
|
||||
break;
|
||||
case 0xd: /* White */
|
||||
REPEAT(line[x] = 0xff)
|
||||
break;
|
||||
case 0xe: /* Black */
|
||||
REPEAT(line[x] = 0)
|
||||
break;
|
||||
default:
|
||||
unimpl("bitmap opcode 0x%x\n", opcode);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/* 2 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress2(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
const uint8 *end = input + size;
|
||||
uint16 *prevline = NULL, *line = NULL;
|
||||
int opcode, count, offset, isfillormix, x = width;
|
||||
int lastopcode = -1, insertmix = False, bicolour = False;
|
||||
uint8 code;
|
||||
uint16 colour1 = 0, colour2 = 0;
|
||||
uint8 mixmask, mask = 0;
|
||||
uint16 mix = 0xffff;
|
||||
int fom_mask = 0;
|
||||
|
||||
while (input < end)
|
||||
{
|
||||
fom_mask = 0;
|
||||
code = CVAL(input);
|
||||
opcode = code >> 4;
|
||||
/* Handle different opcode forms */
|
||||
switch (opcode)
|
||||
{
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
opcode -= 6;
|
||||
count = code & 0xf;
|
||||
offset = 16;
|
||||
break;
|
||||
case 0xf:
|
||||
opcode = code & 0xf;
|
||||
if (opcode < 9)
|
||||
{
|
||||
count = CVAL(input);
|
||||
count |= CVAL(input) << 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (opcode < 0xb) ? 8 : 1;
|
||||
}
|
||||
offset = 0;
|
||||
break;
|
||||
default:
|
||||
opcode >>= 1;
|
||||
count = code & 0x1f;
|
||||
offset = 32;
|
||||
break;
|
||||
}
|
||||
/* Handle strange cases for counts */
|
||||
if (offset != 0)
|
||||
{
|
||||
isfillormix = ((opcode == 2) || (opcode == 7));
|
||||
if (count == 0)
|
||||
{
|
||||
if (isfillormix)
|
||||
count = CVAL(input) + 1;
|
||||
else
|
||||
count = CVAL(input) + offset;
|
||||
}
|
||||
else if (isfillormix)
|
||||
{
|
||||
count <<= 3;
|
||||
}
|
||||
}
|
||||
/* Read preliminary data */
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: /* Fill */
|
||||
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
||||
insertmix = True;
|
||||
break;
|
||||
case 8: /* Bicolour */
|
||||
CVAL2(input, colour1);
|
||||
case 3: /* Colour */
|
||||
CVAL2(input, colour2);
|
||||
break;
|
||||
case 6: /* SetMix/Mix */
|
||||
case 7: /* SetMix/FillOrMix */
|
||||
CVAL2(input, mix);
|
||||
opcode -= 5;
|
||||
break;
|
||||
case 9: /* FillOrMix_1 */
|
||||
mask = 0x03;
|
||||
opcode = 0x02;
|
||||
fom_mask = 3;
|
||||
break;
|
||||
case 0x0a: /* FillOrMix_2 */
|
||||
mask = 0x05;
|
||||
opcode = 0x02;
|
||||
fom_mask = 5;
|
||||
break;
|
||||
}
|
||||
lastopcode = opcode;
|
||||
mixmask = 0;
|
||||
/* Output body */
|
||||
while (count > 0)
|
||||
{
|
||||
if (x >= width)
|
||||
{
|
||||
if (height <= 0)
|
||||
return False;
|
||||
x = 0;
|
||||
height--;
|
||||
prevline = line;
|
||||
line = ((uint16 *) output) + height * width;
|
||||
}
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: /* Fill */
|
||||
if (insertmix)
|
||||
{
|
||||
if (prevline == NULL)
|
||||
line[x] = mix;
|
||||
else
|
||||
line[x] = prevline[x] ^ mix;
|
||||
insertmix = False;
|
||||
count--;
|
||||
x++;
|
||||
}
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT(line[x] = 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT(line[x] = prevline[x])
|
||||
}
|
||||
break;
|
||||
case 1: /* Mix */
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT(line[x] = mix)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT(line[x] = prevline[x] ^ mix)
|
||||
}
|
||||
break;
|
||||
case 2: /* Fill or Mix */
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
MASK_UPDATE();
|
||||
if (mask & mixmask)
|
||||
line[x] = mix;
|
||||
else
|
||||
line[x] = 0;
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
MASK_UPDATE();
|
||||
if (mask & mixmask)
|
||||
line[x] = prevline[x] ^ mix;
|
||||
else
|
||||
line[x] = prevline[x];
|
||||
)
|
||||
}
|
||||
break;
|
||||
case 3: /* Colour */
|
||||
REPEAT(line[x] = colour2)
|
||||
break;
|
||||
case 4: /* Copy */
|
||||
REPEAT(CVAL2(input, line[x]))
|
||||
break;
|
||||
case 8: /* Bicolour */
|
||||
REPEAT
|
||||
(
|
||||
if (bicolour)
|
||||
{
|
||||
line[x] = colour2;
|
||||
bicolour = False;
|
||||
}
|
||||
else
|
||||
{
|
||||
line[x] = colour1;
|
||||
bicolour = True;
|
||||
count++;
|
||||
}
|
||||
)
|
||||
break;
|
||||
case 0xd: /* White */
|
||||
REPEAT(line[x] = 0xffff)
|
||||
break;
|
||||
case 0xe: /* Black */
|
||||
REPEAT(line[x] = 0)
|
||||
break;
|
||||
default:
|
||||
unimpl("bitmap opcode 0x%x\n", opcode);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/* 3 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress3(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
uint8 *end = input + size;
|
||||
uint8 *prevline = NULL, *line = NULL;
|
||||
int opcode, count, offset, isfillormix, x = width;
|
||||
int lastopcode = -1, insertmix = False, bicolour = False;
|
||||
uint8 code;
|
||||
uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0};
|
||||
uint8 mixmask, mask = 0;
|
||||
uint8 mix[3] = {0xff, 0xff, 0xff};
|
||||
int fom_mask = 0;
|
||||
|
||||
while (input < end)
|
||||
{
|
||||
fom_mask = 0;
|
||||
code = CVAL(input);
|
||||
opcode = code >> 4;
|
||||
/* Handle different opcode forms */
|
||||
switch (opcode)
|
||||
{
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
opcode -= 6;
|
||||
count = code & 0xf;
|
||||
offset = 16;
|
||||
break;
|
||||
case 0xf:
|
||||
opcode = code & 0xf;
|
||||
if (opcode < 9)
|
||||
{
|
||||
count = CVAL(input);
|
||||
count |= CVAL(input) << 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (opcode <
|
||||
0xb) ? 8 : 1;
|
||||
}
|
||||
offset = 0;
|
||||
break;
|
||||
default:
|
||||
opcode >>= 1;
|
||||
count = code & 0x1f;
|
||||
offset = 32;
|
||||
break;
|
||||
}
|
||||
/* Handle strange cases for counts */
|
||||
if (offset != 0)
|
||||
{
|
||||
isfillormix = ((opcode == 2) || (opcode == 7));
|
||||
if (count == 0)
|
||||
{
|
||||
if (isfillormix)
|
||||
count = CVAL(input) + 1;
|
||||
else
|
||||
count = CVAL(input) + offset;
|
||||
}
|
||||
else if (isfillormix)
|
||||
{
|
||||
count <<= 3;
|
||||
}
|
||||
}
|
||||
/* Read preliminary data */
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: /* Fill */
|
||||
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
||||
insertmix = True;
|
||||
break;
|
||||
case 8: /* Bicolour */
|
||||
colour1[0] = CVAL(input);
|
||||
colour1[1] = CVAL(input);
|
||||
colour1[2] = CVAL(input);
|
||||
case 3: /* Colour */
|
||||
colour2[0] = CVAL(input);
|
||||
colour2[1] = CVAL(input);
|
||||
colour2[2] = CVAL(input);
|
||||
break;
|
||||
case 6: /* SetMix/Mix */
|
||||
case 7: /* SetMix/FillOrMix */
|
||||
mix[0] = CVAL(input);
|
||||
mix[1] = CVAL(input);
|
||||
mix[2] = CVAL(input);
|
||||
opcode -= 5;
|
||||
break;
|
||||
case 9: /* FillOrMix_1 */
|
||||
mask = 0x03;
|
||||
opcode = 0x02;
|
||||
fom_mask = 3;
|
||||
break;
|
||||
case 0x0a: /* FillOrMix_2 */
|
||||
mask = 0x05;
|
||||
opcode = 0x02;
|
||||
fom_mask = 5;
|
||||
break;
|
||||
}
|
||||
lastopcode = opcode;
|
||||
mixmask = 0;
|
||||
/* Output body */
|
||||
while (count > 0)
|
||||
{
|
||||
if (x >= width)
|
||||
{
|
||||
if (height <= 0)
|
||||
return False;
|
||||
x = 0;
|
||||
height--;
|
||||
prevline = line;
|
||||
line = output + height * (width * 3);
|
||||
}
|
||||
switch (opcode)
|
||||
{
|
||||
case 0: /* Fill */
|
||||
if (insertmix)
|
||||
{
|
||||
if (prevline == NULL)
|
||||
{
|
||||
line[x * 3] = mix[0];
|
||||
line[x * 3 + 1] = mix[1];
|
||||
line[x * 3 + 2] = mix[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
line[x * 3] =
|
||||
prevline[x * 3] ^ mix[0];
|
||||
line[x * 3 + 1] =
|
||||
prevline[x * 3 + 1] ^ mix[1];
|
||||
line[x * 3 + 2] =
|
||||
prevline[x * 3 + 2] ^ mix[2];
|
||||
}
|
||||
insertmix = False;
|
||||
count--;
|
||||
x++;
|
||||
}
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] = 0;
|
||||
line[x * 3 + 1] = 0;
|
||||
line[x * 3 + 2] = 0;
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] = prevline[x * 3];
|
||||
line[x * 3 + 1] = prevline[x * 3 + 1];
|
||||
line[x * 3 + 2] = prevline[x * 3 + 2];
|
||||
)
|
||||
}
|
||||
break;
|
||||
case 1: /* Mix */
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] = mix[0];
|
||||
line[x * 3 + 1] = mix[1];
|
||||
line[x * 3 + 2] = mix[2];
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] =
|
||||
prevline[x * 3] ^ mix[0];
|
||||
line[x * 3 + 1] =
|
||||
prevline[x * 3 + 1] ^ mix[1];
|
||||
line[x * 3 + 2] =
|
||||
prevline[x * 3 + 2] ^ mix[2];
|
||||
)
|
||||
}
|
||||
break;
|
||||
case 2: /* Fill or Mix */
|
||||
if (prevline == NULL)
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
MASK_UPDATE();
|
||||
if (mask & mixmask)
|
||||
{
|
||||
line[x * 3] = mix[0];
|
||||
line[x * 3 + 1] = mix[1];
|
||||
line[x * 3 + 2] = mix[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
line[x * 3] = 0;
|
||||
line[x * 3 + 1] = 0;
|
||||
line[x * 3 + 2] = 0;
|
||||
}
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
REPEAT
|
||||
(
|
||||
MASK_UPDATE();
|
||||
if (mask & mixmask)
|
||||
{
|
||||
line[x * 3] =
|
||||
prevline[x * 3] ^ mix [0];
|
||||
line[x * 3 + 1] =
|
||||
prevline[x * 3 + 1] ^ mix [1];
|
||||
line[x * 3 + 2] =
|
||||
prevline[x * 3 + 2] ^ mix [2];
|
||||
}
|
||||
else
|
||||
{
|
||||
line[x * 3] =
|
||||
prevline[x * 3];
|
||||
line[x * 3 + 1] =
|
||||
prevline[x * 3 + 1];
|
||||
line[x * 3 + 2] =
|
||||
prevline[x * 3 + 2];
|
||||
}
|
||||
)
|
||||
}
|
||||
break;
|
||||
case 3: /* Colour */
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] = colour2 [0];
|
||||
line[x * 3 + 1] = colour2 [1];
|
||||
line[x * 3 + 2] = colour2 [2];
|
||||
)
|
||||
break;
|
||||
case 4: /* Copy */
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] = CVAL(input);
|
||||
line[x * 3 + 1] = CVAL(input);
|
||||
line[x * 3 + 2] = CVAL(input);
|
||||
)
|
||||
break;
|
||||
case 8: /* Bicolour */
|
||||
REPEAT
|
||||
(
|
||||
if (bicolour)
|
||||
{
|
||||
line[x * 3] = colour2[0];
|
||||
line[x * 3 + 1] = colour2[1];
|
||||
line[x * 3 + 2] = colour2[2];
|
||||
bicolour = False;
|
||||
}
|
||||
else
|
||||
{
|
||||
line[x * 3] = colour1[0];
|
||||
line[x * 3 + 1] = colour1[1];
|
||||
line[x * 3 + 2] = colour1[2];
|
||||
bicolour = True;
|
||||
count++;
|
||||
}
|
||||
)
|
||||
break;
|
||||
case 0xd: /* White */
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] = 0xff;
|
||||
line[x * 3 + 1] = 0xff;
|
||||
line[x * 3 + 2] = 0xff;
|
||||
)
|
||||
break;
|
||||
case 0xe: /* Black */
|
||||
REPEAT
|
||||
(
|
||||
line[x * 3] = 0;
|
||||
line[x * 3 + 1] = 0;
|
||||
line[x * 3 + 2] = 0;
|
||||
)
|
||||
break;
|
||||
default:
|
||||
unimpl("bitmap opcode 0x%x\n", opcode);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/* decompress a colour plane */
|
||||
static int
|
||||
process_plane(uint8 * in, int width, int height, uint8 * out, int size)
|
||||
{
|
||||
int indexw;
|
||||
int indexh;
|
||||
int code;
|
||||
int collen;
|
||||
int replen;
|
||||
int color;
|
||||
int x;
|
||||
int revcode;
|
||||
uint8 * last_line;
|
||||
uint8 * this_line;
|
||||
uint8 * org_in;
|
||||
uint8 * org_out;
|
||||
|
||||
org_in = in;
|
||||
org_out = out;
|
||||
last_line = 0;
|
||||
indexh = 0;
|
||||
while (indexh < height)
|
||||
{
|
||||
out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
|
||||
color = 0;
|
||||
this_line = out;
|
||||
indexw = 0;
|
||||
if (last_line == 0)
|
||||
{
|
||||
while (indexw < width)
|
||||
{
|
||||
code = CVAL(in);
|
||||
replen = code & 0xf;
|
||||
collen = (code >> 4) & 0xf;
|
||||
revcode = (replen << 4) | collen;
|
||||
if ((revcode <= 47) && (revcode >= 16))
|
||||
{
|
||||
replen = revcode;
|
||||
collen = 0;
|
||||
}
|
||||
while (collen > 0)
|
||||
{
|
||||
color = CVAL(in);
|
||||
*out = color;
|
||||
out += 4;
|
||||
indexw++;
|
||||
collen--;
|
||||
}
|
||||
while (replen > 0)
|
||||
{
|
||||
*out = color;
|
||||
out += 4;
|
||||
indexw++;
|
||||
replen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (indexw < width)
|
||||
{
|
||||
code = CVAL(in);
|
||||
replen = code & 0xf;
|
||||
collen = (code >> 4) & 0xf;
|
||||
revcode = (replen << 4) | collen;
|
||||
if ((revcode <= 47) && (revcode >= 16))
|
||||
{
|
||||
replen = revcode;
|
||||
collen = 0;
|
||||
}
|
||||
while (collen > 0)
|
||||
{
|
||||
x = CVAL(in);
|
||||
if (x & 1)
|
||||
{
|
||||
x = x >> 1;
|
||||
x = x + 1;
|
||||
color = -x;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = x >> 1;
|
||||
color = x;
|
||||
}
|
||||
x = last_line[indexw * 4] + color;
|
||||
*out = x;
|
||||
out += 4;
|
||||
indexw++;
|
||||
collen--;
|
||||
}
|
||||
while (replen > 0)
|
||||
{
|
||||
x = last_line[indexw * 4] + color;
|
||||
*out = x;
|
||||
out += 4;
|
||||
indexw++;
|
||||
replen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
indexh++;
|
||||
last_line = this_line;
|
||||
}
|
||||
return (int) (in - org_in);
|
||||
}
|
||||
|
||||
/* 4 byte bitmap decompress */
|
||||
RD_BOOL
|
||||
bitmap_decompress4(uint8 * output, int width, int height, const uint8 * input, int size)
|
||||
{
|
||||
int code;
|
||||
int bytes_pro;
|
||||
int total_pro;
|
||||
|
||||
code = CVAL(input);
|
||||
if (code != 0x10)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
total_pro = 1;
|
||||
bytes_pro = process_plane(input, width, height, output + 3, size - total_pro);
|
||||
total_pro += bytes_pro;
|
||||
input += bytes_pro;
|
||||
bytes_pro = process_plane(input, width, height, output + 2, size - total_pro);
|
||||
total_pro += bytes_pro;
|
||||
input += bytes_pro;
|
||||
bytes_pro = process_plane(input, width, height, output + 1, size - total_pro);
|
||||
total_pro += bytes_pro;
|
||||
input += bytes_pro;
|
||||
bytes_pro = process_plane(input, width, height, output + 0, size - total_pro);
|
||||
total_pro += bytes_pro;
|
||||
return size == total_pro;
|
||||
}
|
||||
|
||||
int
|
||||
bitmap_decompress_15(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||
uint8 * temp = (uint8*)malloc(input_width * input_height * 2);
|
||||
RD_BOOL rv = bitmap_decompress2(temp, input_width, input_height, input, size);
|
||||
|
||||
// convert to rgba
|
||||
for (int y = 0; y < output_height; y++) {
|
||||
for (int x = 0; x < output_width; x++) {
|
||||
uint16 a = ((uint16*)temp)[y * input_width + x];
|
||||
uint8 r = (a & 0x7c00) >> 10;
|
||||
uint8 g = (a & 0x03e0) >> 5;
|
||||
uint8 b = (a & 0x001f);
|
||||
r = r * 255 / 31;
|
||||
g = g * 255 / 31;
|
||||
b = b * 255 / 31;
|
||||
((uint32*)output)[y * output_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
|
||||
}
|
||||
}
|
||||
|
||||
free(temp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
bitmap_decompress_16(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||
uint8 * temp = (uint8*)malloc(input_width * input_height * 2);
|
||||
RD_BOOL rv = bitmap_decompress2(temp, input_width, input_height, input, size);
|
||||
|
||||
// convert to rgba
|
||||
for (int y = 0; y < output_height; y++) {
|
||||
for (int x = 0; x < output_width; x++) {
|
||||
uint16 a = ((uint16*)temp)[y * input_width + x];
|
||||
uint8 r = (a & 0xf800) >> 11;
|
||||
uint8 g = (a & 0x07e0) >> 5;
|
||||
uint8 b = (a & 0x001f);
|
||||
r = r * 255 / 31;
|
||||
g = g * 255 / 63;
|
||||
b = b * 255 / 31;
|
||||
((uint32*)output)[y * output_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
|
||||
}
|
||||
}
|
||||
free(temp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
bitmap_decompress_24(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||
uint8 * temp = (uint8*)malloc(input_width * input_height * 3);
|
||||
RD_BOOL rv = bitmap_decompress3(temp, input_width, input_height, input, size);
|
||||
|
||||
// convert to rgba
|
||||
for (int y = 0; y < output_height; y++) {
|
||||
for (int x = 0; x < output_width; x++) {
|
||||
uint8 r = temp[(y * input_width + x) * 3];
|
||||
uint8 g = temp[(y * input_width + x) * 3 + 1];
|
||||
uint8 b = temp[(y * input_width + x) * 3 + 2];
|
||||
((uint32*)output)[y * output_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
|
||||
}
|
||||
}
|
||||
free(temp);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
bitmap_decompress_32(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||
uint8 * temp = (uint8*)malloc(input_width * input_height * 4);
|
||||
RD_BOOL rv = bitmap_decompress4(temp, input_width, input_height, input, size);
|
||||
|
||||
// convert to rgba
|
||||
for (int y = 0; y < output_height; y++) {
|
||||
for (int x = 0; x < output_width; x++) {
|
||||
uint8 r = temp[(y * input_width + x) * 4];
|
||||
uint8 g = temp[(y * input_width + x) * 4 + 1];
|
||||
uint8 b = temp[(y * input_width + x) * 4 + 2];
|
||||
uint8 a = temp[(y * input_width + x) * 4 + 3];
|
||||
((uint32*)output)[y * output_width + x] = 0xff << 24 | r << 16 | g << 8 | b;
|
||||
}
|
||||
}
|
||||
free(temp);
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef RLE_H
|
||||
#define RLE_H
|
||||
|
||||
#define RD_BOOL int
|
||||
#define False 0
|
||||
#define True 1
|
||||
|
||||
#define uint8 unsigned char
|
||||
#define uint16 unsigned short
|
||||
#define uint32 unsigned int
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
RD_BOOL bitmap_decompress1(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress2(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress3(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
RD_BOOL bitmap_decompress4(uint8 * output, int width, int height, const uint8 * input, int size);
|
||||
|
||||
int bitmap_decompress_15(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||
int bitmap_decompress_16(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||
int bitmap_decompress_24(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||
int bitmap_decompress_32(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RLE_H
|
|
@ -0,0 +1,709 @@
|
|||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QNetworkCookie>
|
||||
#include <QStandardPaths>
|
||||
#include <qcoreapplication.h>
|
||||
#include <inttypes.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "thr_play.h"
|
||||
#include "thr_data.h"
|
||||
#include "util.h"
|
||||
#include "downloader.h"
|
||||
#include "record_format.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include "rle.h"
|
||||
|
||||
|
||||
static QImage* _rdpimg2QImage(int w, int h, int bitsPerPixel, bool isCompressed, const uint8_t* dat, uint32_t len) {
|
||||
QImage* out;
|
||||
switch(bitsPerPixel) {
|
||||
case 15:
|
||||
if(isCompressed) {
|
||||
uint8_t* _dat = reinterpret_cast<uint8_t*>(calloc(1, w*h*2));
|
||||
if(!bitmap_decompress1(_dat, w, h, dat, len)) {
|
||||
free(_dat);
|
||||
return nullptr;
|
||||
}
|
||||
out = new QImage(_dat, w, h, QImage::Format_RGB555);
|
||||
free(_dat);
|
||||
}
|
||||
else {
|
||||
out = new QImage(QImage(dat, w, h, QImage::Format_RGB555).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)));
|
||||
}
|
||||
return out;
|
||||
|
||||
case 16:
|
||||
if(isCompressed) {
|
||||
uint8_t* _dat = reinterpret_cast<uint8_t*>(calloc(1, w*h*2));
|
||||
if(!bitmap_decompress2(_dat, w, h, dat, len)) {
|
||||
free(_dat);
|
||||
qDebug() << "22------------------DECOMPRESS2 failed.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: 这里需要进一步优化,直接操作QImage的buffer。
|
||||
out = new QImage(w, h, QImage::Format_RGB16);
|
||||
for(int y = 0; y < h; y++) {
|
||||
for(int x = 0; x < w; x++) {
|
||||
uint16 a = ((uint16*)_dat)[y * w + x];
|
||||
uint8 r = ((a & 0xf800) >> 11) * 255 / 31;
|
||||
uint8 g = ((a & 0x07e0) >> 5) * 255 / 63;
|
||||
uint8 b = (a & 0x001f) * 255 / 31;
|
||||
out->setPixelColor(x, y, QColor(r,g,b));
|
||||
}
|
||||
}
|
||||
free(_dat);
|
||||
return out;
|
||||
}
|
||||
else {
|
||||
out = new QImage(QImage(dat, w, h, QImage::Format_RGB16).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)));
|
||||
}
|
||||
return out;
|
||||
|
||||
case 24:
|
||||
case 32:
|
||||
default:
|
||||
qDebug() << "--------NOT support " << bitsPerPixel << " bitsPerPix.";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static QImage* _raw2QImage(int w, int h, const uint8_t* dat, uint32_t len) {
|
||||
QImage* out;
|
||||
|
||||
// TODO: 这里需要进一步优化,直接操作QImage的buffer。
|
||||
out = new QImage(w, h, QImage::Format_RGB16);
|
||||
for(int y = 0; y < h; y++) {
|
||||
for(int x = 0; x < w; x++) {
|
||||
uint16 a = ((uint16*)dat)[y * w + x];
|
||||
uint8 r = ((a & 0xf800) >> 11) * 255 / 31;
|
||||
uint8 g = ((a & 0x07e0) >> 5) * 255 / 63;
|
||||
uint8 b = (a & 0x001f) * 255 / 31;
|
||||
out->setPixelColor(x, y, QColor(r,g,b));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================================================================
|
||||
// ThrData
|
||||
//=================================================================
|
||||
|
||||
ThrData::ThrData(MainWindow* mainwin, const QString& res) {
|
||||
m_mainwin = mainwin;
|
||||
m_res = res;
|
||||
m_need_download = false;
|
||||
m_need_stop = false;
|
||||
m_need_restart = false;
|
||||
m_wait_restart = false;
|
||||
m_need_show_kf = false;
|
||||
|
||||
m_file_idx = 0;
|
||||
m_offset = 0;
|
||||
|
||||
#ifdef __APPLE__
|
||||
m_data_path_base = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
m_data_path_base += "/tp-testdata/";
|
||||
#else
|
||||
m_data_path_base = QCoreApplication::applicationDirPath() + "/record";
|
||||
#endif
|
||||
qDebug("data-path-base: %s", m_data_path_base.toStdString().c_str());
|
||||
|
||||
// qDebug() << "AppConfigLocation:" << QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
||||
// qDebug() << "AppDataLocation:" << QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
// qDebug() << "AppLocalDataLocation:" << QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
|
||||
// qDebug() << "ConfigLocation:" << QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
|
||||
// qDebug() << "CacheLocation:" << QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
// qDebug() << "GenericCacheLocation:" << QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
|
||||
|
||||
/*
|
||||
AppConfigLocation: "C:/Users/apex/AppData/Local/tp-player"
|
||||
AppDataLocation: "C:/Users/apex/AppData/Roaming/tp-player"
|
||||
AppLocalDataLocation: "C:/Users/apex/AppData/Local/tp-player"
|
||||
ConfigLocation: "C:/Users/apex/AppData/Local/tp-player"
|
||||
CacheLocation: "C:/Users/apex/AppData/Local/tp-player/cache"
|
||||
GenericCacheLocation: "C:/Users/apex/AppData/Local/cache"
|
||||
*/
|
||||
}
|
||||
|
||||
ThrData::~ThrData() {
|
||||
_clear_data();
|
||||
}
|
||||
|
||||
void ThrData::stop() {
|
||||
if(!isRunning())
|
||||
return;
|
||||
m_need_stop = true;
|
||||
wait();
|
||||
qDebug("data thread stop() end.");
|
||||
}
|
||||
|
||||
void ThrData::_notify_message(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_MESSAGE);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThrData::_notify_error(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_ERROR);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThrData::run() {
|
||||
_run();
|
||||
qDebug("ThrData thread run() end.");
|
||||
}
|
||||
|
||||
void ThrData::_run() {
|
||||
|
||||
QString _tmp_res = m_res.toLower();
|
||||
if(_tmp_res.startsWith("http")) {
|
||||
m_need_download = true;
|
||||
_notify_message(LOCAL8BIT("正在准备录像数据,请稍候..."));
|
||||
|
||||
if(!m_thr_download.init(m_data_path_base, m_res)) {
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("无法下载录像文件!\n\n"), m_res));
|
||||
return;
|
||||
}
|
||||
|
||||
m_thr_download.start();
|
||||
msleep(100);
|
||||
|
||||
for(;;) {
|
||||
if(m_need_stop)
|
||||
return;
|
||||
if(!m_thr_download.is_running() || m_thr_download.is_tpk_downloaded())
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
if(!m_thr_download.is_tpk_downloaded()) {
|
||||
_notify_error(QString("%1\n%2").arg(LOCAL8BIT("无法下载录像文件!"), m_res));
|
||||
return;
|
||||
}
|
||||
|
||||
m_thr_download.get_data_path(m_data_path);
|
||||
}
|
||||
else {
|
||||
QFileInfo fi_chk_link(m_res);
|
||||
if(fi_chk_link.isSymLink())
|
||||
m_res = fi_chk_link.symLinkTarget();
|
||||
|
||||
QFileInfo fi(m_res);
|
||||
if(!fi.exists()) {
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("指定的文件或目录不存在!"), m_res));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fi.isFile()) {
|
||||
m_data_path = fi.path();
|
||||
}
|
||||
else if(fi.isDir()) {
|
||||
m_data_path = m_res;
|
||||
}
|
||||
|
||||
m_data_path = QDir::toNativeSeparators(m_data_path);
|
||||
}
|
||||
|
||||
// 到这里,.tpr和.tpk文件均已经下载完成了。
|
||||
|
||||
if(!_load_header())
|
||||
return;
|
||||
|
||||
if(!_load_keyframe())
|
||||
return;
|
||||
|
||||
|
||||
UpdateData* dat = new UpdateData(m_hdr);
|
||||
emit signal_update_data(dat);
|
||||
|
||||
|
||||
QFile* fdata = nullptr;
|
||||
qint64 file_size = 0;
|
||||
qint64 file_processed = 0;
|
||||
qint64 read_len = 0;
|
||||
QString str_fidx;
|
||||
|
||||
for(;;) {
|
||||
// 任何时候确保第一时间响应退出操作
|
||||
if(m_need_stop)
|
||||
return;
|
||||
|
||||
if(m_need_restart) {
|
||||
if(fdata) {
|
||||
fdata->close();
|
||||
delete fdata;
|
||||
fdata = nullptr;
|
||||
}
|
||||
|
||||
m_wait_restart = true;
|
||||
msleep(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果所有文件都已经处理完了,则等待(可能用户会拖动滚动条,或者重新播放)
|
||||
if(m_file_idx >= m_hdr.info.dat_file_count) {
|
||||
msleep(500);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 看看待播放队列中还有多少个数据包
|
||||
int pkg_count_in_queue = 0;
|
||||
int pkg_need_add = 0;
|
||||
|
||||
m_locker.lock();
|
||||
pkg_count_in_queue = m_data.size();
|
||||
m_locker.unlock();
|
||||
|
||||
// 少于1000个的话,补足到2000个
|
||||
if(m_data.size() < 1000)
|
||||
pkg_need_add = 2000 - pkg_count_in_queue;
|
||||
|
||||
if(pkg_need_add == 0) {
|
||||
msleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int i = 0; i < pkg_need_add; ++i) {
|
||||
if(m_need_stop)
|
||||
return;
|
||||
if(m_need_restart)
|
||||
break;
|
||||
|
||||
// 如果数据文件尚未打开,则打开它
|
||||
if(fdata == nullptr) {
|
||||
str_fidx.sprintf("%d", m_file_idx+1);
|
||||
QString tpd_fname = QString("%1/tp-rdp-%2.tpd").arg(m_data_path, str_fidx);
|
||||
tpd_fname = QDir::toNativeSeparators(tpd_fname);
|
||||
|
||||
QFileInfo fi_tpd(tpd_fname);
|
||||
if(!fi_tpd.exists()) {
|
||||
if(m_need_download) {
|
||||
// 此文件尚未下载完成,等待
|
||||
for(;;) {
|
||||
if(m_need_stop)
|
||||
return;
|
||||
if(!m_thr_download.is_running() || m_thr_download.is_tpd_downloaded(m_file_idx))
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
// 下载失败了
|
||||
if(!m_thr_download.is_tpd_downloaded(m_file_idx))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fdata = new QFile(tpd_fname);
|
||||
if(!fdata->open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << tpd_fname << " for read.";
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("无法打开录像数据文件!"), tpd_fname));
|
||||
return;
|
||||
}
|
||||
|
||||
file_size = fdata->size();
|
||||
file_processed = 0;
|
||||
qDebug("Open file tp-rdp-%d.tpd, processed: %" PRId64 ", size: %" PRId64, m_file_idx+1, file_processed, file_size);
|
||||
}
|
||||
|
||||
// 如果指定了起始偏移,则跳过这部分数据
|
||||
if(m_offset > 0) {
|
||||
fdata->seek(m_offset);
|
||||
file_processed = m_offset;
|
||||
m_offset = 0;
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 读取一个数据包
|
||||
//----------------------------------
|
||||
if(file_size - file_processed < sizeof(TS_RECORD_PKG)) {
|
||||
qDebug("invaid tp-rdp-%d.tpd file, filesize=%" PRId64 ", processed=%" PRId64 ", need=%d.", m_file_idx+1, file_size, file_processed, sizeof(TS_RECORD_PKG));
|
||||
_notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
return;
|
||||
}
|
||||
|
||||
TS_RECORD_PKG pkg;
|
||||
read_len = fdata->read(reinterpret_cast<char*>(&pkg), sizeof(TS_RECORD_PKG));
|
||||
if(read_len != sizeof(TS_RECORD_PKG)) {
|
||||
qDebug("invaid tp-rdp-%d.tpd file, read_len=%" PRId64 " (1).", m_file_idx+1, read_len);
|
||||
_notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
return;
|
||||
}
|
||||
file_processed += sizeof(TS_RECORD_PKG);
|
||||
|
||||
if(file_size - file_processed < pkg.size) {
|
||||
qDebug("invaid tp-rdp-%d.tpd file (2).", m_file_idx+1);
|
||||
_notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
return;
|
||||
}
|
||||
|
||||
if(pkg.size == 0) {
|
||||
qDebug("################## too bad.");
|
||||
}
|
||||
|
||||
QByteArray pkg_data = fdata->read(pkg.size);
|
||||
if(pkg_data.size() != static_cast<int>(pkg.size)) {
|
||||
qDebug("invaid tp-rdp-%d.tpd file, read_len=%" PRId64 " (3).", m_file_idx+1, read_len);
|
||||
_notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
return;
|
||||
}
|
||||
file_processed += pkg.size;
|
||||
|
||||
UpdateData* dat = _parse(pkg, pkg_data);
|
||||
if(dat == nullptr) {
|
||||
qDebug("invaid tp-rdp-%d.tpd file (4).", m_file_idx+1);
|
||||
_notify_error(QString("%1\ntp-rdp-%2.tpd").arg(LOCAL8BIT("错误的录像数据文件!"), str_fidx));
|
||||
return;
|
||||
}
|
||||
|
||||
// 遇到关键帧,需要清除自上一个关键帧以来保存的缓存图像数据
|
||||
if(pkg.type == TS_RECORD_TYPE_RDP_KEYFRAME) {
|
||||
for(size_t ci = 0; ci < m_cache_imgs.size(); ++ci) {
|
||||
if(m_cache_imgs[ci] != nullptr)
|
||||
delete m_cache_imgs[ci];
|
||||
}
|
||||
m_cache_imgs.clear();
|
||||
}
|
||||
|
||||
// 拖动滚动条后,需要显示一次关键帧数据,然后跳过后续关键帧。
|
||||
if(pkg.type == TS_RECORD_TYPE_RDP_KEYFRAME) {
|
||||
qDebug("----key frame: %ld, processed=%" PRId64 ", pkg.size=%d", pkg.time_ms, file_processed, pkg.size);
|
||||
if(m_need_show_kf) {
|
||||
m_need_show_kf = false;
|
||||
qDebug("++ show keyframe.");
|
||||
}
|
||||
else {
|
||||
qDebug("-- skip keyframe.");
|
||||
delete dat;
|
||||
dat = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// 数据放到待播放列表中
|
||||
if(dat) {
|
||||
m_locker.lock();
|
||||
m_data.enqueue(dat);
|
||||
m_locker.unlock();
|
||||
}
|
||||
|
||||
// 让线程调度器让播放线程有机会执行
|
||||
// msleep(1);
|
||||
|
||||
// 如果此文件已经处理完毕,则关闭文件,这样下次处理一个新的文件
|
||||
if(file_processed >= file_size) {
|
||||
fdata->close();
|
||||
delete fdata;
|
||||
fdata = nullptr;
|
||||
m_file_idx++;
|
||||
}
|
||||
|
||||
if(m_file_idx >= m_hdr.info.dat_file_count) {
|
||||
UpdateData* dat = new UpdateData(TYPE_END);
|
||||
m_locker.lock();
|
||||
m_data.enqueue(dat);
|
||||
m_locker.unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateData* ThrData::_parse(const TS_RECORD_PKG& pkg, const QByteArray& data) {
|
||||
if(pkg.type == TS_RECORD_TYPE_RDP_POINTER) {
|
||||
if(data.size() != sizeof(TS_RECORD_RDP_POINTER))
|
||||
return nullptr;
|
||||
|
||||
UpdateData* ud = new UpdateData();
|
||||
ud->set_pointer(pkg.time_ms, reinterpret_cast<const TS_RECORD_RDP_POINTER*>(data.data()));
|
||||
return ud;
|
||||
}
|
||||
else if(pkg.type == TS_RECORD_TYPE_RDP_IMAGE) {
|
||||
UpdateData* ud = new UpdateData(TYPE_IMAGE, pkg.time_ms);
|
||||
|
||||
if(data.size() < static_cast<int>(sizeof(uint16_t) + sizeof(TS_RECORD_RDP_IMAGE_INFO))) {
|
||||
delete ud;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t* dat_ptr = reinterpret_cast<const uint8_t*>(data.data());
|
||||
|
||||
uint16_t count = (reinterpret_cast<const uint16_t*>(dat_ptr))[0];
|
||||
uint32_t offset = sizeof(uint16_t);
|
||||
|
||||
UpdateImages& imgs = ud->get_images();
|
||||
|
||||
for(uint16_t i = 0; i < count; ++i) {
|
||||
|
||||
const TS_RECORD_RDP_IMAGE_INFO* info = reinterpret_cast<const TS_RECORD_RDP_IMAGE_INFO*>(dat_ptr+offset);
|
||||
offset += sizeof(TS_RECORD_RDP_IMAGE_INFO);
|
||||
|
||||
if(info->format != TS_RDP_IMG_ALT) {
|
||||
const uint8_t* img_dat = dat_ptr + offset;
|
||||
|
||||
const uint8_t* real_img_dat = nullptr;
|
||||
QByteArray unzip_data;
|
||||
if(info->zip_len > 0) {
|
||||
// 数据被压缩了,需要解压缩
|
||||
unzip_data.resize(static_cast<int>(info->dat_len));
|
||||
|
||||
uLong u_len = info->dat_len;
|
||||
int err = uncompress(reinterpret_cast<uint8_t*>(unzip_data.data()), &u_len, img_dat, info->zip_len);
|
||||
if(err != Z_OK || u_len != info->dat_len) {
|
||||
qDebug("image uncompress failed. err=%d.", err);
|
||||
}
|
||||
else {
|
||||
real_img_dat = reinterpret_cast<const uint8_t*>(unzip_data.data());
|
||||
}
|
||||
|
||||
offset += info->zip_len;
|
||||
}
|
||||
else {
|
||||
real_img_dat = img_dat;
|
||||
offset += info->dat_len;
|
||||
}
|
||||
|
||||
|
||||
UPDATE_IMAGE uimg;
|
||||
uimg.x = info->destLeft;
|
||||
uimg.y = info->destTop;
|
||||
uimg.w = info->destRight - info->destLeft + 1;
|
||||
uimg.h = info->destBottom - info->destTop + 1;
|
||||
if(real_img_dat)
|
||||
uimg.img = _rdpimg2QImage(info->width, info->height, info->bitsPerPixel, (info->format == TS_RDP_IMG_BMP) ? true : false, real_img_dat, info->dat_len);
|
||||
else
|
||||
uimg.img = nullptr;
|
||||
imgs.push_back(uimg);
|
||||
|
||||
QImage* cache_img = nullptr;
|
||||
if(uimg.img != nullptr)
|
||||
cache_img = new QImage(*uimg.img);
|
||||
|
||||
m_cache_imgs.push_back(cache_img);
|
||||
}
|
||||
else {
|
||||
UPDATE_IMAGE uimg;
|
||||
uimg.x = info->destLeft;
|
||||
uimg.y = info->destTop;
|
||||
uimg.w = info->destRight - info->destLeft + 1;
|
||||
uimg.h = info->destBottom - info->destTop + 1;
|
||||
|
||||
size_t cache_idx = info->dat_len;
|
||||
|
||||
if(cache_idx >= m_cache_imgs.size() || m_cache_imgs[cache_idx] == nullptr) {
|
||||
uimg.img = nullptr;
|
||||
}
|
||||
else {
|
||||
uimg.img = new QImage(*m_cache_imgs[cache_idx]);
|
||||
}
|
||||
imgs.push_back(uimg);
|
||||
}
|
||||
}
|
||||
|
||||
return ud;
|
||||
}
|
||||
else if(pkg.type == TS_RECORD_TYPE_RDP_KEYFRAME) {
|
||||
UpdateData* ud = new UpdateData(TYPE_IMAGE, pkg.time_ms);
|
||||
const TS_RECORD_RDP_KEYFRAME_INFO* info = reinterpret_cast<const TS_RECORD_RDP_KEYFRAME_INFO*>(data.data());
|
||||
const uint8_t* data_buf = reinterpret_cast<const uint8_t*>(data.data() + sizeof(TS_RECORD_RDP_KEYFRAME_INFO));
|
||||
uint32_t data_len = data.size() - sizeof(TS_RECORD_RDP_KEYFRAME_INFO);
|
||||
|
||||
UpdateImages& imgs = ud->get_images();
|
||||
|
||||
UPDATE_IMAGE uimg;
|
||||
uimg.x = 0;
|
||||
uimg.y = 0;
|
||||
uimg.w = m_hdr.basic.width;
|
||||
uimg.h = m_hdr.basic.height;
|
||||
|
||||
const uint8_t* real_img_dat = nullptr;
|
||||
uint32_t real_img_len = m_hdr.basic.width * m_hdr.basic.height * 2;
|
||||
|
||||
QByteArray unzip_data;
|
||||
if(data_len != real_img_len) {
|
||||
// 数据被压缩了,需要解压缩
|
||||
unzip_data.resize(static_cast<int>(real_img_len));
|
||||
|
||||
uLong u_len = real_img_len;
|
||||
int err = uncompress(reinterpret_cast<uint8_t*>(unzip_data.data()), &u_len, data_buf, data_len);
|
||||
if(err != Z_OK || u_len != real_img_len) {
|
||||
qDebug("keyframe uncompress failed. err=%d.", err);
|
||||
}
|
||||
else {
|
||||
real_img_dat = reinterpret_cast<const uint8_t*>(unzip_data.data());
|
||||
}
|
||||
}
|
||||
else {
|
||||
real_img_dat = data_buf;
|
||||
}
|
||||
|
||||
if(real_img_dat != nullptr)
|
||||
uimg.img = _raw2QImage(m_hdr.basic.width, m_hdr.basic.height, real_img_dat, real_img_len);
|
||||
else
|
||||
uimg.img = nullptr;
|
||||
imgs.push_back(uimg);
|
||||
|
||||
return ud;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void ThrData::restart(uint32_t start_ms) {
|
||||
qDebug("restart at %ld ms", start_ms);
|
||||
// 让处理线程处理完当前循环,然后等待
|
||||
m_need_restart = true;
|
||||
|
||||
// 确保处理线程已经处理完当前循环
|
||||
for(;;) {
|
||||
msleep(50);
|
||||
if(m_need_stop)
|
||||
return;
|
||||
if(m_wait_restart)
|
||||
break;
|
||||
}
|
||||
|
||||
// 清空待播放队列
|
||||
_clear_data();
|
||||
|
||||
if(start_ms == 0) {
|
||||
m_offset = 0;
|
||||
m_file_idx = 0;
|
||||
m_need_show_kf = false;
|
||||
}
|
||||
else {
|
||||
// 找到最接近 start_ms 但小于它的关键帧
|
||||
size_t i = 0;
|
||||
for(i = 0; i < m_kf.size(); ++i) {
|
||||
if(m_kf[i].time_ms > start_ms) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i > 0)
|
||||
i--;
|
||||
|
||||
qDebug("restart acturelly at %ld ms, kf: %d", m_kf[i].time_ms, i);
|
||||
|
||||
// 指定要播放的数据的开始位置
|
||||
m_offset = m_kf[i].offset;
|
||||
m_file_idx = m_kf[i].file_index;
|
||||
if(m_file_idx == (uint32_t)-1)
|
||||
m_file_idx = 0;
|
||||
m_need_show_kf = true;
|
||||
}
|
||||
|
||||
qDebug("RESTART: offset=%d, file_idx=%d", m_offset, m_file_idx);
|
||||
|
||||
// 让处理线程继续
|
||||
m_wait_restart = false;
|
||||
m_need_restart = false;
|
||||
}
|
||||
|
||||
bool ThrData::_load_header() {
|
||||
QString msg;
|
||||
qDebug() << "PATH_BASE: " << m_data_path;
|
||||
|
||||
QString filename = QString("%1/tp-rdp.tpr").arg(m_data_path);
|
||||
filename = QDir::toNativeSeparators(filename);
|
||||
qDebug() << "TPR: " << filename;
|
||||
|
||||
QFile f(filename);
|
||||
if(!f.open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << filename << " for read.";
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("无法打开录像信息文件!"), filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&m_hdr, 0, sizeof(TS_RECORD_HEADER));
|
||||
|
||||
qint64 read_len = 0;
|
||||
read_len = f.read(reinterpret_cast<char*>(&m_hdr), sizeof(TS_RECORD_HEADER));
|
||||
if(read_len != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug() << "invaid .tpr file.";
|
||||
_notify_error(QString("%1\n\n%2").arg(LOCAL8BIT("错误的录像信息文件!"), filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_hdr.info.ver != 4) {
|
||||
qDebug() << "invaid .tpr file.";
|
||||
_notify_error(QString("%1 %2%3").arg(LOCAL8BIT("不支持的录像文件版本 "), QString(m_hdr.info.ver), LOCAL8BIT("!\n\n此播放器支持录像文件版本 4。")));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_hdr.basic.width == 0 || m_hdr.basic.height == 0) {
|
||||
_notify_error(LOCAL8BIT("错误的录像信息,未记录窗口尺寸!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_hdr.info.dat_file_count == 0) {
|
||||
_notify_error(LOCAL8BIT("错误的录像信息,未记录数据文件数量!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThrData::_load_keyframe() {
|
||||
QString tpk_fname = QString("%1/tp-rdp.tpk").arg(m_data_path);
|
||||
tpk_fname = QDir::toNativeSeparators(tpk_fname);
|
||||
|
||||
qDebug() << "TPK: " << tpk_fname;
|
||||
|
||||
QFile f_kf(tpk_fname);
|
||||
if(!f_kf.open(QFile::ReadOnly)) {
|
||||
qDebug() << "Can not open " << tpk_fname << " for read.";
|
||||
_notify_error(QString("%1\n\n%3").arg(LOCAL8BIT("无法打开关键帧信息文件!"), tpk_fname));
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 fsize = f_kf.size();
|
||||
if(!fsize || fsize % sizeof(TS_RECORD_RDP_KEYFRAME_INFO) != 0) {
|
||||
qDebug() << "Can not open " << tpk_fname << " for read.";
|
||||
_notify_error(LOCAL8BIT("关键帧信息文件格式错误!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 read_len = 0;
|
||||
int kf_count = static_cast<int>(fsize / sizeof(TS_RECORD_RDP_KEYFRAME_INFO));
|
||||
for(int i = 0; i < kf_count; ++i) {
|
||||
TS_RECORD_RDP_KEYFRAME_INFO kf;
|
||||
memset(&kf, 0, sizeof(TS_RECORD_RDP_KEYFRAME_INFO));
|
||||
read_len = f_kf.read(reinterpret_cast<char*>(&kf), sizeof(TS_RECORD_RDP_KEYFRAME_INFO));
|
||||
if(read_len != sizeof(TS_RECORD_RDP_KEYFRAME_INFO)) {
|
||||
qDebug() << "invaid .tpk file.";
|
||||
_notify_error(LOCAL8BIT("关键帧信息文件格式错误!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_kf.push_back(kf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
UpdateData* ThrData::get_data() {
|
||||
UpdateData* d = nullptr;
|
||||
|
||||
m_locker.lock();
|
||||
if(m_data.size() > 0) {
|
||||
d = m_data.dequeue();
|
||||
}
|
||||
m_locker.unlock();
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void ThrData::_clear_data() {
|
||||
m_locker.lock();
|
||||
while(m_data.size() > 0) {
|
||||
UpdateData* d = m_data.dequeue();
|
||||
delete d;
|
||||
}
|
||||
m_locker.unlock();
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
#ifndef THR_DATA_H
|
||||
#define THR_DATA_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QQueue>
|
||||
#include <QMutex>
|
||||
#include <QNetworkReply>
|
||||
#include <QFile>
|
||||
#include <QEventLoop>
|
||||
#include <QImage>
|
||||
#include "update_data.h"
|
||||
#include "record_format.h"
|
||||
#include "thr_download.h"
|
||||
|
||||
/*
|
||||
为支持“边下载,边播放”、“可拖动进度条”等功能,录像数据会分为多个文件存放,目前每个文件约4MB。
|
||||
例如:
|
||||
tp-rdp.tpr
|
||||
tp-rdp.tpk (关键帧信息文件,v3.5.1开始引入)
|
||||
tp-rdp-1.tpd, tp-rdp-2.tpd, tp-rdp-3.tpd, ...
|
||||
这样,下载完一个数据文件,即可播放此数据文件中的内容,同时下载线程可以下载后续数据文件。
|
||||
|
||||
为支持“拖动进度条”,可以在数据文件中插入关键帧的方式,这就要求记录录像数据的同时对图像数据进行解码,
|
||||
并同步合成全屏数据(关键帧),每经过一段时间(或者一定数量的图像数据包)之后,就在录像数据文件中增加一个关键帧。
|
||||
正常播放时,跳过此关键帧。
|
||||
当进度条拖放发生时,找到目标时间点之前的最后一个关键帧,从此处开始无延时播放到目标时间点,然后正常播放。
|
||||
因此,需要能够快速定位到各个关键帧,因为有可能此时尚未下载这个关键帧所在的数据文件。定位到此关键帧
|
||||
所在的数据文件后,下载线程要放弃当前下载任务(如果不是当前正在下载的数据文件),并开始下载新的数据文件。
|
||||
因此,需要引入新的关键帧信息文件(.tpk),记录各个关键帧数据所在的数据文件序号、偏移、时间点等信息。
|
||||
|
||||
另外,为保证数据文件、关键帧信息文件等下载正确,下载时保存到对应的临时文件中,并记录已下载字节数,下载完成后再改名,如:
|
||||
tp-rdp.tpk.tmp, tp-rdp.tpk.len
|
||||
tp-rdp-1.tpd.tmp, tp-rdp-1.tpd.len, ...
|
||||
这样,下次需要下载指定文件时,如果发现对应的临时文件存在,可以根据已下载字节数,继续下载。
|
||||
*/
|
||||
|
||||
typedef std::vector<TS_RECORD_RDP_KEYFRAME_INFO> KeyFrames;
|
||||
|
||||
typedef std::vector<QImage*> CachedImages;
|
||||
|
||||
class MainWindow;
|
||||
|
||||
// 下载必要的文件,解析文件数据,生成图像数据(QImage*),将数据包放入待显示队列中,等待 ThrPlay 线程使用
|
||||
// 注意,无需将所有数据解析并放入待显示队列,此队列有数量限制(例如1000个),避免过多占用内存
|
||||
class ThrData : public QThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ThrData(MainWindow* mainwin, const QString& url);
|
||||
~ThrData();
|
||||
|
||||
virtual void run();
|
||||
void stop();
|
||||
|
||||
void restart(uint32_t start_ms); // 重新从指定时间开始播放
|
||||
|
||||
bool have_more_data();
|
||||
|
||||
UpdateData* get_data();
|
||||
|
||||
private:
|
||||
void _run();
|
||||
|
||||
bool _load_header();
|
||||
bool _load_keyframe();
|
||||
|
||||
void _clear_data();
|
||||
// void _prepare();
|
||||
|
||||
UpdateData* _parse(const TS_RECORD_PKG& pkg, const QByteArray& data);
|
||||
|
||||
void _notify_message(const QString& msg);
|
||||
void _notify_error(const QString& err_msg);
|
||||
|
||||
signals:
|
||||
void signal_update_data(UpdateData*);
|
||||
|
||||
private:
|
||||
MainWindow* m_mainwin;
|
||||
QQueue<UpdateData*> m_data;
|
||||
QMutex m_locker;
|
||||
|
||||
ThrDownload m_thr_download;
|
||||
|
||||
bool m_need_stop;
|
||||
|
||||
bool m_need_download;
|
||||
QString m_res;
|
||||
QString m_data_path_base;
|
||||
|
||||
QString m_url_base;
|
||||
QString m_sid;
|
||||
QString m_rid;
|
||||
QString m_data_path;
|
||||
|
||||
TS_RECORD_HEADER m_hdr;
|
||||
KeyFrames m_kf;
|
||||
|
||||
bool m_need_restart;
|
||||
bool m_wait_restart;
|
||||
bool m_need_show_kf;
|
||||
uint32_t m_file_idx;
|
||||
uint32_t m_offset;
|
||||
|
||||
CachedImages m_cache_imgs;
|
||||
};
|
||||
|
||||
#endif // THR_DATA_H
|
|
@ -0,0 +1,292 @@
|
|||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QNetworkCookie>
|
||||
|
||||
#include "thr_download.h"
|
||||
#include "util.h"
|
||||
#include "downloader.h"
|
||||
#include "record_format.h"
|
||||
|
||||
//=================================================================
|
||||
// ThrDownload
|
||||
//=================================================================
|
||||
|
||||
ThrDownload::ThrDownload() {
|
||||
m_need_stop = false;
|
||||
m_have_tpr = false;
|
||||
m_have_tpk = false;
|
||||
m_have_tpd = nullptr;
|
||||
m_need_tpk = false;
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
ThrDownload::~ThrDownload() {
|
||||
if(m_have_tpd)
|
||||
delete[] m_have_tpd;
|
||||
}
|
||||
|
||||
// tp-player.exe http://teleport.domain.com:7190/{sub/path/}tp_1491560510_ca67fceb75a78c9d/1234 (注意,并不直接访问此URI,实际上其并不存在)
|
||||
// TP服务器地址(可能包含子路径哦,例如上例中的{sub/path/}部分)/session-id(用于判断当前授权用户)/录像会话编号
|
||||
|
||||
bool ThrDownload::init(const QString& local_data_path_base, const QString &res) {
|
||||
m_data_path_base = local_data_path_base;
|
||||
|
||||
QString _tmp_res = res.toLower();
|
||||
if(!_tmp_res.startsWith("http")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList _uris = res.split('/');
|
||||
if(_uris.size() < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sid = _uris[_uris.size()-2];
|
||||
m_rid = _uris[_uris.size()-1];
|
||||
m_url_base = res.left(res.length() - m_sid.length() - m_rid.length() - 2);
|
||||
|
||||
if(m_sid.length() == 0 || m_rid.length() == 0 || m_url_base.length() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThrDownload::stop() {
|
||||
if(!m_running)
|
||||
return;
|
||||
// if(!isRunning())
|
||||
// return;
|
||||
m_need_stop = true;
|
||||
wait();
|
||||
qDebug("data thread stop() end.");
|
||||
}
|
||||
|
||||
// tp-player.exe http://teleport.domain.com:7190/{sub/path/}tp_1491560510_ca67fceb75a78c9d/1234 (注意,并不直接访问此URI,实际上其并不存在)
|
||||
// TP服务器地址(可能包含子路径哦,例如上例中的{sub/path/}部分)/session-id(用于判断当前授权用户)/录像会话编号
|
||||
|
||||
void ThrDownload::run() {
|
||||
_run();
|
||||
m_running = false;
|
||||
qDebug("ThrDownload thread run() end.");
|
||||
}
|
||||
|
||||
void ThrDownload::_run() {
|
||||
// m_state = statDownloading;
|
||||
|
||||
if(!_download_tpr()) {
|
||||
// m_state = statFailDone;
|
||||
return;
|
||||
}
|
||||
m_have_tpr = true;
|
||||
|
||||
m_have_tpd = new bool[m_tpd_count];
|
||||
for(uint32_t i = 0; i < m_tpd_count; ++i) {
|
||||
m_have_tpd[i] = false;
|
||||
}
|
||||
|
||||
if(m_need_tpk) {
|
||||
if(!_download_tpk()) {
|
||||
// m_state = statFailDone;
|
||||
return;
|
||||
}
|
||||
m_have_tpk = true;
|
||||
}
|
||||
|
||||
uint32_t file_idx = 0;
|
||||
for(;;) {
|
||||
if(m_need_stop)
|
||||
break;
|
||||
QString str_fidx;
|
||||
str_fidx.sprintf("%d", file_idx+1);
|
||||
|
||||
QString tpd_fname = QString("%1/tp-rdp-%2.tpd").arg(m_data_path, str_fidx);
|
||||
tpd_fname = QDir::toNativeSeparators(tpd_fname);
|
||||
|
||||
QString tmp_fname = QString("%1/tp-rdp-%2.tpd.downloading").arg(m_data_path, str_fidx);
|
||||
tmp_fname = QDir::toNativeSeparators(tmp_fname);
|
||||
|
||||
QFileInfo fi_tmp(tmp_fname);
|
||||
if(fi_tmp.isFile()) {
|
||||
QFile::remove(tmp_fname);
|
||||
}
|
||||
|
||||
QFileInfo fi_tpd(tpd_fname);
|
||||
if(!fi_tpd.exists()) {
|
||||
QString url = QString("%1/audit/get-file?act=read&type=rdp&rid=%2&f=tp-rdp-%3.tpd").arg(m_url_base, m_rid, str_fidx);
|
||||
|
||||
qDebug() << "URL : " << url;
|
||||
qDebug() << "TPD : " << tmp_fname;
|
||||
if(!_download_file(url, tmp_fname)) {
|
||||
// m_state = statFailDone;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!QFile::rename(tmp_fname, tpd_fname)) {
|
||||
// m_state = statFailDone;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_have_tpd[file_idx] = true;
|
||||
|
||||
file_idx += 1;
|
||||
if(file_idx >= m_tpd_count)
|
||||
break;
|
||||
}
|
||||
|
||||
// m_state = statSuccessDone;
|
||||
}
|
||||
|
||||
bool ThrDownload::_download_tpr() {
|
||||
QString url = QString("%1/audit/get-file?act=read&type=rdp&rid=%2&f=tp-rdp.tpr").arg(m_url_base, m_rid);
|
||||
QByteArray data;
|
||||
if(!_download_file(url, data))
|
||||
return false;
|
||||
|
||||
if(data.size() != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug("invalid header data. %d", data.size());
|
||||
m_error = QString(LOCAL8BIT("录像信息文件数据错误!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
TS_RECORD_HEADER* hdr = reinterpret_cast<TS_RECORD_HEADER*>(data.data());
|
||||
// if(hdr->info.ver != 4) {
|
||||
// qDebug() << "invaid .tpr file.";
|
||||
// m_last_error = QString("%1 %2%3").arg(LOCAL8BIT("不支持的录像文件版本 "), QString(hdr->info.ver), LOCAL8BIT("!\n\n此播放器支持录像文件版本 4。"));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if(m_hdr.basic.width == 0 || m_hdr.basic.height == 0) {
|
||||
// _notify_error(LOCAL8BIT("错误的录像信息,未记录窗口尺寸!"));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if(m_hdr.info.dat_file_count == 0) {
|
||||
// _notify_error(LOCAL8BIT("错误的录像信息,未记录数据文件数量!"));
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
||||
// 下载得到的数据应该是一个TS_RECORD_HEADER,解析此数据,生成本地文件路径,并保存之。
|
||||
QDateTime timeUTC;
|
||||
// timeUTC.setTimeSpec(Qt::UTC);
|
||||
// timeUTC.setTime_t(m_hdr.basic.timestamp);
|
||||
timeUTC.setSecsSinceEpoch(hdr->basic.timestamp);
|
||||
QString strUTC = timeUTC.toString("yyyyMMdd-hhmmss");
|
||||
|
||||
QString strAcc(hdr->basic.acc_username);
|
||||
int idx = strAcc.indexOf('\\');
|
||||
if(-1 != idx) {
|
||||
QString _domain = strAcc.left(idx);
|
||||
QString _user = strAcc.right(strAcc.length() - idx - 1);
|
||||
strAcc = _user + "@" + _domain;
|
||||
}
|
||||
|
||||
QString strType;
|
||||
if(hdr->info.type == TS_TPPR_TYPE_SSH) {
|
||||
strType = "SSH";
|
||||
}
|
||||
else if(hdr->info.type == TS_TPPR_TYPE_RDP) {
|
||||
strType = "RDP";
|
||||
m_need_tpk = true;
|
||||
}
|
||||
else {
|
||||
strType = "UNKNOWN";
|
||||
}
|
||||
|
||||
// .../record/RDP-211-admin-user@domain-192.168.0.68-20191015-020243
|
||||
m_data_path = QString("%1/%2-%3-%4-%5-%6-%7").arg(m_data_path_base, strType, m_rid, hdr->basic.user_username, strAcc, hdr->basic.host_ip, strUTC);
|
||||
m_data_path = QDir::toNativeSeparators(m_data_path);
|
||||
qDebug() << "PATH_BASE: " << m_data_path;
|
||||
|
||||
QDir dir;
|
||||
dir.mkpath(m_data_path);
|
||||
QFileInfo fi;
|
||||
fi.setFile(m_data_path);
|
||||
if(!fi.isDir()) {
|
||||
qDebug("can not create folder to save downloaded file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QString filename = QString("%1/tp-rdp.tpr").arg(m_data_path);
|
||||
filename = QDir::toNativeSeparators(filename);
|
||||
qDebug() << "TPR: " << filename;
|
||||
|
||||
QFile f;
|
||||
f.setFileName(filename);
|
||||
if(!f.open(QIODevice::WriteOnly | QFile::Truncate)){
|
||||
qDebug("open file for write failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 written = f.write(reinterpret_cast<const char*>(hdr), sizeof(TS_RECORD_HEADER));
|
||||
f.flush();
|
||||
f.close();
|
||||
|
||||
if(written != sizeof(TS_RECORD_HEADER)) {
|
||||
qDebug("save header file failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_tpd_count = hdr->info.dat_file_count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThrDownload::_download_tpk() {
|
||||
QString tpk_fname = QString("%1/tp-rdp.tpk").arg(m_data_path);
|
||||
tpk_fname = QDir::toNativeSeparators(tpk_fname);
|
||||
|
||||
QString tmp_fname = QString("%1/tp-rdp.tpk.downloading").arg(m_data_path);
|
||||
tmp_fname = QDir::toNativeSeparators(tmp_fname);
|
||||
|
||||
QFileInfo fi_tmp(tmp_fname);
|
||||
if(fi_tmp.isFile()) {
|
||||
QFile::remove(tmp_fname);
|
||||
}
|
||||
|
||||
QFileInfo fi_tpk(tpk_fname);
|
||||
if(!fi_tpk.exists()) {
|
||||
QString url = QString("%1/audit/get-file?act=read&type=rdp&rid=%2&f=tp-rdp.tpk").arg(m_url_base, m_rid);
|
||||
qDebug() << "TPK: " << tmp_fname;
|
||||
if(!_download_file(url, tmp_fname))
|
||||
return false;
|
||||
|
||||
if(!QFile::rename(tmp_fname, tpk_fname))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThrDownload::_download_file(const QString& url, const QString filename) {
|
||||
Downloader dl;
|
||||
if(!dl.request(url, m_sid, filename)) {
|
||||
qDebug() << "download failed.";
|
||||
m_error = QString("%1").arg(LOCAL8BIT("下载文件失败!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThrDownload::_download_file(const QString& url, QByteArray& data) {
|
||||
Downloader dl;
|
||||
if(!dl.request(url, m_sid, &data)) {
|
||||
qDebug() << "download failed.";
|
||||
m_error = QString("%1").arg(LOCAL8BIT("下载文件失败!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThrDownload::is_tpd_downloaded(uint32_t file_idx) const {
|
||||
if(!m_have_tpd)
|
||||
return false;
|
||||
if(file_idx >= m_tpd_count)
|
||||
return false;
|
||||
return m_have_tpd[file_idx];
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef THR_DOWNLOAD_H
|
||||
#define THR_DOWNLOAD_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QNetworkReply>
|
||||
#include <QFile>
|
||||
#include <QEventLoop>
|
||||
|
||||
class ThrDownload : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
//public:
|
||||
// enum State {
|
||||
// statStarting,
|
||||
// statDownloading,
|
||||
// statInvalidParam,
|
||||
// statFailDone,
|
||||
// statSuccessDone
|
||||
// };
|
||||
|
||||
public:
|
||||
ThrDownload();
|
||||
~ThrDownload();
|
||||
|
||||
bool init(const QString& local_data_path_base, const QString& res);
|
||||
|
||||
virtual void run();
|
||||
void stop();
|
||||
|
||||
bool is_running() const {return m_running;}
|
||||
|
||||
bool is_tpr_downloaded() const {return m_have_tpr;}
|
||||
bool is_tpk_downloaded() const {return m_have_tpk;}
|
||||
bool is_tpd_downloaded(uint32_t file_idx) const;
|
||||
bool get_data_path(QString& path) const {
|
||||
if(m_data_path.isEmpty())
|
||||
return false;
|
||||
path = m_data_path;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void _run();
|
||||
|
||||
bool _download_tpr();
|
||||
bool _download_tpk();
|
||||
|
||||
bool _download_file(const QString& url, const QString filename);
|
||||
bool _download_file(const QString& url, QByteArray& data);
|
||||
|
||||
private:
|
||||
bool m_need_stop;
|
||||
|
||||
QString m_data_path_base;
|
||||
|
||||
QString m_url_base;
|
||||
QString m_sid;
|
||||
QString m_rid;
|
||||
QString m_data_path;
|
||||
|
||||
bool m_running;
|
||||
bool m_have_tpr;
|
||||
bool m_have_tpk;
|
||||
bool m_need_tpk;
|
||||
|
||||
uint32_t m_tpd_count;
|
||||
bool* m_have_tpd;
|
||||
|
||||
QString m_error;
|
||||
};
|
||||
|
||||
#endif // THR_DOWNLOAD_H
|
|
@ -0,0 +1,182 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
#include "thr_play.h"
|
||||
#include "thr_data.h"
|
||||
#include "mainwindow.h"
|
||||
#include "record_format.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/*
|
||||
* 录像播放流程:
|
||||
* - 数据处理线程,该线程负责(下载)文件、解析文件,将数据准备成待播放队列;
|
||||
* + 数据处理线程维护待播放队列,少于500个则填充至1000个,每20ms检查一次队列是否少于500个。
|
||||
* - 播放线程从队列中取出一个数据,判断当前时间是否应该播放此数据,如果应该,则将此数据发送给主UI
|
||||
* + if( 播放速率 * (当前时间 - 播放时间) >= (当前数据包偏移时间 - 上个数据包偏移时间)) 则 播放
|
||||
* + 如选择“跳过无操作时间”,则数据包偏移时间差超过3秒的,视为3秒。
|
||||
*/
|
||||
|
||||
|
||||
ThrPlay::ThrPlay(MainWindow* mainwnd) {
|
||||
m_mainwnd = mainwnd;
|
||||
m_need_stop = false;
|
||||
m_need_pause = false;
|
||||
m_speed = 1;
|
||||
m_skip = false;
|
||||
m_start_ms = 0;
|
||||
}
|
||||
|
||||
ThrPlay::~ThrPlay() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void ThrPlay::stop() {
|
||||
if(!isRunning())
|
||||
return;
|
||||
|
||||
m_need_stop = true;
|
||||
wait();
|
||||
qDebug() << "play-thread end.";
|
||||
}
|
||||
|
||||
void ThrPlay::_notify_message(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_MESSAGE);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThrPlay::_notify_error(const QString& msg) {
|
||||
UpdateData* _msg = new UpdateData(TYPE_ERROR);
|
||||
_msg->message(msg);
|
||||
emit signal_update_data(_msg);
|
||||
}
|
||||
|
||||
void ThrPlay::resume(bool relocate, uint32_t start_ms) {
|
||||
if(relocate) {
|
||||
m_start_ms = start_ms;
|
||||
m_first_run = true;
|
||||
}
|
||||
m_need_pause = false;
|
||||
}
|
||||
|
||||
void ThrPlay::run() {
|
||||
|
||||
ThrData* thr_data = m_mainwnd->get_thr_data();
|
||||
m_first_run = true;
|
||||
uint32_t last_time_ms = 0;
|
||||
uint32_t last_pass_ms = 0;
|
||||
|
||||
UpdateData* dat = nullptr;
|
||||
for(;;) {
|
||||
if(m_need_stop)
|
||||
break;
|
||||
|
||||
// 1. 从ThrData的待播放队列中取出一个数据
|
||||
dat = thr_data->get_data();
|
||||
if(dat == nullptr) {
|
||||
msleep(20);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(m_first_run) {
|
||||
m_first_run = false;
|
||||
_notify_message("");
|
||||
}
|
||||
|
||||
if(m_start_ms > 0) {
|
||||
if(dat->get_time() < m_start_ms) {
|
||||
emit signal_update_data(dat);
|
||||
continue;
|
||||
}
|
||||
last_time_ms = m_start_ms;
|
||||
m_start_ms = 0;
|
||||
UpdateData* _enable = new UpdateData(TYPE_ENABLE_DRAW);
|
||||
emit signal_update_data(_enable);
|
||||
}
|
||||
|
||||
// 2. 根据数据包的信息,等待到播放时间点
|
||||
uint32_t need_wait_ms = 0;
|
||||
uint32_t this_time_ms = dat->get_time();
|
||||
uint32_t this_pass_ms = last_time_ms;
|
||||
if(this_time_ms > 0) {
|
||||
if(this_time_ms >= last_time_ms)
|
||||
need_wait_ms = this_time_ms - last_time_ms;
|
||||
else
|
||||
need_wait_ms = 0;
|
||||
|
||||
if(need_wait_ms > 0) {
|
||||
uint32_t time_wait = 0;
|
||||
|
||||
// 如果设置了跳过无操作区间,将超过1秒的等待时间压缩至1秒。
|
||||
if(m_skip) {
|
||||
if(need_wait_ms > 1000)
|
||||
need_wait_ms = 1000;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
time_wait = need_wait_ms > 10 ? 10 : need_wait_ms;
|
||||
msleep(time_wait);
|
||||
|
||||
if(m_need_pause) {
|
||||
while(m_need_pause) {
|
||||
msleep(50);
|
||||
if(m_need_stop)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_need_stop)
|
||||
break;
|
||||
|
||||
if(m_start_ms > 0) {
|
||||
delete dat;
|
||||
dat = nullptr;
|
||||
UpdateData* _disable = new UpdateData(TYPE_DISABLE_DRAW);
|
||||
msleep(500);
|
||||
emit signal_update_data(_disable);
|
||||
break;
|
||||
}
|
||||
|
||||
time_wait *= m_speed;
|
||||
|
||||
// 如果已经在等待长时间无操作区间内,用户设置了跳过无操作区间,则将超过0.5秒的等待时间压缩至0.5秒。
|
||||
if(m_skip) {
|
||||
if(need_wait_ms > 500)
|
||||
need_wait_ms = 500;
|
||||
}
|
||||
|
||||
this_pass_ms += time_wait;
|
||||
if(this_pass_ms - last_pass_ms > 100) {
|
||||
UpdateData* _passed_ms = new UpdateData(TYPE_PLAYED_MS);
|
||||
_passed_ms->played_ms(this_pass_ms);
|
||||
emit signal_update_data(_passed_ms);
|
||||
last_pass_ms = this_pass_ms;
|
||||
}
|
||||
|
||||
if(need_wait_ms <= time_wait)
|
||||
break;
|
||||
else
|
||||
need_wait_ms -= time_wait;
|
||||
}
|
||||
|
||||
if(m_need_stop)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
last_time_ms = this_time_ms;
|
||||
|
||||
// 3. 将数据包发送给主UI界面进行显示
|
||||
if(dat != nullptr) {
|
||||
if(dat->data_type() == TYPE_END) {
|
||||
_notify_message(LOCAL8BIT("播放结束"));
|
||||
}
|
||||
emit signal_update_data(dat);
|
||||
}
|
||||
}
|
||||
|
||||
if(dat != nullptr)
|
||||
delete dat;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef THR_PLAY_H
|
||||
#define THR_PLAY_H
|
||||
|
||||
#include <QThread>
|
||||
#include "update_data.h"
|
||||
#include "downloader.h"
|
||||
|
||||
class MainWindow;
|
||||
// 根据播放规则,将要播放的图像发送给主UI线程进行显示
|
||||
class ThrPlay : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class ThrData;
|
||||
public:
|
||||
ThrPlay(MainWindow* mainwnd);
|
||||
~ThrPlay();
|
||||
|
||||
virtual void run();
|
||||
void stop();
|
||||
void pause() {m_need_pause = true;}
|
||||
void resume(bool relocate, uint32_t start_ms);
|
||||
void speed(int s) {if(s >= 1 && s <= 16) m_speed = s;}
|
||||
void skip(bool s) {m_skip = s;}
|
||||
|
||||
private:
|
||||
void _notify_message(const QString& msg);
|
||||
void _notify_error(const QString& err_msg);
|
||||
|
||||
signals:
|
||||
void signal_update_data(UpdateData*);
|
||||
|
||||
private:
|
||||
MainWindow* m_mainwnd;
|
||||
bool m_need_stop;
|
||||
bool m_need_pause;
|
||||
int m_speed;
|
||||
bool m_skip;
|
||||
bool m_first_run;
|
||||
uint32_t m_start_ms;
|
||||
};
|
||||
|
||||
#endif // THR_PLAY_H
|
|
@ -0,0 +1,70 @@
|
|||
TEMPLATE = app
|
||||
TARGET = tp-player
|
||||
|
||||
QT += core gui widgets network
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
bar.h \
|
||||
thr_play.h \
|
||||
thr_data.h \
|
||||
update_data.h \
|
||||
record_format.h \
|
||||
rle.h \
|
||||
util.h \
|
||||
downloader.h \
|
||||
thr_download.h
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
bar.cpp \
|
||||
thr_play.cpp \
|
||||
thr_data.cpp \
|
||||
update_data.cpp \
|
||||
rle.c \
|
||||
util.cpp \
|
||||
downloader.cpp \
|
||||
thr_download.cpp
|
||||
|
||||
RESOURCES += \
|
||||
tp-player.qrc
|
||||
|
||||
RC_FILE += \
|
||||
tp-player.rc
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
|
||||
win32:CONFIG(release, debug|release): {
|
||||
DEFINES += QT_NO_DEBUG_OUTPUT
|
||||
LIBS += -L$$PWD/../../external/zlib/build/release/ -lzlib
|
||||
DESTDIR = $$PWD/../../out/client/x86/Release
|
||||
}
|
||||
else:win32:CONFIG(debug, debug|release): {
|
||||
LIBS += -L$$PWD/../../external/zlib/build/debug/ -lzlibd
|
||||
DESTDIR = $$PWD/../../out/client/x86/Debug
|
||||
}
|
||||
|
||||
|
||||
macx:CONFIG(release, debug|release): {
|
||||
DEFINES += QT_NO_DEBUG_OUTPUT
|
||||
LIBS += -L$$PWD/../../external/zlib/build/release/ -lzlib
|
||||
DESTDIR = $$PWD/../../out/client/x86/Release
|
||||
}
|
||||
else:macx:CONFIG(debug, debug|release): {
|
||||
LIBS += -L$$PWD/../../external/zlib/build/debug/ -lzlibd
|
||||
DESTDIR = $$PWD/../../out/client/x86/Debug
|
||||
}
|
||||
|
||||
|
||||
INCLUDEPATH += $$PWD/../../external/zlib
|
||||
INCLUDEPATH += $$PWD/../../external/zlib/build
|
||||
DEPENDPATH += $$PWD/../../external/zlib
|
||||
DEPENDPATH += $$PWD/../../external/zlib/build
|
||||
|
||||
#win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/../../external/zlib/build/release/libzlibstatic.a
|
||||
#else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/../../external/zlib/build/debug/libzlibstaticd.a
|
||||
#else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/../../external/zlib/build/release/zlibstatic.lib
|
||||
#else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/../../external/zlib/build/debug/zlibstaticd.lib
|
|
@ -0,0 +1,38 @@
|
|||
<RCC>
|
||||
<qresource prefix="/tp-player">
|
||||
<file>res/bg.png</file>
|
||||
<file>res/cursor.png</file>
|
||||
|
||||
<file>res/bar/bg-left.png</file>
|
||||
<file>res/bar/bg-mid.png</file>
|
||||
<file>res/bar/bg-right.png</file>
|
||||
|
||||
<file>res/bar/btn-normal-left.png</file>
|
||||
<file>res/bar/btn-normal-mid.png</file>
|
||||
<file>res/bar/btn-normal-right.png</file>
|
||||
<file>res/bar/btn-sel-left.png</file>
|
||||
<file>res/bar/btn-sel-mid.png</file>
|
||||
<file>res/bar/btn-sel-right.png</file>
|
||||
<file>res/bar/btn-hover-left.png</file>
|
||||
<file>res/bar/btn-hover-mid.png</file>
|
||||
<file>res/bar/btn-hover-right.png</file>
|
||||
|
||||
<file>res/bar/play-hover.png</file>
|
||||
<file>res/bar/play-normal.png</file>
|
||||
<file>res/bar/pause-hover.png</file>
|
||||
<file>res/bar/pause-normal.png</file>
|
||||
|
||||
<file>res/bar/prgbar-mid.png</file>
|
||||
<file>res/bar/prgbar-right.png</file>
|
||||
<file>res/bar/prgbarh-left.png</file>
|
||||
<file>res/bar/prgbarh-mid.png</file>
|
||||
|
||||
<file>res/bar/prgpt-normal.png</file>
|
||||
<file>res/bar/prgpt-hover.png</file>
|
||||
|
||||
<file>res/bar/chkbox-normal.png</file>
|
||||
<file>res/bar/chkbox-hover.png</file>
|
||||
<file>res/bar/chkbox-sel-normal.png</file>
|
||||
<file>res/bar/chkbox-sel-hover.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -0,0 +1,2 @@
|
|||
IDI_ICON1 ICON DISCARDABLE "res\\tp-player.ico"
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#include "update_data.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
UpdateData::UpdateData() : QObject(nullptr)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
|
||||
UpdateData::UpdateData(int data_type) : QObject(nullptr)
|
||||
{
|
||||
_init();
|
||||
m_data_type = data_type;
|
||||
}
|
||||
|
||||
UpdateData::UpdateData(int data_type, uint32_t time_ms) : QObject(nullptr)
|
||||
{
|
||||
_init();
|
||||
m_data_type = data_type;
|
||||
m_time_ms = time_ms;
|
||||
}
|
||||
|
||||
UpdateData::UpdateData(const TS_RECORD_HEADER& hdr) : QObject(nullptr)
|
||||
{
|
||||
_init();
|
||||
m_data_type = TYPE_HEADER_INFO;
|
||||
m_hdr = new TS_RECORD_HEADER;
|
||||
memcpy(m_hdr, &hdr, sizeof(TS_RECORD_HEADER));
|
||||
}
|
||||
|
||||
void UpdateData::_init() {
|
||||
m_data_type = TYPE_UNKNOWN;
|
||||
m_hdr = nullptr;
|
||||
m_pointer = nullptr;
|
||||
|
||||
m_data_buf = nullptr;
|
||||
m_data_len = 0;
|
||||
m_time_ms = 0;
|
||||
}
|
||||
|
||||
UpdateData::~UpdateData() {
|
||||
if(m_hdr)
|
||||
delete m_hdr;
|
||||
if(m_pointer)
|
||||
delete m_pointer;
|
||||
for(int i = 0; i < m_images.size(); ++i) {
|
||||
delete m_images[i].img;
|
||||
}
|
||||
m_images.clear();
|
||||
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
}
|
||||
|
||||
void UpdateData::set_pointer(uint32_t ts, const TS_RECORD_RDP_POINTER* p) {
|
||||
m_data_type = TYPE_POINTER;
|
||||
m_time_ms = ts;
|
||||
m_pointer = new TS_RECORD_RDP_POINTER;
|
||||
memcpy(m_pointer, p, sizeof(TS_RECORD_RDP_POINTER));
|
||||
}
|
||||
|
||||
void UpdateData::alloc_data(uint32_t len) {
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
|
||||
m_data_buf = new uint8_t[len];
|
||||
memset(m_data_buf, 0, len);
|
||||
m_data_len = len;
|
||||
}
|
||||
|
||||
void UpdateData::attach_data(const uint8_t* dat, uint32_t len) {
|
||||
if(m_data_buf)
|
||||
delete m_data_buf;
|
||||
m_data_buf = new uint8_t[len];
|
||||
memcpy(m_data_buf, dat, len);
|
||||
m_data_len = len;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef UPDATE_DATA_H
|
||||
#define UPDATE_DATA_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include "record_format.h"
|
||||
|
||||
#define TYPE_UNKNOWN 0
|
||||
#define TYPE_HEADER_INFO 1
|
||||
|
||||
#define TYPE_DISABLE_DRAW 5
|
||||
#define TYPE_ENABLE_DRAW 6
|
||||
|
||||
#define TYPE_POINTER 10
|
||||
#define TYPE_IMAGE 11
|
||||
#define TYPE_KEYFRAME 12
|
||||
#define TYPE_PLAYED_MS 20
|
||||
#define TYPE_DOWNLOAD_PERCENT 21
|
||||
#define TYPE_END 50
|
||||
#define TYPE_MESSAGE 90
|
||||
#define TYPE_ERROR 91
|
||||
|
||||
|
||||
typedef struct UPDATE_IMAGE {
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
QImage* img;
|
||||
}UPDATE_IMAGE;
|
||||
|
||||
typedef QVector<UPDATE_IMAGE> UpdateImages;
|
||||
|
||||
class UpdateData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UpdateData();
|
||||
explicit UpdateData(int data_type);
|
||||
explicit UpdateData(int data_type, uint32_t time_ms);
|
||||
explicit UpdateData(const TS_RECORD_HEADER& hdr);
|
||||
virtual ~UpdateData();
|
||||
|
||||
void set_pointer(uint32_t ts, const TS_RECORD_RDP_POINTER* p);
|
||||
|
||||
TS_RECORD_HEADER* get_header() {return m_hdr;}
|
||||
TS_RECORD_RDP_POINTER* get_pointer() {return m_pointer;}
|
||||
UpdateImages& get_images() {return m_images;}
|
||||
const UpdateImages& get_images() const {return m_images;}
|
||||
|
||||
uint32_t get_time() {return m_time_ms;}
|
||||
|
||||
void alloc_data(uint32_t len);
|
||||
void attach_data(const uint8_t* dat, uint32_t len);
|
||||
|
||||
int data_type() const {return m_data_type;}
|
||||
|
||||
uint8_t* data_buf() {return m_data_buf;}
|
||||
uint32_t data_len() const {return m_data_len;}
|
||||
|
||||
void played_ms(uint32_t ms) {m_played_ms = ms;}
|
||||
uint32_t played_ms() {return m_played_ms;}
|
||||
|
||||
void message(const QString& msg) {m_msg = msg;}
|
||||
const QString message(){return m_msg;}
|
||||
|
||||
private:
|
||||
void _init(void);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
private:
|
||||
int m_data_type;
|
||||
uint32_t m_time_ms;
|
||||
uint8_t* m_data_buf;
|
||||
uint32_t m_data_len;
|
||||
uint32_t m_played_ms;
|
||||
QString m_msg;
|
||||
|
||||
// for HEADER
|
||||
TS_RECORD_HEADER* m_hdr;
|
||||
// for POINTER
|
||||
TS_RECORD_RDP_POINTER* m_pointer;
|
||||
// for IMAGE
|
||||
UpdateImages m_images;
|
||||
};
|
||||
|
||||
class UpdateDataHelper {
|
||||
public:
|
||||
UpdateDataHelper(UpdateData* data) {
|
||||
m_data = data;
|
||||
}
|
||||
~UpdateDataHelper() {
|
||||
if(m_data)
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
private:
|
||||
UpdateData* m_data;
|
||||
};
|
||||
|
||||
|
||||
#endif // UPDATE_DATA_H
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef TP_PLAYER_UTIL_H
|
||||
#define TP_PLAYER_UTIL_H
|
||||
|
||||
#include <QTime>
|
||||
|
||||
class TimeUseTest {
|
||||
public:
|
||||
TimeUseTest() {
|
||||
m_used_ms = 0;
|
||||
m_count = 0;
|
||||
}
|
||||
~TimeUseTest() {}
|
||||
|
||||
void begin() {
|
||||
m_time.start();
|
||||
}
|
||||
void end() {
|
||||
m_count++;
|
||||
m_used_ms += m_time.elapsed();
|
||||
}
|
||||
|
||||
uint32_t used() const {return m_used_ms;}
|
||||
uint32_t count() const {return m_count;}
|
||||
|
||||
private:
|
||||
QTime m_time;
|
||||
uint32_t m_used_ms;
|
||||
uint32_t m_count;
|
||||
};
|
||||
|
||||
#define LOCAL8BIT(x) QString::fromLocal8Bit(x)
|
||||
|
||||
#endif // TP_PLAYER_UTIL_H
|
|
@ -37,8 +37,9 @@
|
|||
7AA2CD541F6AB9F10074C92B /* json_writer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7AA2CD501F6AB9F10074C92B /* json_writer.cpp */; };
|
||||
7AA2CD571F6ABA2E0074C92B /* mongoose.c in Sources */ = {isa = PBXBuildFile; fileRef = 7AA2CD561F6ABA2E0074C92B /* mongoose.c */; };
|
||||
7AA2CD591F6AC0DA0074C92B /* site in Resources */ = {isa = PBXBuildFile; fileRef = 7AA2CD581F6AC0DA0074C92B /* site */; };
|
||||
7AF9BF272199E3DE00BE5DBC /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF1F2199E31A00BE5DBC /* libssl.a */; };
|
||||
7AF9BF292199E3DF00BE5DBC /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF282199E3DF00BE5DBC /* libcrypto.a */; };
|
||||
7AAE4B242390EE5C007EDDE7 /* libmbedtls.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF222199E32B00BE5DBC /* libmbedtls.a */; };
|
||||
7AAE4B252390EE7D007EDDE7 /* libmbedcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF232199E32B00BE5DBC /* libmbedcrypto.a */; };
|
||||
7AAE4B262390EE7D007EDDE7 /* libmbedx509.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF9BF212199E32B00BE5DBC /* libmbedx509.a */; };
|
||||
A1B7B9DD1DB53ED200809327 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A1B7B9DF1DB53ED200809327 /* Localizable.strings */; };
|
||||
A1D700071A5DCE8D003563E4 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = A1D700061A5DCE8D003563E4 /* AboutWindowController.m */; };
|
||||
C149EBFE15D5214600B1F558 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C149EBFD15D5214600B1F558 /* Cocoa.framework */; };
|
||||
|
@ -107,11 +108,10 @@
|
|||
7AA2CD501F6AB9F10074C92B /* json_writer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json_writer.cpp; path = ../../../../external/jsoncpp/src/lib_json/json_writer.cpp; sourceTree = "<group>"; };
|
||||
7AA2CD561F6ABA2E0074C92B /* mongoose.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mongoose.c; path = ../../../../external/mongoose/mongoose.c; sourceTree = "<group>"; };
|
||||
7AA2CD581F6AC0DA0074C92B /* site */ = {isa = PBXFileReference; lastKnownFileType = folder; path = site; sourceTree = "<group>"; };
|
||||
7AF9BF1F2199E31A00BE5DBC /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = ../../external/macos/release/lib/libssl.a; sourceTree = "<group>"; };
|
||||
7AAE4B232390E642007EDDE7 /* mongoose.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mongoose.h; path = ../../../../external/mongoose/mongoose.h; sourceTree = "<group>"; };
|
||||
7AF9BF212199E32B00BE5DBC /* libmbedx509.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedx509.a; path = ../../external/macos/release/lib/libmbedx509.a; sourceTree = "<group>"; };
|
||||
7AF9BF222199E32B00BE5DBC /* libmbedtls.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedtls.a; path = ../../external/macos/release/lib/libmbedtls.a; sourceTree = "<group>"; };
|
||||
7AF9BF232199E32B00BE5DBC /* libmbedcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedcrypto.a; path = ../../external/macos/release/lib/libmbedcrypto.a; sourceTree = "<group>"; };
|
||||
7AF9BF282199E3DF00BE5DBC /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = ../../external/macos/release/lib/libcrypto.a; sourceTree = "<group>"; };
|
||||
A1B7B9D31DB5361700809327 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
A1B7B9DE1DB53ED200809327 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
A1B7B9E01DB53ED700809327 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
|
@ -143,8 +143,9 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C149EBFE15D5214600B1F558 /* Cocoa.framework in Frameworks */,
|
||||
7AF9BF292199E3DF00BE5DBC /* libcrypto.a in Frameworks */,
|
||||
7AF9BF272199E3DE00BE5DBC /* libssl.a in Frameworks */,
|
||||
7AAE4B262390EE7D007EDDE7 /* libmbedx509.a in Frameworks */,
|
||||
7AAE4B252390EE7D007EDDE7 /* libmbedcrypto.a in Frameworks */,
|
||||
7AAE4B242390EE5C007EDDE7 /* libmbedtls.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -225,6 +226,7 @@
|
|||
7AA2CD551F6ABA000074C92B /* mongoose */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AAE4B232390E642007EDDE7 /* mongoose.h */,
|
||||
7AA2CD561F6ABA2E0074C92B /* mongoose.c */,
|
||||
);
|
||||
name = mongoose;
|
||||
|
@ -248,13 +250,6 @@
|
|||
path = csrc;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7AF9BF1E2199E0DD00BE5DBC /* mbedtls */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = mbedtls;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A12D9BE61BCF2C72004F52A6 /* apple-scpt */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -286,11 +281,9 @@
|
|||
C149EBFC15D5214600B1F558 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AF9BF282199E3DF00BE5DBC /* libcrypto.a */,
|
||||
7AF9BF232199E32B00BE5DBC /* libmbedcrypto.a */,
|
||||
7AF9BF222199E32B00BE5DBC /* libmbedtls.a */,
|
||||
7AF9BF212199E32B00BE5DBC /* libmbedx509.a */,
|
||||
7AF9BF1F2199E31A00BE5DBC /* libssl.a */,
|
||||
C149EBFD15D5214600B1F558 /* Cocoa.framework */,
|
||||
C149EBFF15D5214600B1F558 /* Other Frameworks */,
|
||||
);
|
||||
|
@ -310,7 +303,6 @@
|
|||
C149EC0315D5214600B1F558 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7AF9BF1E2199E0DD00BE5DBC /* mbedtls */,
|
||||
7A45423D2196E32800FEB5B4 /* cfg */,
|
||||
7AD3E8741F6A7CC600D2EB48 /* csrc */,
|
||||
A12D9BE61BCF2C72004F52A6 /* apple-scpt */,
|
||||
|
@ -367,7 +359,7 @@
|
|||
C149EBF015D5214600B1F558 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0930;
|
||||
LastUpgradeCheck = 1120;
|
||||
ORGANIZATIONNAME = TP4A;
|
||||
TargetAttributes = {
|
||||
C149EBF815D5214600B1F558 = {
|
||||
|
@ -381,7 +373,7 @@
|
|||
};
|
||||
buildConfigurationList = C149EBF315D5214600B1F558 /* Build configuration list for PBXProject "TP-Assist" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
|
@ -606,13 +598,14 @@
|
|||
C149EC1815D5214600B1F558 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "src/TP-Assist-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
MG_ENABLE_SSL,
|
||||
"MG_SSL_IF=MG_SSL_IF_MBEDTLS",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../common/teleport,
|
||||
|
@ -634,11 +627,14 @@
|
|||
C149EC1915D5214600B1F558 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "src/TP-Assist-Prefix.pch";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = MG_ENABLE_SSL;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
MG_ENABLE_SSL,
|
||||
"MG_SSL_IF=MG_SSL_IF_MBEDTLS",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../../common/teleport,
|
||||
../../common/libex/include,
|
||||
|
|
|
@ -6,58 +6,17 @@ on scriptRun(argsCmd, argsProfile, argsTitle)
|
|||
end scriptRun
|
||||
|
||||
on CommandRun(theCmd, theProfile, theTitle)
|
||||
tell application "iTerm"
|
||||
if it is not running then
|
||||
tell application "iTerm"
|
||||
activate
|
||||
delay 0.5
|
||||
try
|
||||
close first window
|
||||
end try
|
||||
end tell
|
||||
|
||||
tell application "iTerm"
|
||||
try
|
||||
create window with profile theProfile
|
||||
on error msg
|
||||
create window with profile "Default"
|
||||
end try
|
||||
tell the current window
|
||||
tell the current session
|
||||
delay 0.5
|
||||
set name to theTitle
|
||||
set profile to theProfile
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
else
|
||||
--assume that iTerm is open and open a new tab
|
||||
try
|
||||
try
|
||||
tell application "iTerm"
|
||||
if it is not running then
|
||||
tell application "iTerm"
|
||||
activate
|
||||
tell the current window
|
||||
try
|
||||
create tab with profile theProfile
|
||||
on error msg
|
||||
create tab with profile "Default"
|
||||
end try
|
||||
tell the current tab
|
||||
tell the current session
|
||||
delay 0.5
|
||||
set name to theTitle
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
delay 0.5
|
||||
try
|
||||
close first window
|
||||
end try
|
||||
end tell
|
||||
on error msg
|
||||
-- if all iTerm windows are closed the app stays open. In this scenario iTerm has
|
||||
-- no "current window" and will give an error when trying to create the new tab.
|
||||
|
||||
tell application "iTerm"
|
||||
try
|
||||
create window with profile theProfile
|
||||
|
@ -68,13 +27,59 @@ on CommandRun(theCmd, theProfile, theTitle)
|
|||
tell the current session
|
||||
delay 0.5
|
||||
set name to theTitle
|
||||
set profile to theProfile
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
end try
|
||||
end if
|
||||
end tell
|
||||
else
|
||||
--assume that iTerm is open and open a new tab
|
||||
try
|
||||
tell application "iTerm"
|
||||
activate
|
||||
tell the current window
|
||||
try
|
||||
create tab with profile theProfile
|
||||
on error msg
|
||||
create tab with profile "Default"
|
||||
end try
|
||||
tell the current tab
|
||||
tell the current session
|
||||
delay 0.5
|
||||
set name to theTitle
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
on error msg
|
||||
-- if all iTerm windows are closed the app stays open. In this scenario iTerm has
|
||||
-- no "current window" and will give an error when trying to create the new tab.
|
||||
tell application "iTerm"
|
||||
try
|
||||
create window with profile theProfile
|
||||
on error msg
|
||||
create window with profile "Default"
|
||||
end try
|
||||
tell the current window
|
||||
tell the current session
|
||||
delay 0.5
|
||||
set name to theTitle
|
||||
write text theCmd
|
||||
delay 0.5
|
||||
write text ""
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
end try
|
||||
end if
|
||||
end tell
|
||||
on error msg
|
||||
display dialog "ERROR: " & msg
|
||||
end try
|
||||
|
||||
end CommandRun
|
||||
|
|
|
@ -1,76 +1,83 @@
|
|||
on scriptRun(argsCmd, argsProfile, argsTitle)
|
||||
set theCmd to (argsCmd)
|
||||
set theCmd to (argsCmd)
|
||||
set theProfile to (argsProfile)
|
||||
set theTitle to (argsTitle)
|
||||
CommandRun(theCmd, theProfile, theTitle)
|
||||
end scriptRun
|
||||
|
||||
on CommandRun(theCmd, theProfile, theTitle)
|
||||
tell application "Terminal"
|
||||
if it is not running then
|
||||
--if this is the first time Terminal is running you have specify window 1
|
||||
--if you dont do this you will get two windows and the title wont be set
|
||||
activate
|
||||
delay 1.0
|
||||
set newTerm to do script theCmd in window 1
|
||||
set newTerm's current settings to settings set theProfile
|
||||
set custom title of front window to theTitle
|
||||
|
||||
delay 1.0
|
||||
reopen
|
||||
activate
|
||||
tell application "System Events" to key code 36
|
||||
else
|
||||
--Terminal is running get the window count
|
||||
set windowCount to (count every window)
|
||||
if windowCount = 0 then
|
||||
--Terminal is running but no windows are open
|
||||
--run our script in a new window
|
||||
try
|
||||
tell application "Terminal"
|
||||
if it is not running then
|
||||
--if this is the first time Terminal is running you have specify window 1
|
||||
--if you dont do this you will get two windows and the title wont be set
|
||||
activate
|
||||
delay 3.0
|
||||
set newTerm to do script theCmd in window 1
|
||||
set newTerm's current settings to settings set theProfile
|
||||
set custom title of front window to theTitle
|
||||
|
||||
delay 1.0
|
||||
reopen
|
||||
activate
|
||||
|
||||
do script theCmd in window 1
|
||||
|
||||
set current settings of selected tab of front window to settings set theProfile
|
||||
set title displays custom title of front window to true
|
||||
set custom title of selected tab of front window to theTitle
|
||||
|
||||
delay 1.0
|
||||
reopen
|
||||
activate
|
||||
tell application "System Events" to key code 36
|
||||
|
||||
tell application "System Events" to key code 36
|
||||
else
|
||||
--Terminal is running and we have a window run in a new tab
|
||||
reopen
|
||||
activate
|
||||
|
||||
tell application "System Events"
|
||||
tell process "Terminal"
|
||||
delay 0.5
|
||||
keystroke "t" using {command down}
|
||||
--Terminal is running get the window count
|
||||
set windowCount to (count every window)
|
||||
if windowCount = 0 then
|
||||
--Terminal is running but no windows are open
|
||||
--run our script in a new window
|
||||
reopen
|
||||
activate
|
||||
|
||||
do script theCmd in window 1
|
||||
|
||||
set current settings of selected tab of front window to settings set theProfile
|
||||
set title displays custom title of front window to true
|
||||
set custom title of selected tab of front window to theTitle
|
||||
|
||||
delay 1.0
|
||||
reopen
|
||||
activate
|
||||
tell application "System Events" to key code 36
|
||||
|
||||
else
|
||||
--Terminal is running and we have a window run in a new tab
|
||||
reopen
|
||||
activate
|
||||
|
||||
tell application "System Events"
|
||||
tell process "Terminal"
|
||||
delay 0.5
|
||||
keystroke "t" using {command down}
|
||||
end tell
|
||||
end tell
|
||||
end tell
|
||||
|
||||
reopen
|
||||
activate
|
||||
do script theCmd in front window
|
||||
|
||||
set current settings of selected tab of front window to settings set theProfile
|
||||
set title displays custom title of front window to true
|
||||
set custom title of selected tab of front window to theTitle
|
||||
|
||||
delay 1.0
|
||||
reopen
|
||||
activate
|
||||
tell application "System Events" to key code 36
|
||||
|
||||
|
||||
reopen
|
||||
activate
|
||||
do script theCmd in front window
|
||||
|
||||
set current settings of selected tab of front window to settings set theProfile
|
||||
set title displays custom title of front window to true
|
||||
set custom title of selected tab of front window to theTitle
|
||||
|
||||
delay 1.0
|
||||
reopen
|
||||
activate
|
||||
tell application "System Events" to key code 36
|
||||
|
||||
end if
|
||||
|
||||
--set current settings of selected tab of front window to settings set theProfile
|
||||
--set title displays custom title of front window to true
|
||||
--set custom title of selected tab of front window to theTitle
|
||||
end if
|
||||
|
||||
# set current settings of selected tab of front window to settings set theProfile
|
||||
# set title displays custom title of front window to true
|
||||
# set custom title of selected tab of front window to theTitle
|
||||
end if
|
||||
|
||||
end tell
|
||||
|
||||
end tell
|
||||
|
||||
on error msg
|
||||
display dialog "ERROR: " & msg
|
||||
end try
|
||||
|
||||
|
||||
end CommandRun
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
<div class="footer">
|
||||
<div class="container">
|
||||
<p><a href="https://tp4a.com/" target="_blank">TELEPORT</a> | ©2015 - 2018,保留所有权利。</p>
|
||||
<p><a href="https://tp4a.com/" target="_blank">TELEPORT</a> | ©2015 - 2020,保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
<!DOCTYPE html>
|
||||
<!--[if IE 8]>
|
||||
<html lang="en" class="ie8"><![endif]-->
|
||||
<!--[if !IE]><!-->
|
||||
<html lang="zh_CN">
|
||||
<!--<![endif]-->
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>TELEPORT助手</title>
|
||||
<link rel="shortcut icon" href="favicon.png">
|
||||
|
||||
<link href="plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="css/style.css" rel="stylesheet" type="text/css" />
|
||||
|
||||
<style type="text/css">
|
||||
.info-box {
|
||||
padding:20px;
|
||||
margin:40px;
|
||||
border:1px solid #78b17c;
|
||||
background-color:#e4ffe5;
|
||||
font-size: 140%;
|
||||
}
|
||||
.warning-box {
|
||||
padding:20px;
|
||||
margin:40px;
|
||||
border:1px solid #eac781;
|
||||
background-color: #f9f5d7;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="header">
|
||||
<div class="container">
|
||||
<span class="title"><i class="fa fa-cog fa-fw"></i> Teleport 助手</span>
|
||||
<span class="sub-title" id="version"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-fix"></div>
|
||||
|
||||
<div class="footer">
|
||||
<div class="container">
|
||||
<p><a href="https://tp4a.com/" target="_blank">TELEPORT</a> | ©2015 - 2020,保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="content">
|
||||
|
||||
<div class="info-box">
|
||||
Teleport助手工作正常!
|
||||
</div>
|
||||
|
||||
<div class="warning-box">
|
||||
<p>如果在使用 HTTPS 方式访问 teleport 的 web 服务时检测不到助手,请<a href="https://127.0.0.1:50023" target="_blank">点击这里</a>,查看页面是否能够正常显示。</p>
|
||||
<p>因为助手在配合HTTPS访问时使用了<strong>自签名证书</strong>,而自签名证书的颁发机构的根证书<strong>默认不被浏览器信任</strong>,因此,还<strong>需要将其设置为浏览器信任的根证书</strong>才行,根据浏览器的不同,具体设置方法有两种:</p>
|
||||
<p><strong>Chrome/IE/Edge/Opera 等浏览器</strong></p>
|
||||
<ol>
|
||||
<li>在桌面的助手快捷方式上点击右键,然后选择“打开文件所在的位置”;</li>
|
||||
<li>右键点击 <strong>cacert.cer</strong>,在弹出菜单中选择“安装证书”;</li>
|
||||
<li>在打开的“证书导入向导”对话框中选择“当前用户”,点击下一步;</li>
|
||||
<li>选择“将所有的证书都放入下列存储”,然后点击“浏览”按钮;</li>
|
||||
<li>在打开的“选择证书存储”对话框中选择<strong>“受信任的根证书颁发机构”</strong>,点击确定;</li>
|
||||
<li>点击“下一步”,然后点击“完成”;</li>
|
||||
<li>系统提示“导入成功”,大功告成。</li>
|
||||
</ol>
|
||||
|
||||
<p><strong>FireFox火狐浏览器</strong></p>
|
||||
<ol>
|
||||
<li>打开火狐浏览器的选项页面;</li>
|
||||
<li>点击左侧的“隐私与安全”,然后滚动页面到底部,点击“查看证书”按钮;</li>
|
||||
<li>在打开的“证书管理器”对话框中选择“证书颁发机构”选项卡;</li>
|
||||
<li>点击对话框底部的“导入”按钮,然后选择 <strong>cacert.cer</strong> 文件并点击“打开”按钮;</li>
|
||||
<li>在“下载证书”对话框中,勾选“信任由此证书颁发机构来标识网站”,然后点击“确定”;</li>
|
||||
<li>点击“确定”来关闭证书管理器对话框,大功告成。</li>
|
||||
</ol>
|
||||
|
||||
<p><strong>注意:</strong>导入证书后,请再次<a href="https://127.0.0.1:50023" target="_blank">点击这里</a>,查看页面是否能够正常显示。</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.31"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15505"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
@ -19,61 +19,61 @@
|
|||
<window title="About Teleport Assist" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="750" y="574" width="315" height="204"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2048" height="1129"/>
|
||||
<rect key="contentRect" x="750" y="574" width="329" height="217"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1057"/>
|
||||
<view key="contentView" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="315" height="204"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="329" height="217"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6kW-hd-spe">
|
||||
<rect key="frame" x="125" y="126" width="64" height="64"/>
|
||||
<rect key="frame" x="125" y="133" width="64" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" animates="YES" imageAlignment="top" imageScaling="proportionallyDown" image="teleport" id="VBv-EA-L5r"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="APf-vF-1w0">
|
||||
<rect key="frame" x="18" y="99" width="279" height="17"/>
|
||||
<rect key="frame" x="18" y="91" width="293" height="28"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Program Name and Tag Line" id="tb3-eK-HAT">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" allowsUndo="NO" sendsActionOnEndEditing="YES" alignment="center" title="Program Name and Tag Line" id="tb3-eK-HAT">
|
||||
<font key="font" metaFont="system" size="18"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LTk-GB-fgJ">
|
||||
<rect key="frame" x="18" y="73" width="279" height="17"/>
|
||||
<rect key="frame" x="18" y="76" width="293" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Version" id="6fl-Xm-UPS">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rfT-bT-B7g">
|
||||
<rect key="frame" x="18" y="40" width="293" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Copyright" id="Cmu-CQ-3V9">
|
||||
<font key="font" metaFont="system" size="10"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="soF-wq-5hG">
|
||||
<rect key="frame" x="14" y="13" width="287" height="32"/>
|
||||
<rect key="frame" x="14" y="13" width="301" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Homepage" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uUM-88-32s">
|
||||
<buttonCell key="cell" type="push" title="url" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="uUM-88-32s">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<font key="font" metaFont="system" size="12"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="btnHomepage:" target="-2" id="ZGb-bg-pCR"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rfT-bT-B7g">
|
||||
<rect key="frame" x="18" y="51" width="279" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Copyright" id="Cmu-CQ-3V9">
|
||||
<font key="font" metaFont="system" size="10"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="50.5" y="233"/>
|
||||
<point key="canvasLocation" x="57.5" y="239.5"/>
|
||||
</window>
|
||||
</objects>
|
||||
<resources>
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
TPAssist
|
||||
*/
|
||||
|
||||
"app_name" = "Teleport助手";
|
||||
"app_name" = "Teleport Assist";
|
||||
|
||||
//=============================================
|
||||
// for About Window
|
||||
//=============================================
|
||||
"version" = "Version: ";
|
||||
"app_full_name" = "Teleport Assist for macOS";
|
||||
"copyright" = "Copyright © 2017~2018 TP4A. All rights reserved.";
|
||||
"version" = "";
|
||||
"app_full_name" = "Teleport Assist";
|
||||
"copyright" = "Copyright © 2017~2019, tp4a.com. All rights reserved.";
|
||||
"visit_tp4a_website" = "Visit Teleport Website"
|
||||
|
|
|
@ -17,19 +17,21 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.2.0</string>
|
||||
<string>3.5.5</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>3.2.0</string>
|
||||
<string>3.5.5</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.productivity</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSAppleEventsUsageDescription</key>
|
||||
<string></string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2017~2018 TP4A. All rights reserved.</string>
|
||||
<string>Copyright © 2017~2019, tp4a.com. All rights reserved.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
|
|
@ -41,9 +41,12 @@ bool TsCfg::save(const ex_astr& new_value)
|
|||
if(!_load(new_value))
|
||||
return false;
|
||||
|
||||
Json::StyledWriter jwriter;
|
||||
ex_astr val = jwriter.write(m_root);
|
||||
|
||||
Json::StreamWriterBuilder jwb;
|
||||
std::unique_ptr<Json::StreamWriter> jwriter(jwb.newStreamWriter());
|
||||
ex_aoss os;
|
||||
jwriter->write(m_root, &os);
|
||||
ex_astr val = os.str();
|
||||
|
||||
if(!ex_write_text_file(g_env.m_cfg_file, val)) {
|
||||
EXLOGE("can not save config file.\n");
|
||||
return false;
|
||||
|
@ -123,12 +126,21 @@ bool TsCfg::_parse_app(const Json::Value& m_root, const ex_astr& str_app, APP_CO
|
|||
|
||||
|
||||
bool TsCfg::_load(const ex_astr& str_json) {
|
||||
Json::Reader jreader;
|
||||
// Json::Reader jreader;
|
||||
//
|
||||
// if (!jreader.parse(str_json.c_str(), m_root)) {
|
||||
// EXLOGE("can not parse new config data, not in json format?\n");
|
||||
// return false;
|
||||
// }
|
||||
Json::CharReaderBuilder jcrb;
|
||||
std::unique_ptr<Json::CharReader> const jreader(jcrb.newCharReader());
|
||||
const char *str_json_begin = str_json.c_str();
|
||||
|
||||
if (!jreader.parse(str_json.c_str(), m_root)) {
|
||||
EXLOGE("can not parse new config data, not in json format?\n");
|
||||
return false;
|
||||
}
|
||||
ex_astr err;
|
||||
if (!jreader->parse(str_json_begin, str_json_begin + str_json.length(), &m_root, &err)) {
|
||||
EXLOGE("can not parse new config data, not in json format? %s\n", err.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
//===================================
|
||||
// check ssh config
|
||||
|
|
|
@ -32,3 +32,11 @@ bool TsEnv::init(const char* cfg_file, const char* res_path)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int mg_ssl_if_mbed_random(void *ctx, unsigned char *buf, size_t len) {
|
||||
(void) ctx;
|
||||
while (len--) *buf++ = (arc4random() % 255);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ int http_rpc_start(void* app) {
|
|||
EXLOGE("[ERROR] can not start HTTP-RPC listener, maybe port %d is already in use.\n", TS_HTTP_RPC_PORT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EXLOGW("[rpc] TeleportAssist-HTTP-RPC ready on localhost:%d\n", TS_HTTP_RPC_PORT);
|
||||
|
||||
|
||||
EXLOGW("[rpc] TeleportAssist-HTTP-RPC ready on 127.0.0.1:%d\n", TS_HTTP_RPC_PORT);
|
||||
|
||||
if(!g_http_interface.start())
|
||||
return -2;
|
||||
|
||||
|
@ -43,9 +43,9 @@ int http_rpc_start(void* app) {
|
|||
EXLOGE("[ERROR] can not start HTTPS-RPC listener, maybe port %d is already in use.\n", TS_HTTPS_RPC_PORT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
EXLOGW("[rpc] TeleportAssist-HTTPS-RPC ready on localhost:%d\n", TS_HTTPS_RPC_PORT);
|
||||
|
||||
|
||||
EXLOGW("[rpc] TeleportAssist-HTTPS-RPC ready on 127.0.0.1:%d\n", TS_HTTPS_RPC_PORT);
|
||||
|
||||
if(!g_https_interface.start())
|
||||
return -2;
|
||||
|
||||
|
@ -106,22 +106,21 @@ TsHttpRpc::~TsHttpRpc()
|
|||
mg_mgr_free(&m_mg_mgr);
|
||||
}
|
||||
|
||||
bool TsHttpRpc::init_http()
|
||||
{
|
||||
|
||||
char addr[128] = { 0 };
|
||||
ex_strformat(addr, 128, "tcp://localhost:%d", TS_HTTP_RPC_PORT);
|
||||
|
||||
bool TsHttpRpc::init_http() {
|
||||
struct mg_connection* nc = NULL;
|
||||
|
||||
char addr[128] = { 0 };
|
||||
ex_strformat(addr, 128, "tcp://127.0.0.1:%d", TS_HTTP_RPC_PORT);
|
||||
|
||||
nc = mg_bind(&m_mg_mgr, addr, _mg_event_handler);
|
||||
if (nc == NULL) {
|
||||
EXLOGE("[rpc] TsHttpRpc::init_http() localhost:%d\n", TS_HTTP_RPC_PORT);
|
||||
if (!nc) {
|
||||
EXLOGE("[rpc] TsHttpRpc::init 127.0.0.1:%d\n", TS_HTTP_RPC_PORT);
|
||||
return false;
|
||||
}
|
||||
nc->user_data = this;
|
||||
|
||||
|
||||
mg_set_protocol_http_websocket(nc);
|
||||
|
||||
|
||||
return _on_init();
|
||||
}
|
||||
|
||||
|
@ -135,27 +134,27 @@ bool TsHttpRpc::init_https()
|
|||
ex_wstr2astr(file_ssl_cert, _ssl_cert);
|
||||
ex_astr _ssl_key;
|
||||
ex_wstr2astr(file_ssl_key, _ssl_key);
|
||||
|
||||
|
||||
const char *err = NULL;
|
||||
struct mg_bind_opts bind_opts;
|
||||
memset(&bind_opts, 0, sizeof(bind_opts));
|
||||
bind_opts.ssl_cert = _ssl_cert.c_str();
|
||||
bind_opts.ssl_key = _ssl_key.c_str();
|
||||
bind_opts.error_string = &err;
|
||||
|
||||
|
||||
char addr[128] = { 0 };
|
||||
ex_strformat(addr, 128, "tcp://localhost:%d", TS_HTTPS_RPC_PORT);
|
||||
ex_strformat(addr, 128, "tcp://127.0.0.1:%d", TS_HTTPS_RPC_PORT);
|
||||
|
||||
struct mg_connection* nc = NULL;
|
||||
nc = mg_bind_opt(&m_mg_mgr, addr, _mg_event_handler, bind_opts);
|
||||
if (nc == NULL) {
|
||||
EXLOGE("[rpc] TsHttpRpc::init_https() localhost:%d\n", TS_HTTPS_RPC_PORT);
|
||||
if (!nc) {
|
||||
EXLOGE("[rpc] TsHttpRpc::init 127.0.0.1:%d\n", TS_HTTPS_RPC_PORT);
|
||||
return false;
|
||||
}
|
||||
nc->user_data = this;
|
||||
|
||||
|
||||
mg_set_protocol_http_websocket(nc);
|
||||
|
||||
|
||||
return _on_init();
|
||||
}
|
||||
|
||||
|
@ -182,7 +181,7 @@ void TsHttpRpc::_thread_loop(void)
|
|||
{
|
||||
mg_mgr_poll(&m_mg_mgr, 500);
|
||||
}
|
||||
|
||||
|
||||
EXLOGV("[core] rpc main loop end.\n");
|
||||
}
|
||||
|
||||
|
@ -225,23 +224,25 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat
|
|||
EXLOGV("[rpc] got %s request: %s\n", dbg_method, uri.c_str());
|
||||
#endif
|
||||
ex_astr ret_buf;
|
||||
bool b_is_index = false;
|
||||
bool b_is_html = false;
|
||||
|
||||
if (uri == "/")
|
||||
{
|
||||
ex_wstr page = L"<html lang=\"zh_CN\"><head><meta charset=\"utf-8\"/><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><title>Teleport Assistor</title>\n<style type=\"text/css\">\n.box{padding:20px;margin:40px;border:1px solid #78b17c;background-color:#e4ffe5;}\n</style>\n</head><body><div class=\"box\">Teleport Assistor works fine.</div></body></html>";
|
||||
ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8);
|
||||
// if (uri == "/") {
|
||||
// ex_wstr page = L"<html lang=\"zh_CN\"><head><meta charset=\"utf-8\"/><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><title>TeleportÖúÊÖ</title>\n<style type=\"text/css\">\n.box{padding:20px;margin:40px;border:1px solid #78b17c;background-color:#e4ffe5;}\n</style>\n</head><body><div class=\"box\">Teleport Assistor works fine.</div></body></html>";
|
||||
// ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8);
|
||||
//
|
||||
// mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]);
|
||||
// nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
// return;
|
||||
// }
|
||||
|
||||
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]);
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uri == "/config")
|
||||
{
|
||||
uri = "/index.html";
|
||||
b_is_index = true;
|
||||
}
|
||||
if (uri == "/") {
|
||||
uri = "/status.html";
|
||||
b_is_html = true;
|
||||
}
|
||||
else if (uri == "/config") {
|
||||
uri = "/index.html";
|
||||
b_is_html = true;
|
||||
}
|
||||
|
||||
ex_astr temp;
|
||||
size_t offset = uri.find("/", 1);
|
||||
|
@ -262,24 +263,24 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat
|
|||
{
|
||||
_this->_process_js_request(method, json_param, ret_buf);
|
||||
}
|
||||
|
||||
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]);
|
||||
|
||||
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: application/json\r\n\r\n%s", ret_buf.length(), ret_buf.c_str());
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ex_astr file_suffix;
|
||||
offset = uri.rfind(".");
|
||||
if (offset > 0)
|
||||
{
|
||||
file_suffix = uri.substr(offset, uri.length());
|
||||
}
|
||||
|
||||
|
||||
ex_wstr2astr(g_env.m_site_path, temp);
|
||||
ex_astr index_path = temp + uri;
|
||||
|
||||
|
||||
|
||||
FILE* file = ex_fopen(index_path.c_str(), "rb");
|
||||
if (file)
|
||||
|
@ -295,25 +296,23 @@ void TsHttpRpc::_mg_event_handler(struct mg_connection *nc, int ev, void *ev_dat
|
|||
fseek(file, 0, SEEK_SET);
|
||||
ret = fread(buf, 1, file_size, file);
|
||||
fclose(file);
|
||||
|
||||
|
||||
ex_astr content_type = _this->get_content_type(file_suffix);
|
||||
|
||||
|
||||
mg_printf(nc, "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: %s\r\n\r\n", file_size, content_type.c_str());
|
||||
mg_send(nc, buf, (int)file_size);
|
||||
delete []buf;
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
return;
|
||||
}
|
||||
else if (b_is_index)
|
||||
{
|
||||
} else if (b_is_html) {
|
||||
ex_wstr page = L"<html lang=\"zh_CN\"><html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>404 Not Found</h1></center><hr><center><p>Teleport Assistor configuration page not found.</p></center></body></html>";
|
||||
ex_wstr2astr(page, ret_buf, EX_CODEPAGE_UTF8);
|
||||
|
||||
mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.size() - 1, &ret_buf[0]);
|
||||
|
||||
mg_printf(nc, "HTTP/1.0 404 File Not Found\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %ld\r\nContent-Type: text/html\r\n\r\n%s", ret_buf.length(), ret_buf.c_str());
|
||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -336,7 +335,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as
|
|||
|
||||
ex_astrs strs;
|
||||
|
||||
size_t pos_start = 1; // 跳过第一个字节,一定是 '/'
|
||||
size_t pos_start = 1; // skip first charactor, it must be '/'
|
||||
|
||||
size_t i = 0;
|
||||
for (i = pos_start; i < req->uri.len; ++i)
|
||||
|
@ -349,7 +348,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as
|
|||
tmp_uri.assign(req->uri.p + pos_start, i - pos_start);
|
||||
strs.push_back(tmp_uri);
|
||||
}
|
||||
pos_start = i + 1; // 跳过当前找到的分隔符
|
||||
pos_start = i + 1; // skip current split chactor.
|
||||
}
|
||||
}
|
||||
if (pos_start < req->uri.len)
|
||||
|
@ -397,7 +396,7 @@ int TsHttpRpc::_parse_request(struct http_message* req, ex_astr& func_cmd, ex_as
|
|||
|
||||
if (func_args.length() > 0)
|
||||
{
|
||||
// 将参数进行 url-decode 解码
|
||||
// decode param with url-decode.
|
||||
size_t len = func_args.length() * 2;
|
||||
ex_chars sztmp;
|
||||
sztmp.resize(len);
|
||||
|
@ -448,44 +447,50 @@ void TsHttpRpc::_process_js_request(const ex_astr& func_cmd, const ex_astr& func
|
|||
|
||||
void TsHttpRpc::_create_json_ret(ex_astr& buf, int errcode)
|
||||
{
|
||||
// 返回: {"code":123}
|
||||
// return {"code":123}
|
||||
|
||||
Json::FastWriter jr_writer;
|
||||
Json::Value jr_root;
|
||||
|
||||
jr_root["code"] = errcode;
|
||||
buf = jr_writer.write(jr_root);
|
||||
Json::StreamWriterBuilder jwb;
|
||||
std::unique_ptr<Json::StreamWriter> jwriter(jwb.newStreamWriter());
|
||||
ex_aoss os;
|
||||
jwriter->write(jr_root, &os);
|
||||
buf = os.str();
|
||||
}
|
||||
|
||||
void TsHttpRpc::_create_json_ret(ex_astr& buf, Json::Value& jr_root)
|
||||
{
|
||||
Json::FastWriter jr_writer;
|
||||
buf = jr_writer.write(jr_root);
|
||||
Json::StreamWriterBuilder jwb;
|
||||
std::unique_ptr<Json::StreamWriter> jwriter(jwb.newStreamWriter());
|
||||
ex_aoss os;
|
||||
jwriter->write(jr_root, &os);
|
||||
buf = os.str();
|
||||
}
|
||||
|
||||
void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
||||
{
|
||||
// 入参:{"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2}
|
||||
void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf) {
|
||||
// param: {"ip":"192.168.5.11","port":22,"uname":"root","uauth":"abcdefg","authmode":1,"protocol":2}
|
||||
// authmode: 1=password, 2=private-key
|
||||
// protocol: 1=rdp, 2=ssh
|
||||
// SSH返回: {"code":0, "data":{"sid":"0123abcde"}}
|
||||
// RDP返回: {"code":0, "data":{"sid":"0123abcde0A"}}
|
||||
// SSH return {"code":0, "data":{"sid":"0123abcde"}}
|
||||
// RDP return {"code":0, "data":{"sid":"0123abcde0A"}}
|
||||
|
||||
Json::Reader jreader;
|
||||
Json::Value jsRoot;
|
||||
Json::CharReaderBuilder jcrb;
|
||||
std::unique_ptr<Json::CharReader> const jreader(jcrb.newCharReader());
|
||||
const char *str_json_begin = func_args.c_str();
|
||||
|
||||
if (!jreader.parse(func_args.c_str(), jsRoot))
|
||||
{
|
||||
_create_json_ret(buf, TPE_JSON_FORMAT);
|
||||
return;
|
||||
}
|
||||
Json::Value jsRoot;
|
||||
ex_astr err;
|
||||
if (!jreader->parse(str_json_begin, str_json_begin + func_args.length(), &jsRoot, &err)) {
|
||||
_create_json_ret(buf, TPE_JSON_FORMAT);
|
||||
return;
|
||||
}
|
||||
if (!jsRoot.isObject())
|
||||
{
|
||||
_create_json_ret(buf, TPE_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断参数是否正确
|
||||
// check param
|
||||
if (!jsRoot["teleport_ip"].isString()
|
||||
|| !jsRoot["teleport_port"].isNumeric() || !jsRoot["remote_host_ip"].isString()
|
||||
|| !jsRoot["session_id"].isString() || !jsRoot["protocol_type"].isNumeric() || !jsRoot["protocol_sub_type"].isNumeric()
|
||||
|
@ -512,10 +517,9 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
ex_astr s_exec;
|
||||
ex_astr s_arg;
|
||||
ex_astrs s_argv;
|
||||
|
||||
|
||||
if (pro_type == TP_PROTOCOL_TYPE_RDP)
|
||||
{
|
||||
|
||||
|
||||
if (pro_type == TP_PROTOCOL_TYPE_RDP) {
|
||||
//==============================================
|
||||
// RDP
|
||||
//==============================================
|
||||
|
@ -524,10 +528,10 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
_create_json_ret(buf, TPE_NOT_EXISTS);
|
||||
return;
|
||||
}
|
||||
|
||||
bool flag_clipboard = (protocol_flag & TP_FLAG_RDP_CLIPBOARD);
|
||||
bool flag_disk = (protocol_flag & TP_FLAG_RDP_DISK);
|
||||
bool flag_console = (protocol_flag & TP_FLAG_RDP_CONSOLE);
|
||||
|
||||
bool flag_clipboard = ((protocol_flag & TP_FLAG_RDP_CLIPBOARD) == TP_FLAG_RDP_CLIPBOARD);
|
||||
bool flag_disk = ((protocol_flag & TP_FLAG_RDP_DISK) == TP_FLAG_RDP_DISK);
|
||||
bool flag_console = ((protocol_flag & TP_FLAG_RDP_CONSOLE) == TP_FLAG_RDP_CONSOLE);
|
||||
|
||||
int rdp_w = 800;
|
||||
int rdp_h = 640;
|
||||
|
@ -578,9 +582,9 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
{
|
||||
szPwd[i] = '*';
|
||||
}
|
||||
|
||||
|
||||
//ex_astr2wstr(real_sid, w_sid);
|
||||
|
||||
|
||||
//w_exe_path = _T("\"");
|
||||
//w_exe_path += g_cfg.rdp_app + _T("\" ");
|
||||
//w_exe_path += g_cfg.rdp_cmdline;
|
||||
|
@ -589,24 +593,49 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
//w_exe_path = _T("xfreerdp -u {user_name} {size} {console} ");
|
||||
//s_exec = "/usr/local/Cellar/freerdp/1.0.2_1/bin/xfreerdp";
|
||||
s_exec = g_cfg.rdp.application;
|
||||
s_argv.push_back(s_exec.c_str());
|
||||
s_arg = g_cfg.rdp.cmdline;
|
||||
|
||||
sid = "02" + real_sid;
|
||||
// s_argv.push_back("/f");
|
||||
|
||||
s_argv.push_back("/sec:tls");
|
||||
s_argv.push_back("-wallpaper");
|
||||
s_argv.push_back("-themes");
|
||||
// Ignore certificate
|
||||
s_argv.push_back("/cert-ignore");
|
||||
// Automatically accept certificate on first connect
|
||||
s_argv.push_back("/cert-tofu");
|
||||
|
||||
ex_astr _tmp_pass = "/p:PLACEHOLDER";
|
||||
//_tmp_pass += szPwd;
|
||||
s_argv.push_back(_tmp_pass);
|
||||
|
||||
//#if 0
|
||||
//s_argv.push_back(s_exec.c_str());
|
||||
|
||||
{
|
||||
ex_astr username = "02" + real_sid;
|
||||
|
||||
s_argv.push_back("-u");
|
||||
s_argv.push_back(username.c_str());
|
||||
|
||||
// ex_astr username = "02" + real_sid;
|
||||
// s_argv.push_back("/u:");
|
||||
// s_argv.push_back(username.c_str());
|
||||
|
||||
|
||||
if (rdp_w == 0 || rdp_h == 0) {
|
||||
s_argv.push_back("-f");
|
||||
s_argv.push_back("/f");
|
||||
}
|
||||
else {
|
||||
char sz_size[64] = {0};
|
||||
ex_strformat(sz_size, 63, "%dx%d", rdp_w, rdp_h);
|
||||
s_argv.push_back("-g");
|
||||
s_argv.push_back(sz_size);
|
||||
}
|
||||
|
||||
// char sz_size[64] = {0};
|
||||
// ex_strformat(sz_size, 63, "%dx%d", rdp_w, rdp_h);
|
||||
// s_argv.push_back("-g");
|
||||
// s_argv.push_back(sz_size);
|
||||
char sz_width[64] = {0};
|
||||
ex_strformat(sz_width, 63, "/w:%d", rdp_w);
|
||||
s_argv.push_back(sz_width);
|
||||
|
||||
char sz_height[64] = {0};
|
||||
ex_strformat(sz_height, 63, "/h:%d", rdp_h);
|
||||
s_argv.push_back(sz_height);
|
||||
}
|
||||
|
||||
if (flag_console && rdp_console)
|
||||
s_argv.push_back("/admin");
|
||||
|
||||
|
@ -619,17 +648,16 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
// s_argv.push_back("+drives");
|
||||
// else
|
||||
// s_argv.push_back("-drives");
|
||||
|
||||
{
|
||||
char sz_temp[128] = {0};
|
||||
ex_strformat(sz_temp, 127, "%s:%d", teleport_ip.c_str(), teleport_port);
|
||||
s_argv.push_back(sz_temp);
|
||||
}
|
||||
//
|
||||
// {
|
||||
// char sz_temp[128] = {0};
|
||||
// ex_strformat(sz_temp, 127, "%s:%d", teleport_ip.c_str(), teleport_port);
|
||||
// s_argv.push_back(sz_temp);
|
||||
// }
|
||||
}
|
||||
|
||||
//#endif
|
||||
}
|
||||
else if (pro_type == TP_PROTOCOL_TYPE_SSH)
|
||||
{
|
||||
else if (pro_type == TP_PROTOCOL_TYPE_SSH) {
|
||||
//==============================================
|
||||
// SSH
|
||||
//==============================================
|
||||
|
@ -638,11 +666,11 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
{
|
||||
if(g_cfg.ssh.name == "terminal" || g_cfg.ssh.name == "iterm2") {
|
||||
char szCmd[1024] = {0};
|
||||
ex_strformat(szCmd, 1023, "ssh %s@%s -p %d", sid.c_str(), teleport_ip.c_str(), teleport_port);
|
||||
|
||||
ex_strformat(szCmd, 1023, "ssh %s@%s -p %d -o \"StrictHostKeyChecking no\"", sid.c_str(), teleport_ip.c_str(), teleport_port);
|
||||
|
||||
char szTitle[128] = {0};
|
||||
ex_strformat(szTitle, 127, "TP#%s", real_host_ip.c_str());
|
||||
|
||||
|
||||
int ret = AppDelegate_start_ssh_client(g_app, szCmd, g_cfg.ssh.name.c_str(), g_cfg.ssh.cmdline.c_str(), szTitle);
|
||||
if(ret == 0)
|
||||
_create_json_ret(buf, TPE_OK);
|
||||
|
@ -650,20 +678,20 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
_create_json_ret(buf, TPE_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(g_cfg.ssh.application.length() == 0) {
|
||||
_create_json_ret(buf, TPE_NOT_EXISTS);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
s_exec = g_cfg.ssh.application;
|
||||
s_argv.push_back(s_exec.c_str());
|
||||
|
||||
|
||||
s_arg = g_cfg.ssh.cmdline;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
// sorry, SFTP not supported yet for macOS.
|
||||
// _create_json_ret(buf, TPE_NOT_IMPLEMENT);
|
||||
// return;
|
||||
|
@ -672,16 +700,14 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
_create_json_ret(buf, TPE_NOT_EXISTS);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
s_exec = g_cfg.sftp.application;
|
||||
s_argv.push_back(s_exec.c_str());
|
||||
|
||||
s_arg = g_cfg.sftp.cmdline;
|
||||
|
||||
s_arg = g_cfg.sftp.cmdline;
|
||||
}
|
||||
}
|
||||
else if (pro_type == TP_PROTOCOL_TYPE_TELNET)
|
||||
{
|
||||
else if (pro_type == TP_PROTOCOL_TYPE_TELNET) {
|
||||
//==============================================
|
||||
// TELNET
|
||||
//==============================================
|
||||
|
@ -716,7 +742,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
// s_arg = g_cfg.telnet.cmdline;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---- split s_arg and push to s_argv ---
|
||||
ex_astr::size_type p1 = 0;
|
||||
ex_astr::size_type p2 = 0;
|
||||
|
@ -739,7 +765,7 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
ex_astr _t;
|
||||
_t.assign(tmp, p1, p2 - p1);
|
||||
tmp.erase(0, p2 + 2);
|
||||
|
||||
|
||||
s_argv.push_back(_t);
|
||||
} else {
|
||||
p1 = 0;
|
||||
|
@ -754,12 +780,12 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
ex_astr _t;
|
||||
_t.assign(tmp, p1, p2 - p1);
|
||||
tmp.erase(0, p2 + 1);
|
||||
|
||||
|
||||
s_argv.push_back(_t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Json::Value root_ret;
|
||||
ex_astr utf8_path = s_exec;
|
||||
|
||||
|
@ -774,18 +800,18 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
utf8_path += " ";
|
||||
utf8_path += (*it);
|
||||
}
|
||||
|
||||
|
||||
root_ret["path"] = utf8_path;
|
||||
|
||||
// for macOS, Create Process should be fork()/exec()...
|
||||
pid_t processId;
|
||||
if ((processId = fork()) == 0) {
|
||||
|
||||
|
||||
int i = 0;
|
||||
char** _argv = (char**)calloc(s_argv.size()+1, sizeof(char*));
|
||||
if (!_argv)
|
||||
return;
|
||||
|
||||
|
||||
for (i = 0; i < s_argv.size(); ++i)
|
||||
{
|
||||
_argv[i] = ex_strdup(s_argv[i].c_str());
|
||||
|
@ -800,42 +826,47 @@ void TsHttpRpc::_rpc_func_run_client(const ex_astr& func_args, ex_astr& buf)
|
|||
}
|
||||
}
|
||||
free(_argv);
|
||||
|
||||
|
||||
} else if (processId < 0) {
|
||||
root_ret["code"] = TPE_FAILED;
|
||||
} else {
|
||||
root_ret["code"] = TPE_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// root_ret["code"] = TPE_OK;
|
||||
_create_json_ret(buf, root_ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf)
|
||||
{
|
||||
void TsHttpRpc::_rpc_func_rdp_play(const ex_astr& func_args, ex_astr& buf) {
|
||||
_create_json_ret(buf, TPE_NOT_IMPLEMENT);
|
||||
}
|
||||
|
||||
void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf)
|
||||
{
|
||||
void TsHttpRpc::_rpc_func_get_config(const ex_astr& func_args, ex_astr& buf) {
|
||||
Json::Value jr_root;
|
||||
jr_root["code"] = 0;
|
||||
jr_root["data"] = g_cfg.get_root();
|
||||
_create_json_ret(buf, jr_root);
|
||||
}
|
||||
|
||||
void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf)
|
||||
{
|
||||
Json::Reader jreader;
|
||||
Json::Value jsRoot;
|
||||
if (!jreader.parse(func_args.c_str(), jsRoot))
|
||||
{
|
||||
_create_json_ret(buf, TPE_JSON_FORMAT);
|
||||
return;
|
||||
}
|
||||
void TsHttpRpc::_rpc_func_set_config(const ex_astr& func_args, ex_astr& buf) {
|
||||
// Json::Reader jreader;
|
||||
// Json::Value jsRoot;
|
||||
// if (!jreader.parse(func_args.c_str(), jsRoot))
|
||||
// {
|
||||
// _create_json_ret(buf, TPE_JSON_FORMAT);
|
||||
// return;
|
||||
// }
|
||||
|
||||
Json::CharReaderBuilder jcrb;
|
||||
std::unique_ptr<Json::CharReader> const jreader(jcrb.newCharReader());
|
||||
const char *str_json_begin = func_args.c_str();
|
||||
Json::Value jsRoot;
|
||||
ex_astr err;
|
||||
if (!jreader->parse(str_json_begin, str_json_begin + func_args.length(), &jsRoot, &err)) {
|
||||
_create_json_ret(buf, TPE_JSON_FORMAT);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!g_cfg.save(func_args))
|
||||
_create_json_ret(buf, TPE_FAILED);
|
||||
|
@ -848,7 +879,7 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
|
|||
#if 0
|
||||
Json::Reader jreader;
|
||||
Json::Value jsRoot;
|
||||
|
||||
|
||||
if (!jreader.parse(func_args.c_str(), jsRoot)) {
|
||||
_create_json_ret(buf, TPE_JSON_FORMAT);
|
||||
return;
|
||||
|
@ -859,7 +890,7 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
|
|||
// return;
|
||||
// }
|
||||
// int action = jsRoot["action"].asUInt();
|
||||
|
||||
|
||||
AppDelegate_select_app(g_app);
|
||||
_create_json_ret(buf, TPE_FAILED);
|
||||
|
||||
|
@ -884,8 +915,7 @@ void TsHttpRpc::_rpc_func_file_action(const ex_astr& func_args, ex_astr& buf) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf)
|
||||
{
|
||||
void TsHttpRpc::_rpc_func_get_version(const ex_astr& func_args, ex_astr& buf) {
|
||||
Json::Value root_ret;
|
||||
ex_wstr w_version = TP_ASSIST_VER;
|
||||
ex_astr version;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef __TS_ASSIST_VER_H__
|
||||
#define __TS_ASSIST_VER_H__
|
||||
|
||||
#define TP_ASSIST_VER L"3.2.0"
|
||||
|
||||
#endif // __TS_ASSIST_VER_H__
|
||||
#ifndef __TS_ASSIST_VER_H__
|
||||
#define __TS_ASSIST_VER_H__
|
||||
|
||||
#define TP_ASSIST_VER L"3.5.5"
|
||||
|
||||
#endif // __TS_ASSIST_VER_H__
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// for About Window
|
||||
//=============================================
|
||||
"about " = "关于 ";
|
||||
"version" = "版本:";
|
||||
"app_full_name" = "Teleport助手 - macOS";
|
||||
"copyright" = "© 2017~2018 TP4A,保留所有权利。";
|
||||
"version" = "";
|
||||
"app_full_name" = "Teleport助手";
|
||||
"copyright" = "© 2017~2019,tp4a.com。保留所有权利。";
|
||||
"visit_tp4a_website" = "访问 Teleport 网站";
|
||||
|
|
|
@ -96,7 +96,7 @@ INT_PTR CALLBACK eomDlgMainProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARA
|
|||
|
||||
case IDM_OPEN_CONFIG:
|
||||
{
|
||||
ShellExecute(nullptr, _T("open"), _T("http://localhost:50022/config"), nullptr, nullptr, SW_SHOW);
|
||||
ShellExecute(nullptr, _T("open"), _T("http://127.0.0.1:50022/config"), nullptr, nullptr, SW_SHOW);
|
||||
return TRUE;
|
||||
}break;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
<div class="footer">
|
||||
<div class="container">
|
||||
<p><a href="https://tp4a.com/" target="_blank">TELEPORT</a> | ©2015 - 2018,保留所有权利。</p>
|
||||
<p><a href="https://tp4a.com/" target="_blank">TELEPORT</a> | ©2015 - 2020,保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
|||
<ul>
|
||||
<li><span class="arg-varb">{host_ip}</span> 替换主机IP地址</li>
|
||||
<li><span class="arg-varb">{host_port}</span> 替换主机端口号</li>
|
||||
<li><span class="arg-varb">{host_name}</span> 替换主机名称</li>
|
||||
<li><span class="arg-varb">{user_name}</span> 替换用户名</li>
|
||||
<li><span class="arg-varb">{real_ip}</span> 替换为远程主机真实IP(仅用于显示,例如客户端的窗口标题或标签页标题等)</li>
|
||||
<li><span class="arg-varb">{assist_tools_path}</span> 替换为助手工具所在的tools目录的绝对路径</li>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
var g_url_base = 'http://localhost:50022';
|
||||
//var g_url_base = 'http://localhost:50022';
|
||||
var g_url_base = 'http://127.0.0.1:50022';
|
||||
|
||||
var g_cfg = null;
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
<!DOCTYPE html>
|
||||
<!--[if IE 8]>
|
||||
<html lang="en" class="ie8"><![endif]-->
|
||||
<!--[if !IE]><!-->
|
||||
<html lang="zh_CN">
|
||||
<!--<![endif]-->
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>TELEPORT助手</title>
|
||||
<link rel="shortcut icon" href="favicon.png">
|
||||
|
||||
<link href="plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="css/style.css" rel="stylesheet" type="text/css" />
|
||||
|
||||
<style type="text/css">
|
||||
.info-box {
|
||||
padding:20px;
|
||||
margin:40px;
|
||||
border:1px solid #78b17c;
|
||||
background-color:#e4ffe5;
|
||||
font-size: 140%;
|
||||
}
|
||||
.warning-box {
|
||||
padding:20px;
|
||||
margin:40px;
|
||||
border:1px solid #eac781;
|
||||
background-color: #f9f5d7;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="header">
|
||||
<div class="container">
|
||||
<span class="title"><i class="fa fa-cog fa-fw"></i> Teleport 助手</span>
|
||||
<span class="sub-title" id="version"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-fix"></div>
|
||||
|
||||
<div class="footer">
|
||||
<div class="container">
|
||||
<p><a href="https://tp4a.com/" target="_blank">TELEPORT</a> | ©2015 - 2020,保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="content">
|
||||
|
||||
<div class="info-box">
|
||||
Teleport助手工作正常!
|
||||
</div>
|
||||
|
||||
<div class="warning-box">
|
||||
<p>如果在使用 HTTPS 方式访问 teleport 的 web 服务时检测不到助手,请<a href="https://127.0.0.1:50023" target="_blank">点击这里</a>,查看页面是否能够正常显示。</p>
|
||||
<p>因为助手在配合HTTPS访问时使用了<strong>自签名证书</strong>,而自签名证书的颁发机构的根证书<strong>默认不被浏览器信任</strong>,因此,还<strong>需要将其设置为浏览器信任的根证书</strong>才行,根据浏览器的不同,具体设置方法有两种:</p>
|
||||
<p><strong>Chrome/IE/Edge/Opera 等浏览器</strong></p>
|
||||
<ol>
|
||||
<li>在桌面的助手快捷方式上点击右键,然后选择“打开文件所在的位置”;</li>
|
||||
<li>右键点击 <strong>cacert.cer</strong>,在弹出菜单中选择“安装证书”;</li>
|
||||
<li>在打开的“证书导入向导”对话框中选择“当前用户”,点击下一步;</li>
|
||||
<li>选择“将所有的证书都放入下列存储”,然后点击“浏览”按钮;</li>
|
||||
<li>在打开的“选择证书存储”对话框中选择<strong>“受信任的根证书颁发机构”</strong>,点击确定;</li>
|
||||
<li>点击“下一步”,然后点击“完成”;</li>
|
||||
<li>系统提示“导入成功”,大功告成。</li>
|
||||
</ol>
|
||||
|
||||
<p><strong>FireFox火狐浏览器</strong></p>
|
||||
<ol>
|
||||
<li>打开火狐浏览器的选项页面;</li>
|
||||
<li>点击左侧的“隐私与安全”,然后滚动页面到底部,点击“查看证书”按钮;</li>
|
||||
<li>在打开的“证书管理器”对话框中选择“证书颁发机构”选项卡;</li>
|
||||
<li>点击对话框底部的“导入”按钮,然后选择 <strong>cacert.cer</strong> 文件并点击“打开”按钮;</li>
|
||||
<li>在“下载证书”对话框中,勾选“信任由此证书颁发机构来标识网站”,然后点击“确定”;</li>
|
||||
<li>点击“确定”来关闭证书管理器对话框,大功告成。</li>
|
||||
</ol>
|
||||
|
||||
<p><strong>注意:</strong>导入证书后,请再次<a href="https://127.0.0.1:50023" target="_blank">点击这里</a>,查看页面是否能够正常显示。</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1 +1,14 @@
|
|||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <ex.h>
|
||||
|
||||
// #ifdef EX_DEBUG
|
||||
// // # pragma comment(lib, "libssl32MTd.lib")
|
||||
// // # pragma comment(lib, "libcrypto32MTd.lib")
|
||||
// #else
|
||||
// # pragma comment(lib, "libssl32MT.lib")
|
||||
// # pragma comment(lib, "libcrypto32MT.lib")
|
||||
// #endif
|
||||
|
||||
# pragma comment(lib, "libssl.lib")
|
||||
# pragma comment(lib, "libcrypto.lib")
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tp_assist", "tp_assist.vs2015.vcxproj", "{63B7A8F2-9722-487C-A92A-3DB5D8CA1473}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{63B7A8F2-9722-487C-A92A-3DB5D8CA1473}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{63B7A8F2-9722-487C-A92A-3DB5D8CA1473}.Debug|x86.Build.0 = Debug|Win32
|
||||
{63B7A8F2-9722-487C-A92A-3DB5D8CA1473}.Release|x86.ActiveCfg = Release|Win32
|
||||
{63B7A8F2-9722-487C-A92A-3DB5D8CA1473}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,185 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{63B7A8F2-9722-487C-A92A-3DB5D8CA1473}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>tp_assist</RootNamespace>
|
||||
<ProjectName>tp_assist</ProjectName>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>..\..\out\client\$(PlatformTarget)\$(Configuration)\</OutDir>
|
||||
<IntDir>..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\</IntDir>
|
||||
<IncludePath>C:\Program Files %28x86%29\Visual Leak Detector\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files %28x86%29\Visual Leak Detector\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>..\..\out\client\$(PlatformTarget)\$(Configuration)\</OutDir>
|
||||
<IntDir>..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;MG_ENABLE_SSL;_DEBUG;_WINDOWS;_WINSOCK_DEPRECATED_NO_WARNINGS;MG_ENABLE_THREADS;MG_DISABLE_HTTP_DIGEST_AUTH;MG_DISABLE_MQTT;MG_DISABLE_SSI;MG_DISABLE_FILESYSTEM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\common\teleport;..\..\common\libex\include;..\..\external\jsoncpp\include;..\..\external\openssl\inc32</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>..\..\external\openssl\out32\ssleay32.lib;..\..\external\openssl\out32\libeay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;MG_ENABLE_SSL;NDEBUG;_WINDOWS;_WINSOCK_DEPRECATED_NO_WARNINGS;MG_ENABLE_THREADS;MG_DISABLE_HTTP_DIGEST_AUTH;MG_DISABLE_MQTT;MG_DISABLE_SSI;MG_DISABLE_FILESYSTEM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\common\teleport;..\..\common\libex\include;..\..\external\jsoncpp\include;..\..\external\openssl\inc32</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>..\..\external\openssl\out32\ssleay32.lib;..\..\external\openssl\out32\libeay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\common\libex\include\ex.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_const.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_ini.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_log.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_path.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_platform.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_str.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_thread.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_types.h" />
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_util.h" />
|
||||
<ClInclude Include="..\..\common\teleport\teleport_const.h" />
|
||||
<ClInclude Include="..\..\external\mongoose\mongoose.h" />
|
||||
<ClInclude Include="dlg_main.h" />
|
||||
<ClInclude Include="msocketx.h" />
|
||||
<ClInclude Include="Resource.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="tp_assist.h" />
|
||||
<ClInclude Include="ts_cfg.h" />
|
||||
<ClInclude Include="ts_const.h" />
|
||||
<ClInclude Include="ts_env.h" />
|
||||
<ClInclude Include="ts_http_rpc.h" />
|
||||
<ClInclude Include="ts_network.h" />
|
||||
<ClInclude Include="ts_ver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_ini.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_log.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_path.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_str.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_thread.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_util.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\jsoncpp\src\lib_json\json_reader.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\jsoncpp\src\lib_json\json_value.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\jsoncpp\src\lib_json\json_writer.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\mongoose\mongoose.c">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dlg_main.cpp" />
|
||||
<ClCompile Include="msocketx.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tp_assist.cpp" />
|
||||
<ClCompile Include="ts_cfg.cpp" />
|
||||
<ClCompile Include="ts_env.cpp" />
|
||||
<ClCompile Include="ts_http_rpc.cpp" />
|
||||
<ClCompile Include="ts_network.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="tp_assist.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\tp.ico" />
|
||||
<Image Include="res\tp_small.ico" />
|
||||
<Image Include="res\tray_normal.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\external\jsoncpp\src\lib_json\json_valueiterator.inl" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,180 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dlg_main.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tp_assist.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ts_http_rpc.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ts_network.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msocketx.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ts_env.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ts_cfg.cpp">
|
||||
<Filter>main app</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\jsoncpp\src\lib_json\json_reader.cpp">
|
||||
<Filter>jsoncpp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\jsoncpp\src\lib_json\json_value.cpp">
|
||||
<Filter>jsoncpp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\jsoncpp\src\lib_json\json_writer.cpp">
|
||||
<Filter>jsoncpp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\external\mongoose\mongoose.c">
|
||||
<Filter>mongoose</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_str.cpp">
|
||||
<Filter>libex\src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_util.cpp">
|
||||
<Filter>libex\src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_path.cpp">
|
||||
<Filter>libex\src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_ini.cpp">
|
||||
<Filter>libex\src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_log.cpp">
|
||||
<Filter>libex\src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\common\libex\src\ex_thread.cpp">
|
||||
<Filter>libex\src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Resource.h">
|
||||
<Filter>resource</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dlg_main.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="tp_assist.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ts_http_rpc.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ts_network.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ts_env.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ts_cfg.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\external\mongoose\mongoose.h">
|
||||
<Filter>mongoose</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msocketx.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_const.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_path.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_platform.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_str.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_types.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_util.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ts_const.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ts_ver.h">
|
||||
<Filter>main app</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_ini.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_log.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\libex\include\ex\ex_thread.h">
|
||||
<Filter>libex\header</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\common\teleport\teleport_const.h">
|
||||
<Filter>teleport</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\tp.ico">
|
||||
<Filter>resource</Filter>
|
||||
</Image>
|
||||
<Image Include="res\tp_small.ico">
|
||||
<Filter>resource</Filter>
|
||||
</Image>
|
||||
<Image Include="res\tray_normal.ico">
|
||||
<Filter>resource</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="resource">
|
||||
<UniqueIdentifier>{52b425b1-8aa9-4e08-acbd-c88387350530}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="jsoncpp">
|
||||
<UniqueIdentifier>{adabe93d-3938-4b11-9352-5b67a1efd7e3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="mongoose">
|
||||
<UniqueIdentifier>{35a345a0-6147-4c87-97c9-3b0b2a57e348}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="main app">
|
||||
<UniqueIdentifier>{0942cec3-67df-4d19-bbc1-e962145e496f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="libex">
|
||||
<UniqueIdentifier>{a88e05d3-51f4-463f-84cc-c3bc86f07aac}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="libex\header">
|
||||
<UniqueIdentifier>{e3e7a811-5905-4ad5-86a7-9721af5d015a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="libex\src">
|
||||
<UniqueIdentifier>{d7d49fa4-5192-42c5-bc70-5584d9d646c6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="teleport">
|
||||
<UniqueIdentifier>{1291a5cf-cb08-4ad6-8a86-8a0486297c63}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="tp_assist.rc">
|
||||
<Filter>resource</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\external\jsoncpp\src\lib_json\json_valueiterator.inl">
|
||||
<Filter>jsoncpp</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -46,8 +46,8 @@
|
|||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>..\..\out\client\$(PlatformTarget)\$(Configuration)\</OutDir>
|
||||
<IntDir>..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\</IntDir>
|
||||
<IncludePath>C:\Program Files %28x86%29\Visual Leak Detector\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Program Files %28x86%29\Visual Leak Detector\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>C:\apps\vld\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\apps\vld\lib\Win32;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
|
@ -61,12 +61,14 @@
|
|||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;MG_ENABLE_SSL;_DEBUG;_WINDOWS;_WINSOCK_DEPRECATED_NO_WARNINGS;MG_ENABLE_THREADS;MG_DISABLE_HTTP_DIGEST_AUTH;MG_DISABLE_MQTT;MG_DISABLE_SSI;MG_DISABLE_FILESYSTEM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\common\teleport;..\..\common\libex\include;..\..\external\jsoncpp\include;..\..\external\openssl\inc32</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\common\teleport;..\..\common\libex\include;..\..\external\jsoncpp\include;..\..\external\openssl\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>..\..\external\openssl\out32\ssleay32.lib;..\..\external\openssl\out32\libeay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\external\openssl\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
|
@ -78,7 +80,7 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;MG_ENABLE_SSL;NDEBUG;_WINDOWS;_WINSOCK_DEPRECATED_NO_WARNINGS;MG_ENABLE_THREADS;MG_DISABLE_HTTP_DIGEST_AUTH;MG_DISABLE_MQTT;MG_DISABLE_SSI;MG_DISABLE_FILESYSTEM;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\..\common\teleport;..\..\common\libex\include;..\..\external\jsoncpp\include;..\..\external\openssl\inc32</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\..\common\teleport;..\..\common\libex\include;..\..\external\jsoncpp\include;..\..\external\openssl\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
@ -86,7 +88,8 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>..\..\external\openssl\out32\ssleay32.lib;..\..\external\openssl\out32\libeay32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\external\openssl\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,266 +1,274 @@
|
|||
#include "stdafx.h"
|
||||
#include "ts_cfg.h"
|
||||
#include "ts_env.h"
|
||||
|
||||
|
||||
TsCfg g_cfg;
|
||||
|
||||
TsCfg::TsCfg()
|
||||
{}
|
||||
|
||||
TsCfg::~TsCfg()
|
||||
{}
|
||||
|
||||
bool TsCfg::init(void) {
|
||||
ex_astr file_content;
|
||||
if (!ex_read_text_file(g_env.m_cfg_file, file_content)) {
|
||||
EXLOGE("can not load config file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_load(file_content))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TsCfg::save(const ex_astr& new_value)
|
||||
{
|
||||
if (!_load(new_value))
|
||||
return false;
|
||||
|
||||
Json::StyledWriter jwriter;
|
||||
ex_astr val = jwriter.write(m_root);
|
||||
|
||||
if (!ex_write_text_file(g_env.m_cfg_file, val)) {
|
||||
EXLOGE("can not save config file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TsCfg::_load(const ex_astr& str_json) {
|
||||
Json::Reader jreader;
|
||||
|
||||
if (!jreader.parse(str_json.c_str(), m_root)) {
|
||||
EXLOGE("can not parse new config data, not in json format? %s\n", jreader.getFormattedErrorMessages().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ex_astr sel_name;
|
||||
size_t i = 0;
|
||||
ex_astr tmp;
|
||||
|
||||
//===================================
|
||||
// check ssh config
|
||||
//===================================
|
||||
|
||||
if (!m_root["ssh"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["ssh"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["ssh"]["selected"].asCString();
|
||||
|
||||
if (!m_root["ssh"]["available"].isArray() || m_root["ssh"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["ssh"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["ssh"]["available"][i]["name"].isString()
|
||||
|| !m_root["ssh"]["available"][i]["app"].isString()
|
||||
|| !m_root["ssh"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["ssh"]["available"][i]["display"].isNull()) {
|
||||
m_root["ssh"]["available"][i]["display"] = m_root["ssh"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["ssh"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["ssh"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, ssh_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["ssh"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, ssh_cmdline, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ssh_app.length() == 0 || ssh_cmdline.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//===================================
|
||||
// check sftp config
|
||||
//===================================
|
||||
|
||||
if (!m_root["scp"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["scp"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["scp"]["selected"].asCString();
|
||||
|
||||
if (!m_root["scp"]["available"].isArray() || m_root["scp"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["scp"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["scp"]["available"][i]["name"].isString()
|
||||
|| !m_root["scp"]["available"][i]["app"].isString()
|
||||
|| !m_root["scp"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["scp"]["available"][i]["display"].isNull()) {
|
||||
m_root["scp"]["available"][i]["display"] = m_root["scp"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["scp"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["scp"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, scp_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["scp"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, scp_cmdline, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (scp_app.length() == 0 || scp_cmdline.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//===================================
|
||||
// check telnet config
|
||||
//===================================
|
||||
|
||||
if (!m_root["telnet"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["telnet"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["telnet"]["selected"].asCString();
|
||||
|
||||
if (!m_root["telnet"]["available"].isArray() || m_root["telnet"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["telnet"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["telnet"]["available"][i]["name"].isString()
|
||||
|| !m_root["telnet"]["available"][i]["app"].isString()
|
||||
|| !m_root["telnet"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["telnet"]["available"][i]["display"].isNull()) {
|
||||
m_root["telnet"]["available"][i]["display"] = m_root["telnet"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["telnet"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["telnet"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, telnet_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["telnet"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, telnet_cmdline, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (telnet_app.length() == 0 || telnet_cmdline.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//===================================
|
||||
// check rdp config
|
||||
//===================================
|
||||
|
||||
if (!m_root["rdp"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["rdp"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["rdp"]["selected"].asCString();
|
||||
|
||||
if (!m_root["rdp"]["available"].isArray() || m_root["rdp"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["rdp"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["rdp"]["available"][i]["name"].isString()
|
||||
|| !m_root["rdp"]["available"][i]["app"].isString()
|
||||
|| !m_root["rdp"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["rdp"]["available"][i]["display"].isNull()) {
|
||||
m_root["rdp"]["available"][i]["display"] = m_root["rdp"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["rdp"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["rdp"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, rdp_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["rdp"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, rdp_cmdline, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["rdp"]["available"][i]["name"].asCString();
|
||||
ex_astr2wstr(tmp, rdp_name, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rdp_app.length() == 0 || rdp_cmdline.length() == 0 || rdp_name.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#include "stdafx.h"
|
||||
#include "ts_cfg.h"
|
||||
#include "ts_env.h"
|
||||
|
||||
|
||||
TsCfg g_cfg;
|
||||
|
||||
TsCfg::TsCfg()
|
||||
{}
|
||||
|
||||
TsCfg::~TsCfg()
|
||||
{}
|
||||
|
||||
bool TsCfg::init(void) {
|
||||
ex_astr file_content;
|
||||
if (!ex_read_text_file(g_env.m_cfg_file, file_content)) {
|
||||
EXLOGE("can not load config file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_load(file_content))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TsCfg::save(const ex_astr& new_value)
|
||||
{
|
||||
if (!_load(new_value))
|
||||
return false;
|
||||
|
||||
//Json::StyledWriter jwriter;
|
||||
Json::StreamWriterBuilder jwb;
|
||||
std::unique_ptr<Json::StreamWriter> jwriter(jwb.newStreamWriter());
|
||||
ex_aoss os;
|
||||
jwriter->write(m_root, &os);
|
||||
ex_astr val = os.str();
|
||||
|
||||
if (!ex_write_text_file(g_env.m_cfg_file, val)) {
|
||||
EXLOGE("can not save config file.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TsCfg::_load(const ex_astr& str_json) {
|
||||
//Json::Reader jreader;
|
||||
Json::CharReaderBuilder jcrb;
|
||||
std::unique_ptr<Json::CharReader> const jreader(jcrb.newCharReader());
|
||||
const char *str_json_begin = str_json.c_str();
|
||||
|
||||
ex_astr err;
|
||||
if (!jreader->parse(str_json_begin, str_json_begin + str_json.length(), &m_root, &err)) {
|
||||
EXLOGE("can not parse new config data, not in json format? %s\n", err.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ex_astr sel_name;
|
||||
size_t i = 0;
|
||||
ex_astr tmp;
|
||||
|
||||
//===================================
|
||||
// check ssh config
|
||||
//===================================
|
||||
|
||||
if (!m_root["ssh"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["ssh"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["ssh"]["selected"].asCString();
|
||||
|
||||
if (!m_root["ssh"]["available"].isArray() || m_root["ssh"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["ssh"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["ssh"]["available"][i]["name"].isString()
|
||||
|| !m_root["ssh"]["available"][i]["app"].isString()
|
||||
|| !m_root["ssh"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["ssh"]["available"][i]["display"].isNull()) {
|
||||
m_root["ssh"]["available"][i]["display"] = m_root["ssh"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["ssh"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["ssh"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, ssh_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["ssh"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, ssh_cmdline, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ssh_app.length() == 0 || ssh_cmdline.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//===================================
|
||||
// check sftp config
|
||||
//===================================
|
||||
|
||||
if (!m_root["scp"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["scp"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["scp"]["selected"].asCString();
|
||||
|
||||
if (!m_root["scp"]["available"].isArray() || m_root["scp"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["scp"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["scp"]["available"][i]["name"].isString()
|
||||
|| !m_root["scp"]["available"][i]["app"].isString()
|
||||
|| !m_root["scp"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["scp"]["available"][i]["display"].isNull()) {
|
||||
m_root["scp"]["available"][i]["display"] = m_root["scp"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["scp"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["scp"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, scp_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["scp"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, scp_cmdline, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (scp_app.length() == 0 || scp_cmdline.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//===================================
|
||||
// check telnet config
|
||||
//===================================
|
||||
|
||||
if (!m_root["telnet"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["telnet"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["telnet"]["selected"].asCString();
|
||||
|
||||
if (!m_root["telnet"]["available"].isArray() || m_root["telnet"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["telnet"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["telnet"]["available"][i]["name"].isString()
|
||||
|| !m_root["telnet"]["available"][i]["app"].isString()
|
||||
|| !m_root["telnet"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["telnet"]["available"][i]["display"].isNull()) {
|
||||
m_root["telnet"]["available"][i]["display"] = m_root["telnet"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["telnet"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["telnet"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, telnet_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["telnet"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, telnet_cmdline, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (telnet_app.length() == 0 || telnet_cmdline.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//===================================
|
||||
// check rdp config
|
||||
//===================================
|
||||
|
||||
if (!m_root["rdp"].isObject()) {
|
||||
EXLOGE("invalid config, error 1.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_root["rdp"]["selected"].isString()) {
|
||||
EXLOGE("invalid config, error 2.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel_name = m_root["rdp"]["selected"].asCString();
|
||||
|
||||
if (!m_root["rdp"]["available"].isArray() || m_root["rdp"]["available"].size() == 0) {
|
||||
EXLOGE("invalid config, error 3.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_root["rdp"]["available"].size(); ++i) {
|
||||
|
||||
if (
|
||||
!m_root["rdp"]["available"][i]["name"].isString()
|
||||
|| !m_root["rdp"]["available"][i]["app"].isString()
|
||||
|| !m_root["rdp"]["available"][i]["cmdline"].isString()
|
||||
) {
|
||||
EXLOGE("invalid config, error 4.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_root["rdp"]["available"][i]["display"].isNull()) {
|
||||
m_root["rdp"]["available"][i]["display"] = m_root["rdp"]["available"][i]["name"];
|
||||
}
|
||||
|
||||
if (m_root["rdp"]["available"][i]["name"].asCString() != sel_name)
|
||||
continue;
|
||||
|
||||
tmp = m_root["rdp"]["available"][i]["app"].asCString();
|
||||
ex_astr2wstr(tmp, rdp_app, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["rdp"]["available"][i]["cmdline"].asCString();
|
||||
ex_astr2wstr(tmp, rdp_cmdline, EX_CODEPAGE_UTF8);
|
||||
tmp = m_root["rdp"]["available"][i]["name"].asCString();
|
||||
ex_astr2wstr(tmp, rdp_name, EX_CODEPAGE_UTF8);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rdp_app.length() == 0 || rdp_cmdline.length() == 0 || rdp_name.length() == 0) {
|
||||
EXLOGE("invalid config, error 6.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|