summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
committermanuel <manuel@mausz.at>2015-03-03 16:53:59 +0100
commitffca21f2743a7b367fa212799c6e2fea6190dd5d (patch)
tree0608ea3a29cf644ec9ab204e2b4bb9bfaae1c381
downloadkodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.gz
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.bz2
kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.zip
initial commit for kodi master
-rw-r--r--addons/library.xbmc.addon/dlfcn-win32.cpp263
-rw-r--r--addons/library.xbmc.addon/dlfcn-win32.h46
-rw-r--r--addons/library.xbmc.addon/libXBMC_addon.h600
-rw-r--r--addons/library.xbmc.codec/libXBMC_codec.h124
-rw-r--r--addons/library.xbmc.gui/libXBMC_gui.h845
-rw-r--r--addons/library.xbmc.pvr/libXBMC_pvr.h332
-rw-r--r--project/cmake/addons/CMakeLists.txt249
-rw-r--r--project/cmake/addons/README68
-rw-r--r--project/cmake/addons/addons/audioencoder.flac/audioencoder.flac.txt1
-rw-r--r--project/cmake/addons/addons/audioencoder.flac/platforms.txt1
-rw-r--r--project/cmake/addons/addons/audioencoder.lame/audioencoder.lame.txt1
-rw-r--r--project/cmake/addons/addons/audioencoder.lame/platforms.txt1
-rw-r--r--project/cmake/addons/addons/audioencoder.vorbis/audioencoder.vorbis.txt1
-rw-r--r--project/cmake/addons/addons/audioencoder.vorbis/platforms.txt1
-rw-r--r--project/cmake/addons/addons/audioencoder.wav/audioencoder.wav.txt1
-rw-r--r--project/cmake/addons/addons/audioencoder.wav/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.argustv/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.argustv/pvr.argustv.txt1
-rw-r--r--project/cmake/addons/addons/pvr.demo/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.demo/pvr.demo.txt1
-rw-r--r--project/cmake/addons/addons/pvr.dvblink/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.dvblink/pvr.dvblink.txt1
-rw-r--r--project/cmake/addons/addons/pvr.dvbviewer/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.dvbviewer/pvr.dvbviewer.txt1
-rw-r--r--project/cmake/addons/addons/pvr.hts/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.hts/pvr.hts.txt1
-rw-r--r--project/cmake/addons/addons/pvr.iptvsimple/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt1
-rw-r--r--project/cmake/addons/addons/pvr.mediaportal.tvserver/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.mediaportal.tvserver/pvr.mediaportal.tvserver.txt1
-rw-r--r--project/cmake/addons/addons/pvr.mythtv/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.mythtv/pvr.mythtv.txt1
-rw-r--r--project/cmake/addons/addons/pvr.nextpvr/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.nextpvr/pvr.nextpvr.txt1
-rw-r--r--project/cmake/addons/addons/pvr.njoy/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.njoy/pvr.njoy.txt1
-rw-r--r--project/cmake/addons/addons/pvr.vdr.vnsi/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.vdr.vnsi/pvr.vdr.vnsi.txt1
-rw-r--r--project/cmake/addons/addons/pvr.vuplus/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.vuplus/pvr.vuplus.txt1
-rw-r--r--project/cmake/addons/addons/pvr.wmc/platforms.txt1
-rw-r--r--project/cmake/addons/addons/pvr.wmc/pvr.wmc.txt1
-rw-r--r--project/cmake/addons/depends/CMakeLists.txt42
-rw-r--r--project/cmake/addons/depends/README61
-rw-r--r--project/cmake/addons/depends/common/kodi-platform/deps.txt2
-rw-r--r--project/cmake/addons/depends/common/kodi-platform/kodi-platform.txt1
-rw-r--r--project/cmake/addons/depends/common/tinyxml/CMakeLists.txt23
-rw-r--r--project/cmake/addons/depends/common/tinyxml/tinyxml.txt1
-rw-r--r--project/cmake/addons/depends/windows/CMakeLists.txt55
-rw-r--r--project/cmake/addons/depends/windows/Find7Zip.cmake7
-rw-r--r--project/cmake/addons/depends/windows/README19
-rw-r--r--project/cmake/addons/depends/windows/extract-7z.cmake10
-rw-r--r--project/cmake/addons/depends/windows/extract-direct.cmake2
-rw-r--r--project/cmake/addons/depends/windows/install.cmake24
-rw-r--r--project/cmake/addons/depends/windows/prebuilt/README21
-rw-r--r--project/cmake/kodi-config.cmake.in11
-rw-r--r--project/cmake/platform/android/defines.txt1
-rw-r--r--project/cmake/platform/darwin/defines.txt1
-rw-r--r--project/cmake/platform/freebsd/defines.txt1
-rw-r--r--project/cmake/platform/ios/defines.txt1
-rw-r--r--project/cmake/platform/linux/defines.txt1
-rw-r--r--project/cmake/platform/rbpi/defines.txt1
-rw-r--r--project/cmake/platform/windows/defines.txt1
-rw-r--r--project/cmake/scripts/common/addon-helpers.cmake113
-rw-r--r--project/cmake/scripts/common/addoptions.cmake82
-rw-r--r--project/cmake/scripts/common/check_target_platform.cmake61
-rw-r--r--project/cmake/scripts/common/handle-depends.cmake191
-rw-r--r--project/cmake/scripts/common/prepare-env.cmake88
-rw-r--r--project/cmake/scripts/windows/c-flag-overrides.cmake5
-rw-r--r--project/cmake/scripts/windows/cxx-flag-overrides.cmake5
-rw-r--r--project/cmake/xbmc-config.cmake.in4
-rwxr-xr-xscripts/sync_buildenv.sh17
-rw-r--r--scripts/toolchain/android-arm.cmake58
-rw-r--r--scripts/toolchain/ios-arm.cmake58
-rw-r--r--scripts/toolchain/linux-i486.cmake58
-rw-r--r--scripts/toolchain/linux-x86_64.cmake58
-rw-r--r--scripts/toolchain/osx-i386.cmake58
-rw-r--r--scripts/toolchain/osx-x86_64.cmake58
-rw-r--r--scripts/toolchain/rbpi-arm.cmake58
-rw-r--r--version.txt11
-rw-r--r--xbmc/addons/Addon.cpp653
-rw-r--r--xbmc/addons/Addon.h278
-rw-r--r--xbmc/addons/AddonCallbacks.cpp173
-rw-r--r--xbmc/addons/AddonCallbacks.h466
-rw-r--r--xbmc/addons/AddonCallbacksAddon.cpp532
-rw-r--r--xbmc/addons/AddonCallbacksAddon.h73
-rw-r--r--xbmc/addons/AddonCallbacksCodec.cpp116
-rw-r--r--xbmc/addons/AddonCallbacksCodec.h46
-rw-r--r--xbmc/addons/AddonCallbacksGUI.cpp2281
-rw-r--r--xbmc/addons/AddonCallbacksGUI.h272
-rw-r--r--xbmc/addons/AddonCallbacksPVR.cpp324
-rw-r--r--xbmc/addons/AddonCallbacksPVR.h166
-rw-r--r--xbmc/addons/AddonDatabase.cpp797
-rw-r--r--xbmc/addons/AddonDatabase.h175
-rw-r--r--xbmc/addons/AddonDll.h572
-rw-r--r--xbmc/addons/AddonInstaller.cpp974
-rw-r--r--xbmc/addons/AddonInstaller.h229
-rw-r--r--xbmc/addons/AddonManager.cpp1030
-rw-r--r--xbmc/addons/AddonManager.h253
-rw-r--r--xbmc/addons/AddonStatusHandler.cpp175
-rw-r--r--xbmc/addons/AddonStatusHandler.h56
-rw-r--r--xbmc/addons/AddonVersion.cpp138
-rw-r--r--xbmc/addons/AddonVersion.h72
-rw-r--r--xbmc/addons/AudioEncoder.cpp90
-rw-r--r--xbmc/addons/AudioEncoder.h51
-rw-r--r--xbmc/addons/ContextItemAddon.cpp108
-rw-r--r--xbmc/addons/ContextItemAddon.h72
-rw-r--r--xbmc/addons/DllAddon.h70
-rw-r--r--xbmc/addons/DllLibCPluff.h116
-rw-r--r--xbmc/addons/DllPVRClient.h29
-rw-r--r--xbmc/addons/GUIDialogAddonInfo.cpp458
-rw-r--r--xbmc/addons/GUIDialogAddonInfo.h80
-rw-r--r--xbmc/addons/GUIDialogAddonSettings.cpp1200
-rw-r--r--xbmc/addons/GUIDialogAddonSettings.h91
-rw-r--r--xbmc/addons/GUIViewStateAddonBrowser.cpp132
-rw-r--r--xbmc/addons/GUIViewStateAddonBrowser.h35
-rw-r--r--xbmc/addons/GUIWindowAddonBrowser.cpp677
-rw-r--r--xbmc/addons/GUIWindowAddonBrowser.h79
-rw-r--r--xbmc/addons/IAddon.h138
-rw-r--r--xbmc/addons/Makefile31
-rw-r--r--xbmc/addons/PluginSource.cpp96
-rw-r--r--xbmc/addons/PluginSource.h58
-rw-r--r--xbmc/addons/Repository.cpp395
-rw-r--r--xbmc/addons/Repository.h82
-rw-r--r--xbmc/addons/Scraper.cpp1033
-rw-r--r--xbmc/addons/Scraper.h178
-rw-r--r--xbmc/addons/ScreenSaver.cpp125
-rw-r--r--xbmc/addons/ScreenSaver.h47
-rw-r--r--xbmc/addons/Service.cpp158
-rw-r--r--xbmc/addons/Service.h63
-rw-r--r--xbmc/addons/Skin.cpp491
-rw-r--r--xbmc/addons/Skin.h155
-rw-r--r--xbmc/addons/Visualisation.cpp486
-rw-r--r--xbmc/addons/Visualisation.h111
-rw-r--r--xbmc/addons/Webinterface.cpp75
-rw-r--r--xbmc/addons/Webinterface.h54
-rw-r--r--xbmc/addons/addon-bindings.mk20
-rw-r--r--xbmc/addons/include/NOTE12
-rw-r--r--xbmc/addons/include/xbmc_addon_cpp_dll.h191
-rw-r--r--xbmc/addons/include/xbmc_addon_dll.h55
-rw-r--r--xbmc/addons/include/xbmc_addon_types.h64
-rw-r--r--xbmc/addons/include/xbmc_audioenc_dll.h61
-rw-r--r--xbmc/addons/include/xbmc_audioenc_types.h113
-rw-r--r--xbmc/addons/include/xbmc_codec_types.h55
-rw-r--r--xbmc/addons/include/xbmc_epg_types.h96
-rw-r--r--xbmc/addons/include/xbmc_pvr_dll.h710
-rw-r--r--xbmc/addons/include/xbmc_pvr_types.h415
-rw-r--r--xbmc/addons/include/xbmc_scr_dll.h45
-rw-r--r--xbmc/addons/include/xbmc_scr_types.h53
-rw-r--r--xbmc/addons/include/xbmc_stream_utils.hpp264
-rw-r--r--xbmc/addons/include/xbmc_vis_dll.h55
-rw-r--r--xbmc/addons/include/xbmc_vis_types.h111
-rw-r--r--xbmc/addons/test/Makefile9
-rw-r--r--xbmc/addons/test/TestAddonVersion.cpp254
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp184
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h359
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp193
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h85
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp404
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h68
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp197
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h60
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp1767
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h172
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp391
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h68
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp493
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h118
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h36
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp199
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h60
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp89
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h31
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp247
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h99
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp153
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h30
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in19
178 files changed, 28850 insertions, 0 deletions
diff --git a/addons/library.xbmc.addon/dlfcn-win32.cpp b/addons/library.xbmc.addon/dlfcn-win32.cpp
new file mode 100644
index 0000000..5839921
--- /dev/null
+++ b/addons/library.xbmc.addon/dlfcn-win32.cpp
@@ -0,0 +1,263 @@
1/*
2 * dlfcn-win32
3 * Copyright (c) 2007 Ramiro Polla
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <windows.h>
21#include <stdio.h>
22
23#include "dlfcn-win32.h"
24
25/* Note:
26 * MSDN says these functions are not thread-safe. We make no efforts to have
27 * any kind of thread safety.
28 */
29
30/* I have no special reason to have set MAX_GLOBAL_OBJECTS to this value. Any
31 * comments are welcome.
32 */
33#define MAX_OBJECTS 255
34
35static HMODULE global_objects[MAX_OBJECTS];
36
37/* This function adds an object to the list of global objects.
38 * The implementation is very simple and slow.
39 * TODO: should failing this function be enough to fail the call to dlopen( )?
40 */
41static void global_object_add( HMODULE hModule )
42{
43 int i;
44
45 for( i = 0 ; i < MAX_OBJECTS ; i++ )
46 {
47 if( !global_objects[i] )
48 {
49 global_objects[i] = hModule;
50 break;
51 }
52 }
53}
54
55static void global_object_rem( HMODULE hModule )
56{
57 int i;
58
59 for( i = 0 ; i < MAX_OBJECTS ; i++ )
60 {
61 if( global_objects[i] == hModule )
62 {
63 global_objects[i] = 0;
64 break;
65 }
66 }
67}
68
69/* Argument to last function. Used in dlerror( ) */
70static char last_name[MAX_PATH];
71
72static int copy_string( char *dest, int dest_size, const char *src )
73{
74 int i = 0;
75
76 if( src && dest )
77 {
78 for( i = 0 ; i < dest_size-1 ; i++ )
79 {
80 if( !src[i] )
81 break;
82 else
83 dest[i] = src[i];
84 }
85 }
86 dest[i] = '\0';
87
88 return i;
89}
90
91void *dlopen( const char *file, int mode )
92{
93 HMODULE hModule;
94 UINT uMode;
95
96 /* Do not let Windows display the critical-error-handler message box */
97 uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
98
99 if( file == 0 )
100 {
101 /* Save NULL pointer for error message */
102 _snprintf_s( last_name, MAX_PATH, MAX_PATH, "0x%p", file );
103
104 /* POSIX says that if the value of file is 0, a handle on a global
105 * symbol object must be provided. That object must be able to access
106 * all symbols from the original program file, and any objects loaded
107 * with the RTLD_GLOBAL flag.
108 * The return value from GetModuleHandle( ) allows us to retrieve
109 * symbols only from the original program file. For objects loaded with
110 * the RTLD_GLOBAL flag, we create our own list later on.
111 */
112 hModule = GetModuleHandle( NULL );
113 }
114 else
115 {
116 char lpFileName[MAX_PATH];
117 int i;
118
119 /* MSDN says backslashes *must* be used instead of forward slashes. */
120 for( i = 0 ; i < sizeof(lpFileName)-1 ; i++ )
121 {
122 if( !file[i] )
123 break;
124 else if( file[i] == '/' )
125 lpFileName[i] = '\\';
126 else
127 lpFileName[i] = file[i];
128 }
129 lpFileName[i] = '\0';
130
131 /* Save file name for error message */
132 copy_string( last_name, sizeof(last_name), lpFileName );
133
134 /* POSIX says the search path is implementation-defined.
135 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
136 * to UNIX's search paths (start with system folders instead of current
137 * folder).
138 */
139 hModule = LoadLibraryEx( (LPSTR) lpFileName, NULL,
140 LOAD_WITH_ALTERED_SEARCH_PATH );
141 /* If the object was loaded with RTLD_GLOBAL, add it to list of global
142 * objects, so that its symbols may be retrieved even if the handle for
143 * the original program file is passed. POSIX says that if the same
144 * file is specified in multiple invocations, and any of them are
145 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
146 * symbols will remain global.
147 */
148
149 if( hModule && (mode & RTLD_GLOBAL) )
150 global_object_add( hModule );
151 }
152
153 /* Return to previous state of the error-mode bit flags. */
154 SetErrorMode( uMode );
155
156 return (void *) hModule;
157}
158
159int dlclose( void *handle )
160{
161 HMODULE hModule = (HMODULE) handle;
162 BOOL ret;
163
164 /* Save handle for error message */
165 _snprintf_s( last_name, MAX_PATH, MAX_PATH, "0x%p", handle );
166
167 ret = FreeLibrary( hModule );
168
169 /* If the object was loaded with RTLD_GLOBAL, remove it from list of global
170 * objects.
171 */
172 if( ret )
173 global_object_rem( hModule );
174
175 /* dlclose's return value in inverted in relation to FreeLibrary's. */
176 ret = !ret;
177
178 return (int) ret;
179}
180
181void *dlsym( void *handle, const char *name )
182{
183 FARPROC symbol;
184 HMODULE myhandle = (HMODULE) handle;
185
186 /* Save symbol name for error message */
187 copy_string( last_name, sizeof(last_name), name );
188
189 symbol = GetProcAddress( myhandle, name );
190#if 0
191 if( symbol == NULL )
192 {
193 HMODULE hModule;
194
195 /* If the handle for the original program file is passed, also search
196 * in all globally loaded objects.
197 */
198
199 hModule = GetModuleHandle( NULL );
200
201 if( hModule == handle )
202 {
203 int i;
204
205 for( i = 0 ; i < MAX_OBJECTS ; i++ )
206 {
207 if( global_objects[i] != 0 )
208 {
209 symbol = GetProcAddress( global_objects[i], name );
210 if( symbol != NULL )
211 break;
212 }
213 }
214 }
215
216
217 CloseHandle( hModule );
218 }
219#endif
220 return (void*) symbol;
221}
222
223char *dlerror( void )
224{
225 DWORD dwMessageId;
226 /* POSIX says this function doesn't have to be thread-safe, so we use one
227 * static buffer.
228 * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
229 * the limit.
230 */
231 static char lpBuffer[65535];
232 DWORD ret;
233
234 dwMessageId = GetLastError( );
235
236 if( dwMessageId == 0 )
237 return NULL;
238
239 /* Format error message to:
240 * "<argument to function that failed>": <Windows localized error message>
241 */
242 ret = copy_string( lpBuffer, sizeof(lpBuffer), "\"" );
243 ret += copy_string( lpBuffer+ret, sizeof(lpBuffer)-ret, last_name );
244 ret += copy_string( lpBuffer+ret, sizeof(lpBuffer)-ret, "\": " );
245 ret += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId,
246 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
247 lpBuffer+ret, sizeof(lpBuffer)-ret, NULL );
248
249 if( ret > 1 )
250 {
251 /* POSIX says the string must not have trailing <newline> */
252 if( lpBuffer[ret-2] == '\r' && lpBuffer[ret-1] == '\n' )
253 lpBuffer[ret-2] = '\0';
254 }
255
256 /* POSIX says that invoking dlerror( ) a second time, immediately following
257 * a prior invocation, shall result in NULL being returned.
258 */
259 SetLastError(0);
260
261 return lpBuffer;
262}
263
diff --git a/addons/library.xbmc.addon/dlfcn-win32.h b/addons/library.xbmc.addon/dlfcn-win32.h
new file mode 100644
index 0000000..b93a029
--- /dev/null
+++ b/addons/library.xbmc.addon/dlfcn-win32.h
@@ -0,0 +1,46 @@
1#pragma once
2/*
3 * dlfcn-win32
4 * Copyright (c) 2007 Ramiro Polla
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#ifndef DLFCN_H
22#define DLFCN_H
23
24/* POSIX says these are implementation-defined.
25 * To simplify use with Windows API, we treat them the same way.
26 */
27
28#define RTLD_LAZY 0
29#define RTLD_NOW 0
30
31#define RTLD_GLOBAL (1 << 1)
32#define RTLD_LOCAL (1 << 2)
33
34/* These two were added in The Open Group Base Specifications Issue 6.
35 * Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
36 */
37
38#define RTLD_DEFAULT 0
39#define RTLD_NEXT 0
40
41void *dlopen ( const char *file, int mode );
42int dlclose( void *handle );
43void *dlsym ( void *handle, const char *name );
44char *dlerror( void );
45
46#endif /* DLFCN-WIN32_H */
diff --git a/addons/library.xbmc.addon/libXBMC_addon.h b/addons/library.xbmc.addon/libXBMC_addon.h
new file mode 100644
index 0000000..c3ed54f
--- /dev/null
+++ b/addons/library.xbmc.addon/libXBMC_addon.h
@@ -0,0 +1,600 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <string>
23#include <vector>
24#include <string.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <stdint.h>
28#include <stdarg.h>
29
30#ifdef _WIN32 // windows
31#ifndef _SSIZE_T_DEFINED
32typedef intptr_t ssize_t;
33#define _SSIZE_T_DEFINED
34#endif // !_SSIZE_T_DEFINED
35#include "dlfcn-win32.h"
36#define ADDON_DLL "\\library.xbmc.addon\\libXBMC_addon" ADDON_HELPER_EXT
37#define ADDON_HELPER_EXT ".dll"
38#else
39#if defined(__APPLE__) // osx
40#if defined(__POWERPC__)
41#define ADDON_HELPER_ARCH "powerpc-osx"
42#elif defined(__arm__)
43#define ADDON_HELPER_ARCH "arm-osx"
44#elif defined(__x86_64__)
45#define ADDON_HELPER_ARCH "x86-osx"
46#else
47#define ADDON_HELPER_ARCH "x86-osx"
48#endif
49#else // linux
50#if defined(__x86_64__)
51#define ADDON_HELPER_ARCH "x86_64-linux"
52#elif defined(_POWERPC)
53#define ADDON_HELPER_ARCH "powerpc-linux"
54#elif defined(_POWERPC64)
55#define ADDON_HELPER_ARCH "powerpc64-linux"
56#elif defined(__ARMEL__)
57#define ADDON_HELPER_ARCH "arm"
58#elif defined(__mips__)
59#define ADDON_HELPER_ARCH "mips"
60#else
61#define ADDON_HELPER_ARCH "i486-linux"
62#endif
63#endif
64#include <dlfcn.h> // linux+osx
65#define ADDON_HELPER_EXT ".so"
66#define ADDON_DLL_NAME "libXBMC_addon-" ADDON_HELPER_ARCH ADDON_HELPER_EXT
67#define ADDON_DLL "/library.xbmc.addon/" ADDON_DLL_NAME
68#endif
69#if defined(ANDROID)
70#include <sys/stat.h>
71#endif
72
73#ifdef LOG_DEBUG
74#undef LOG_DEBUG
75#endif
76#ifdef LOG_INFO
77#undef LOG_INFO
78#endif
79#ifdef LOG_NOTICE
80#undef LOG_NOTICE
81#endif
82#ifdef LOG_ERROR
83#undef LOG_ERROR
84#endif
85
86namespace ADDON
87{
88 typedef enum addon_log
89 {
90 LOG_DEBUG,
91 LOG_INFO,
92 LOG_NOTICE,
93 LOG_ERROR
94 } addon_log_t;
95
96 typedef enum queue_msg
97 {
98 QUEUE_INFO,
99 QUEUE_WARNING,
100 QUEUE_ERROR
101 } queue_msg_t;
102
103 class CHelper_libXBMC_addon
104 {
105 public:
106 CHelper_libXBMC_addon()
107 {
108 m_libXBMC_addon = NULL;
109 m_Handle = NULL;
110 }
111
112 ~CHelper_libXBMC_addon()
113 {
114 if (m_libXBMC_addon)
115 {
116 XBMC_unregister_me(m_Handle, m_Callbacks);
117 dlclose(m_libXBMC_addon);
118 }
119 }
120
121 bool RegisterMe(void *Handle)
122 {
123 m_Handle = Handle;
124
125 std::string libBasePath;
126 libBasePath = ((cb_array*)m_Handle)->libPath;
127 libBasePath += ADDON_DLL;
128
129#if defined(ANDROID)
130 struct stat st;
131 if(stat(libBasePath.c_str(),&st) != 0)
132 {
133 std::string tempbin = getenv("XBMC_ANDROID_LIBS");
134 libBasePath = tempbin + "/" + ADDON_DLL_NAME;
135 }
136#endif
137
138 m_libXBMC_addon = dlopen(libBasePath.c_str(), RTLD_LAZY);
139 if (m_libXBMC_addon == NULL)
140 {
141 fprintf(stderr, "Unable to load %s\n", dlerror());
142 return false;
143 }
144
145 XBMC_register_me = (void* (*)(void *HANDLE))
146 dlsym(m_libXBMC_addon, "XBMC_register_me");
147 if (XBMC_register_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
148
149 XBMC_unregister_me = (void (*)(void* HANDLE, void* CB))
150 dlsym(m_libXBMC_addon, "XBMC_unregister_me");
151 if (XBMC_unregister_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
152
153 XBMC_log = (void (*)(void* HANDLE, void* CB, const addon_log_t loglevel, const char *msg))
154 dlsym(m_libXBMC_addon, "XBMC_log");
155 if (XBMC_log == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
156
157 XBMC_get_setting = (bool (*)(void* HANDLE, void* CB, const char* settingName, void *settingValue))
158 dlsym(m_libXBMC_addon, "XBMC_get_setting");
159 if (XBMC_get_setting == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
160
161 XBMC_queue_notification = (void (*)(void* HANDLE, void* CB, const queue_msg_t loglevel, const char *msg))
162 dlsym(m_libXBMC_addon, "XBMC_queue_notification");
163 if (XBMC_queue_notification == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
164
165 XBMC_wake_on_lan = (bool (*)(void* HANDLE, void *CB, const char *mac))
166 dlsym(m_libXBMC_addon, "XBMC_wake_on_lan");
167 if (XBMC_wake_on_lan == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
168
169 XBMC_unknown_to_utf8 = (char* (*)(void* HANDLE, void* CB, const char* str))
170 dlsym(m_libXBMC_addon, "XBMC_unknown_to_utf8");
171 if (XBMC_unknown_to_utf8 == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
172
173 XBMC_get_localized_string = (char* (*)(void* HANDLE, void* CB, int dwCode))
174 dlsym(m_libXBMC_addon, "XBMC_get_localized_string");
175 if (XBMC_get_localized_string == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
176
177 XBMC_free_string = (void (*)(void* HANDLE, void* CB, char* str))
178 dlsym(m_libXBMC_addon, "XBMC_free_string");
179 if (XBMC_free_string == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
180
181 XBMC_get_dvd_menu_language = (char* (*)(void* HANDLE, void* CB))
182 dlsym(m_libXBMC_addon, "XBMC_get_dvd_menu_language");
183 if (XBMC_get_dvd_menu_language == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
184
185 XBMC_open_file = (void* (*)(void* HANDLE, void* CB, const char* strFileName, unsigned int flags))
186 dlsym(m_libXBMC_addon, "XBMC_open_file");
187 if (XBMC_open_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
188
189 XBMC_open_file_for_write = (void* (*)(void* HANDLE, void* CB, const char* strFileName, bool bOverWrite))
190 dlsym(m_libXBMC_addon, "XBMC_open_file_for_write");
191 if (XBMC_open_file_for_write == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
192
193 XBMC_read_file = (ssize_t (*)(void* HANDLE, void* CB, void* file, void* lpBuf, size_t uiBufSize))
194 dlsym(m_libXBMC_addon, "XBMC_read_file");
195 if (XBMC_read_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
196
197 XBMC_read_file_string = (bool (*)(void* HANDLE, void* CB, void* file, char *szLine, int iLineLength))
198 dlsym(m_libXBMC_addon, "XBMC_read_file_string");
199 if (XBMC_read_file_string == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
200
201 XBMC_write_file = (ssize_t (*)(void* HANDLE, void* CB, void* file, const void* lpBuf, size_t uiBufSize))
202 dlsym(m_libXBMC_addon, "XBMC_write_file");
203 if (XBMC_write_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
204
205 XBMC_flush_file = (void (*)(void* HANDLE, void* CB, void* file))
206 dlsym(m_libXBMC_addon, "XBMC_flush_file");
207 if (XBMC_flush_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
208
209 XBMC_seek_file = (int64_t (*)(void* HANDLE, void* CB, void* file, int64_t iFilePosition, int iWhence))
210 dlsym(m_libXBMC_addon, "XBMC_seek_file");
211 if (XBMC_seek_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
212
213 XBMC_truncate_file = (int (*)(void* HANDLE, void* CB, void* file, int64_t iSize))
214 dlsym(m_libXBMC_addon, "XBMC_truncate_file");
215 if (XBMC_truncate_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
216
217 XBMC_get_file_position = (int64_t (*)(void* HANDLE, void* CB, void* file))
218 dlsym(m_libXBMC_addon, "XBMC_get_file_position");
219 if (XBMC_get_file_position == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
220
221 XBMC_get_file_length = (int64_t (*)(void* HANDLE, void* CB, void* file))
222 dlsym(m_libXBMC_addon, "XBMC_get_file_length");
223 if (XBMC_get_file_length == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
224
225 XBMC_close_file = (void (*)(void* HANDLE, void* CB, void* file))
226 dlsym(m_libXBMC_addon, "XBMC_close_file");
227 if (XBMC_close_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
228
229 XBMC_get_file_chunk_size = (int (*)(void* HANDLE, void* CB, void* file))
230 dlsym(m_libXBMC_addon, "XBMC_get_file_chunk_size");
231 if (XBMC_get_file_chunk_size == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
232
233 XBMC_file_exists = (bool (*)(void* HANDLE, void* CB, const char *strFileName, bool bUseCache))
234 dlsym(m_libXBMC_addon, "XBMC_file_exists");
235 if (XBMC_file_exists == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
236
237 XBMC_stat_file = (int (*)(void* HANDLE, void* CB, const char *strFileName, struct __stat64* buffer))
238 dlsym(m_libXBMC_addon, "XBMC_stat_file");
239 if (XBMC_stat_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
240
241 XBMC_delete_file = (bool (*)(void* HANDLE, void* CB, const char *strFileName))
242 dlsym(m_libXBMC_addon, "XBMC_delete_file");
243 if (XBMC_delete_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
244
245 XBMC_can_open_directory = (bool (*)(void* HANDLE, void* CB, const char* strURL))
246 dlsym(m_libXBMC_addon, "XBMC_can_open_directory");
247 if (XBMC_can_open_directory == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
248
249 XBMC_create_directory = (bool (*)(void* HANDLE, void* CB, const char* strPath))
250 dlsym(m_libXBMC_addon, "XBMC_create_directory");
251 if (XBMC_create_directory == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
252
253 XBMC_directory_exists = (bool (*)(void* HANDLE, void* CB, const char* strPath))
254 dlsym(m_libXBMC_addon, "XBMC_directory_exists");
255 if (XBMC_directory_exists == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
256
257 XBMC_remove_directory = (bool (*)(void* HANDLE, void* CB, const char* strPath))
258 dlsym(m_libXBMC_addon, "XBMC_remove_directory");
259 if (XBMC_remove_directory == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
260
261 m_Callbacks = XBMC_register_me(m_Handle);
262 return m_Callbacks != NULL;
263 }
264
265 /*!
266 * @brief Add a message to XBMC's log.
267 * @param loglevel The log level of the message.
268 * @param format The format of the message to pass to XBMC.
269 */
270 void Log(const addon_log_t loglevel, const char *format, ... )
271 {
272 char buffer[16384];
273 va_list args;
274 va_start (args, format);
275 vsprintf (buffer, format, args);
276 va_end (args);
277 return XBMC_log(m_Handle, m_Callbacks, loglevel, buffer);
278 }
279
280 /*!
281 * @brief Get a settings value for this add-on.
282 * @param settingName The name of the setting to get.
283 * @param settingValue The value.
284 * @return True if the settings was fetched successfully, false otherwise.
285 */
286 bool GetSetting(const char* settingName, void *settingValue)
287 {
288 return XBMC_get_setting(m_Handle, m_Callbacks, settingName, settingValue);
289 }
290
291 /*!
292 * @brief Queue a notification in the GUI.
293 * @param type The message type.
294 * @param format The format of the message to pass to display in XBMC.
295 */
296 void QueueNotification(const queue_msg_t type, const char *format, ... )
297 {
298 char buffer[16384];
299 va_list args;
300 va_start (args, format);
301 vsprintf (buffer, format, args);
302 va_end (args);
303 return XBMC_queue_notification(m_Handle, m_Callbacks, type, buffer);
304 }
305
306 /*!
307 * @brief Send WakeOnLan magic packet.
308 * @param mac Network address of the host to wake.
309 * @return True if the magic packet was successfully sent, false otherwise.
310 */
311 bool WakeOnLan(const char* mac)
312 {
313 return XBMC_wake_on_lan(m_Handle, m_Callbacks, mac);
314 }
315
316 /*!
317 * @brief Translate a string with an unknown encoding to UTF8.
318 * @param str The string to translate.
319 * @return The string translated to UTF8. Must be freed by calling FreeString() when done.
320 */
321 char* UnknownToUTF8(const char* str)
322 {
323 return XBMC_unknown_to_utf8(m_Handle, m_Callbacks, str);
324 }
325
326 /*!
327 * @brief Get a localised message.
328 * @param dwCode The code of the message to get.
329 * @return The message. Must be freed by calling FreeString() when done.
330 */
331 char* GetLocalizedString(int dwCode)
332 {
333 return XBMC_get_localized_string(m_Handle, m_Callbacks, dwCode);
334 }
335
336
337 /*!
338 * @brief Get the DVD menu language.
339 * @return The language. Must be freed by calling FreeString() when done.
340 */
341 char* GetDVDMenuLanguage()
342 {
343 return XBMC_get_dvd_menu_language(m_Handle, m_Callbacks);
344 }
345
346 /*!
347 * @brief Free the memory used by str
348 * @param str The string to free
349 */
350 void FreeString(char* str)
351 {
352 return XBMC_free_string(m_Handle, m_Callbacks, str);
353 }
354
355 /*!
356 * @brief Open the file with filename via XBMC's CFile. Needs to be closed by calling CloseFile() when done.
357 * @param strFileName The filename to open.
358 * @param flags The flags to pass. Documented in XBMC's File.h
359 * @return A handle for the file, or NULL if it couldn't be opened.
360 */
361 void* OpenFile(const char* strFileName, unsigned int flags)
362 {
363 return XBMC_open_file(m_Handle, m_Callbacks, strFileName, flags);
364 }
365
366 /*!
367 * @brief Open the file with filename via XBMC's CFile in write mode. Needs to be closed by calling CloseFile() when done.
368 * @param strFileName The filename to open.
369 * @param bOverWrite True to overwrite, false otherwise.
370 * @return A handle for the file, or NULL if it couldn't be opened.
371 */
372 void* OpenFileForWrite(const char* strFileName, bool bOverWrite)
373 {
374 return XBMC_open_file_for_write(m_Handle, m_Callbacks, strFileName, bOverWrite);
375 }
376
377 /*!
378 * @brief Read from an open file.
379 * @param file The file handle to read from.
380 * @param lpBuf The buffer to store the data in.
381 * @param uiBufSize The size of the buffer.
382 * @return number of successfully read bytes if any bytes were read and stored in
383 * buffer, zero if no bytes are available to read (end of file was reached)
384 * or undetectable error occur, -1 in case of any explicit error
385 */
386 ssize_t ReadFile(void* file, void* lpBuf, size_t uiBufSize)
387 {
388 return XBMC_read_file(m_Handle, m_Callbacks, file, lpBuf, uiBufSize);
389 }
390
391 /*!
392 * @brief Read a string from an open file.
393 * @param file The file handle to read from.
394 * @param szLine The buffer to store the data in.
395 * @param iLineLength The size of the buffer.
396 * @return True when a line was read, false otherwise.
397 */
398 bool ReadFileString(void* file, char *szLine, int iLineLength)
399 {
400 return XBMC_read_file_string(m_Handle, m_Callbacks, file, szLine, iLineLength);
401 }
402
403 /*!
404 * @brief Write to a file opened in write mode.
405 * @param file The file handle to write to.
406 * @param lpBuf The data to write.
407 * @param uiBufSize Size of the data to write.
408 * @return number of successfully written bytes if any bytes were written,
409 * zero if no bytes were written and no detectable error occur,
410 * -1 in case of any explicit error
411 */
412 ssize_t WriteFile(void* file, const void* lpBuf, size_t uiBufSize)
413 {
414 return XBMC_write_file(m_Handle, m_Callbacks, file, lpBuf, uiBufSize);
415 }
416
417 /*!
418 * @brief Flush buffered data.
419 * @param file The file handle to flush the data for.
420 */
421 void FlushFile(void* file)
422 {
423 return XBMC_flush_file(m_Handle, m_Callbacks, file);
424 }
425
426 /*!
427 * @brief Seek in an open file.
428 * @param file The file handle to see in.
429 * @param iFilePosition The new position.
430 * @param iWhence Seek argument. See stdio.h for possible values.
431 * @return The new position.
432 */
433 int64_t SeekFile(void* file, int64_t iFilePosition, int iWhence)
434 {
435 return XBMC_seek_file(m_Handle, m_Callbacks, file, iFilePosition, iWhence);
436 }
437
438 /*!
439 * @brief Truncate a file to the requested size.
440 * @param file The file handle to truncate.
441 * @param iSize The new max size.
442 * @return New size?
443 */
444 int TruncateFile(void* file, int64_t iSize)
445 {
446 return XBMC_truncate_file(m_Handle, m_Callbacks, file, iSize);
447 }
448
449 /*!
450 * @brief The current position in an open file.
451 * @param file The file handle to get the position for.
452 * @return The requested position.
453 */
454 int64_t GetFilePosition(void* file)
455 {
456 return XBMC_get_file_position(m_Handle, m_Callbacks, file);
457 }
458
459 /*!
460 * @brief Get the file size of an open file.
461 * @param file The file to get the size for.
462 * @return The requested size.
463 */
464 int64_t GetFileLength(void* file)
465 {
466 return XBMC_get_file_length(m_Handle, m_Callbacks, file);
467 }
468
469 /*!
470 * @brief Close an open file.
471 * @param file The file handle to close.
472 */
473 void CloseFile(void* file)
474 {
475 return XBMC_close_file(m_Handle, m_Callbacks, file);
476 }
477
478 /*!
479 * @brief Get the chunk size for an open file.
480 * @param file the file handle to get the size for.
481 * @return The requested size.
482 */
483 int GetFileChunkSize(void* file)
484 {
485 return XBMC_get_file_chunk_size(m_Handle, m_Callbacks, file);
486 }
487
488 /*!
489 * @brief Check if a file exists.
490 * @param strFileName The filename to check.
491 * @param bUseCache Check in file cache.
492 * @return true if the file exists false otherwise.
493 */
494 bool FileExists(const char *strFileName, bool bUseCache)
495 {
496 return XBMC_file_exists(m_Handle, m_Callbacks, strFileName, bUseCache);
497 }
498
499 /*!
500 * @brief Reads file status.
501 * @param strFileName The filename to read the status from.
502 * @param buffer The file status is written into this buffer.
503 * @return The file status was successfully read.
504 */
505 int StatFile(const char *strFileName, struct __stat64* buffer)
506 {
507 return XBMC_stat_file(m_Handle, m_Callbacks, strFileName, buffer);
508 }
509
510 /*!
511 * @brief Deletes a file.
512 * @param strFileName The filename to delete.
513 * @return The file was successfully deleted.
514 */
515 bool DeleteFile(const char *strFileName)
516 {
517 return XBMC_delete_file(m_Handle, m_Callbacks, strFileName);
518 }
519
520 /*!
521 * @brief Checks whether a directory can be opened.
522 * @param strUrl The URL of the directory to check.
523 * @return True when it can be opened, false otherwise.
524 */
525 bool CanOpenDirectory(const char* strUrl)
526 {
527 return XBMC_can_open_directory(m_Handle, m_Callbacks, strUrl);
528 }
529
530 /*!
531 * @brief Creates a directory.
532 * @param strPath Path to the directory.
533 * @return True when it was created, false otherwise.
534 */
535 bool CreateDirectory(const char *strPath)
536 {
537 return XBMC_create_directory(m_Handle, m_Callbacks, strPath);
538 }
539
540 /*!
541 * @brief Checks if a directory exists.
542 * @param strPath Path to the directory.
543 * @return True when it exists, false otherwise.
544 */
545 bool DirectoryExists(const char *strPath)
546 {
547 return XBMC_directory_exists(m_Handle, m_Callbacks, strPath);
548 }
549
550 /*!
551 * @brief Removes a directory.
552 * @param strPath Path to the directory.
553 * @return True when it was removed, false otherwise.
554 */
555 bool RemoveDirectory(const char *strPath)
556 {
557 return XBMC_remove_directory(m_Handle, m_Callbacks, strPath);
558 }
559
560 protected:
561 void* (*XBMC_register_me)(void *HANDLE);
562 void (*XBMC_unregister_me)(void *HANDLE, void* CB);
563 void (*XBMC_log)(void *HANDLE, void* CB, const addon_log_t loglevel, const char *msg);
564 bool (*XBMC_get_setting)(void *HANDLE, void* CB, const char* settingName, void *settingValue);
565 void (*XBMC_queue_notification)(void *HANDLE, void* CB, const queue_msg_t type, const char *msg);
566 bool (*XBMC_wake_on_lan)(void *HANDLE, void* CB, const char* mac);
567 char* (*XBMC_unknown_to_utf8)(void *HANDLE, void* CB, const char* str);
568 char* (*XBMC_get_localized_string)(void *HANDLE, void* CB, int dwCode);
569 char* (*XBMC_get_dvd_menu_language)(void *HANDLE, void* CB);
570 void (*XBMC_free_string)(void *HANDLE, void* CB, char* str);
571 void* (*XBMC_open_file)(void *HANDLE, void* CB, const char* strFileName, unsigned int flags);
572 void* (*XBMC_open_file_for_write)(void *HANDLE, void* CB, const char* strFileName, bool bOverWrite);
573 ssize_t (*XBMC_read_file)(void *HANDLE, void* CB, void* file, void* lpBuf, size_t uiBufSize);
574 bool (*XBMC_read_file_string)(void *HANDLE, void* CB, void* file, char *szLine, int iLineLength);
575 ssize_t(*XBMC_write_file)(void *HANDLE, void* CB, void* file, const void* lpBuf, size_t uiBufSize);
576 void (*XBMC_flush_file)(void *HANDLE, void* CB, void* file);
577 int64_t (*XBMC_seek_file)(void *HANDLE, void* CB, void* file, int64_t iFilePosition, int iWhence);
578 int (*XBMC_truncate_file)(void *HANDLE, void* CB, void* file, int64_t iSize);
579 int64_t (*XBMC_get_file_position)(void *HANDLE, void* CB, void* file);
580 int64_t (*XBMC_get_file_length)(void *HANDLE, void* CB, void* file);
581 void (*XBMC_close_file)(void *HANDLE, void* CB, void* file);
582 int (*XBMC_get_file_chunk_size)(void *HANDLE, void* CB, void* file);
583 bool (*XBMC_file_exists)(void *HANDLE, void* CB, const char *strFileName, bool bUseCache);
584 int (*XBMC_stat_file)(void *HANDLE, void* CB, const char *strFileName, struct __stat64* buffer);
585 bool (*XBMC_delete_file)(void *HANDLE, void* CB, const char *strFileName);
586 bool (*XBMC_can_open_directory)(void *HANDLE, void* CB, const char* strURL);
587 bool (*XBMC_create_directory)(void *HANDLE, void* CB, const char* strPath);
588 bool (*XBMC_directory_exists)(void *HANDLE, void* CB, const char* strPath);
589 bool (*XBMC_remove_directory)(void *HANDLE, void* CB, const char* strPath);
590
591 private:
592 void *m_libXBMC_addon;
593 void *m_Handle;
594 void *m_Callbacks;
595 struct cb_array
596 {
597 const char* libPath;
598 };
599 };
600};
diff --git a/addons/library.xbmc.codec/libXBMC_codec.h b/addons/library.xbmc.codec/libXBMC_codec.h
new file mode 100644
index 0000000..3853f08
--- /dev/null
+++ b/addons/library.xbmc.codec/libXBMC_codec.h
@@ -0,0 +1,124 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <string>
23#include <vector>
24#include <string.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include "xbmc_codec_types.h"
28#include "libXBMC_addon.h"
29
30#ifdef _WIN32
31#define CODEC_HELPER_DLL "\\library.xbmc.codec\\libXBMC_codec" ADDON_HELPER_EXT
32#else
33#define CODEC_HELPER_DLL_NAME "libXBMC_codec-" ADDON_HELPER_ARCH ADDON_HELPER_EXT
34#define CODEC_HELPER_DLL "/library.xbmc.codec/" CODEC_HELPER_DLL_NAME
35#endif
36
37class CHelper_libXBMC_codec
38{
39public:
40 CHelper_libXBMC_codec(void)
41 {
42 m_libXBMC_codec = NULL;
43 m_Handle = NULL;
44 }
45
46 ~CHelper_libXBMC_codec(void)
47 {
48 if (m_libXBMC_codec)
49 {
50 CODEC_unregister_me(m_Handle, m_Callbacks);
51 dlclose(m_libXBMC_codec);
52 }
53 }
54
55 /*!
56 * @brief Resolve all callback methods
57 * @param handle Pointer to the add-on
58 * @return True when all methods were resolved, false otherwise.
59 */
60 bool RegisterMe(void* handle)
61 {
62 m_Handle = handle;
63
64 std::string libBasePath;
65 libBasePath = ((cb_array*)m_Handle)->libPath;
66 libBasePath += CODEC_HELPER_DLL;
67
68#if defined(ANDROID)
69 struct stat st;
70 if(stat(libBasePath.c_str(),&st) != 0)
71 {
72 std::string tempbin = getenv("XBMC_ANDROID_LIBS");
73 libBasePath = tempbin + "/" + CODEC_HELPER_DLL_NAME;
74 }
75#endif
76
77 m_libXBMC_codec = dlopen(libBasePath.c_str(), RTLD_LAZY);
78 if (m_libXBMC_codec == NULL)
79 {
80 fprintf(stderr, "Unable to load %s\n", dlerror());
81 return false;
82 }
83
84 CODEC_register_me = (void* (*)(void *HANDLE))
85 dlsym(m_libXBMC_codec, "CODEC_register_me");
86 if (CODEC_register_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
87
88 CODEC_unregister_me = (void (*)(void* HANDLE, void* CB))
89 dlsym(m_libXBMC_codec, "CODEC_unregister_me");
90 if (CODEC_unregister_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
91
92 CODEC_get_codec_by_name = (xbmc_codec_t (*)(void* HANDLE, void* CB, const char* strCodecName))
93 dlsym(m_libXBMC_codec, "CODEC_get_codec_by_name");
94 if (CODEC_get_codec_by_name == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
95
96 m_Callbacks = CODEC_register_me(m_Handle);
97 return m_Callbacks != NULL;
98 }
99
100 /*!
101 * @brief Get the codec id used by XBMC
102 * @param strCodecName The name of the codec
103 * @return The codec_id, or a codec_id with 0 values when not supported
104 */
105 xbmc_codec_t GetCodecByName(const char* strCodecName)
106 {
107 return CODEC_get_codec_by_name(m_Handle, m_Callbacks, strCodecName);
108 }
109
110protected:
111 void* (*CODEC_register_me)(void*);
112 void (*CODEC_unregister_me)(void*, void*);
113 xbmc_codec_t (*CODEC_get_codec_by_name)(void *HANDLE, void* CB, const char* strCodecName);
114
115private:
116 void* m_libXBMC_codec;
117 void* m_Handle;
118 void* m_Callbacks;
119 struct cb_array
120 {
121 const char* libPath;
122 };
123};
124
diff --git a/addons/library.xbmc.gui/libXBMC_gui.h b/addons/library.xbmc.gui/libXBMC_gui.h
new file mode 100644
index 0000000..8dbc38b
--- /dev/null
+++ b/addons/library.xbmc.gui/libXBMC_gui.h
@@ -0,0 +1,845 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <string>
23#include <vector>
24#include <string.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include "libXBMC_addon.h"
28
29typedef void* GUIHANDLE;
30
31#ifdef _WIN32
32#define GUI_HELPER_DLL "\\library.xbmc.gui\\libXBMC_gui" ADDON_HELPER_EXT
33#else
34#define GUI_HELPER_DLL_NAME "libXBMC_gui-" ADDON_HELPER_ARCH ADDON_HELPER_EXT
35#define GUI_HELPER_DLL "/library.xbmc.gui/" GUI_HELPER_DLL_NAME
36#endif
37
38/* current ADDONGUI API version */
39#define XBMC_GUI_API_VERSION "5.8.0"
40
41/* min. ADDONGUI API version */
42#define XBMC_GUI_MIN_API_VERSION "5.8.0"
43
44#define ADDON_ACTION_PREVIOUS_MENU 10
45#define ADDON_ACTION_CLOSE_DIALOG 51
46#define ADDON_ACTION_NAV_BACK 92
47
48class CAddonGUIWindow;
49class CAddonGUISpinControl;
50class CAddonGUIRadioButton;
51class CAddonGUIProgressControl;
52class CAddonListItem;
53class CAddonGUIRenderingControl;
54class CAddonGUISliderControl;
55class CAddonGUISettingsSliderControl;
56
57class CHelper_libXBMC_gui
58{
59public:
60 CHelper_libXBMC_gui()
61 {
62 m_libXBMC_gui = NULL;
63 m_Handle = NULL;
64 }
65
66 ~CHelper_libXBMC_gui()
67 {
68 if (m_libXBMC_gui)
69 {
70 GUI_unregister_me(m_Handle, m_Callbacks);
71 dlclose(m_libXBMC_gui);
72 }
73 }
74
75 bool RegisterMe(void *Handle)
76 {
77 m_Handle = Handle;
78
79 std::string libBasePath;
80 libBasePath = ((cb_array*)m_Handle)->libPath;
81 libBasePath += GUI_HELPER_DLL;
82
83#if defined(ANDROID)
84 struct stat st;
85 if(stat(libBasePath.c_str(),&st) != 0)
86 {
87 std::string tempbin = getenv("XBMC_ANDROID_LIBS");
88 libBasePath = tempbin + "/" + GUI_HELPER_DLL_NAME;
89 }
90#endif
91
92 m_libXBMC_gui = dlopen(libBasePath.c_str(), RTLD_LAZY);
93 if (m_libXBMC_gui == NULL)
94 {
95 fprintf(stderr, "Unable to load %s\n", dlerror());
96 return false;
97 }
98
99 GUI_register_me = (void* (*)(void *HANDLE))
100 dlsym(m_libXBMC_gui, "GUI_register_me");
101 if (GUI_register_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
102
103 GUI_unregister_me = (void (*)(void *HANDLE, void *CB))
104 dlsym(m_libXBMC_gui, "GUI_unregister_me");
105 if (GUI_unregister_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
106
107 GUI_lock = (void (*)(void *HANDLE, void *CB))
108 dlsym(m_libXBMC_gui, "GUI_lock");
109 if (GUI_lock == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
110
111 GUI_unlock = (void (*)(void *HANDLE, void *CB))
112 dlsym(m_libXBMC_gui, "GUI_unlock");
113 if (GUI_unlock == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
114
115 GUI_get_screen_height = (int (*)(void *HANDLE, void *CB))
116 dlsym(m_libXBMC_gui, "GUI_get_screen_height");
117 if (GUI_get_screen_height == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
118
119 GUI_get_screen_width = (int (*)(void *HANDLE, void *CB))
120 dlsym(m_libXBMC_gui, "GUI_get_screen_width");
121 if (GUI_get_screen_width == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
122
123 GUI_get_video_resolution = (int (*)(void *HANDLE, void *CB))
124 dlsym(m_libXBMC_gui, "GUI_get_video_resolution");
125 if (GUI_get_video_resolution == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
126
127 GUI_Window_create = (CAddonGUIWindow* (*)(void *HANDLE, void *CB, const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog))
128 dlsym(m_libXBMC_gui, "GUI_Window_create");
129 if (GUI_Window_create == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
130
131 GUI_Window_destroy = (void (*)(CAddonGUIWindow* p))
132 dlsym(m_libXBMC_gui, "GUI_Window_destroy");
133 if (GUI_Window_destroy == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
134
135 GUI_control_get_spin = (CAddonGUISpinControl* (*)(void *HANDLE, void *CB, CAddonGUIWindow *window, int controlId))
136 dlsym(m_libXBMC_gui, "GUI_control_get_spin");
137 if (GUI_control_get_spin == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
138
139 GUI_control_release_spin = (void (*)(CAddonGUISpinControl* p))
140 dlsym(m_libXBMC_gui, "GUI_control_release_spin");
141 if (GUI_control_release_spin == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
142
143 GUI_control_get_radiobutton = (CAddonGUIRadioButton* (*)(void *HANDLE, void *CB, CAddonGUIWindow *window, int controlId))
144 dlsym(m_libXBMC_gui, "GUI_control_get_radiobutton");
145 if (GUI_control_get_radiobutton == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
146
147 GUI_control_release_radiobutton = (void (*)(CAddonGUIRadioButton* p))
148 dlsym(m_libXBMC_gui, "GUI_control_release_radiobutton");
149 if (GUI_control_release_radiobutton == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
150
151 GUI_control_get_progress = (CAddonGUIProgressControl* (*)(void *HANDLE, void *CB, CAddonGUIWindow *window, int controlId))
152 dlsym(m_libXBMC_gui, "GUI_control_get_progress");
153 if (GUI_control_get_progress == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
154
155 GUI_control_release_progress = (void (*)(CAddonGUIProgressControl* p))
156 dlsym(m_libXBMC_gui, "GUI_control_release_progress");
157 if (GUI_control_release_progress == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
158
159 GUI_ListItem_create = (CAddonListItem* (*)(void *HANDLE, void *CB, const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path))
160 dlsym(m_libXBMC_gui, "GUI_ListItem_create");
161 if (GUI_ListItem_create == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
162
163 GUI_ListItem_destroy = (void (*)(CAddonListItem* p))
164 dlsym(m_libXBMC_gui, "GUI_ListItem_destroy");
165 if (GUI_ListItem_destroy == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
166
167 GUI_control_get_rendering = (CAddonGUIRenderingControl* (*)(void *HANDLE, void *CB, CAddonGUIWindow *window, int controlId))
168 dlsym(m_libXBMC_gui, "GUI_control_get_rendering");
169 if (GUI_control_get_rendering == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
170
171 GUI_control_release_rendering = (void (*)(CAddonGUIRenderingControl* p))
172 dlsym(m_libXBMC_gui, "GUI_control_release_rendering");
173 if (GUI_control_release_rendering == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
174
175 GUI_control_get_slider = (CAddonGUISliderControl* (*)(void *HANDLE, void *CB, CAddonGUIWindow *window, int controlId))
176 dlsym(m_libXBMC_gui, "GUI_control_get_slider");
177 if (GUI_control_get_slider == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
178
179 GUI_control_release_slider = (void (*)(CAddonGUISliderControl* p))
180 dlsym(m_libXBMC_gui, "GUI_control_release_slider");
181 if (GUI_control_release_slider == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
182
183 GUI_control_get_settings_slider = (CAddonGUISettingsSliderControl* (*)(void *HANDLE, void *CB, CAddonGUIWindow *window, int controlId))
184 dlsym(m_libXBMC_gui, "GUI_control_get_settings_slider");
185 if (GUI_control_get_settings_slider == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
186
187 GUI_control_release_settings_slider = (void (*)(CAddonGUISettingsSliderControl* p))
188 dlsym(m_libXBMC_gui, "GUI_control_release_settings_slider");
189 if (GUI_control_release_settings_slider == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
190
191 GUI_dialog_keyboard_show_and_get_input_with_head = (bool (*)(void *HANDLE, void *CB, char &aTextString, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, bool hiddenInput, unsigned int autoCloseMs))
192 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_get_input_with_head");
193 if (GUI_dialog_keyboard_show_and_get_input_with_head == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
194
195 GUI_dialog_keyboard_show_and_get_input = (bool (*)(void *HANDLE, void *CB, char &aTextString, unsigned int iMaxStringSize, bool allowEmptyResult, unsigned int autoCloseMs))
196 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_get_input");
197 if (GUI_dialog_keyboard_show_and_get_input == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
198
199 GUI_dialog_keyboard_show_and_get_new_password_with_head = (bool (*)(void *HANDLE, void *CB, char &newPassword, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, unsigned int autoCloseMs))
200 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_get_new_password_with_head");
201 if (GUI_dialog_keyboard_show_and_get_new_password_with_head == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
202
203 GUI_dialog_keyboard_show_and_get_new_password = (bool (*)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs))
204 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_get_new_password");
205 if (GUI_dialog_keyboard_show_and_get_new_password == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
206
207 GUI_dialog_keyboard_show_and_verify_new_password_with_head = (bool (*)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, unsigned int autoCloseMs))
208 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_verify_new_password_with_head");
209 if (GUI_dialog_keyboard_show_and_verify_new_password_with_head == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
210
211 GUI_dialog_keyboard_show_and_verify_new_password = (bool (*)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs))
212 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_verify_new_password");
213 if (GUI_dialog_keyboard_show_and_verify_new_password == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
214
215 GUI_dialog_keyboard_show_and_verify_password = (int (*)(void *HANDLE, void *CB, char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries, unsigned int autoCloseMs))
216 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_verify_password");
217 if (GUI_dialog_keyboard_show_and_verify_password == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
218
219 GUI_dialog_keyboard_show_and_get_filter = (bool (*)(void *HANDLE, void *CB, char &aTextString, unsigned int iMaxStringSize, bool searching, unsigned int autoCloseMs))
220 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_show_and_get_filter");
221 if (GUI_dialog_keyboard_show_and_get_filter == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
222
223 GUI_dialog_keyboard_send_text_to_active_keyboard = (bool (*)(void *HANDLE, void *CB, const char *aTextString, bool closeKeyboard))
224 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_send_text_to_active_keyboard");
225 if (GUI_dialog_keyboard_send_text_to_active_keyboard == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
226
227 GUI_dialog_keyboard_is_activated = (bool (*)(void *HANDLE, void *CB))
228 dlsym(m_libXBMC_gui, "GUI_dialog_keyboard_is_activated");
229 if (GUI_dialog_keyboard_is_activated == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
230
231 GUI_dialog_numeric_show_and_verify_new_password = (bool (*)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize))
232 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_verify_new_password");
233 if (GUI_dialog_numeric_show_and_verify_new_password == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
234
235 GUI_dialog_numeric_show_and_verify_password = (int (*)(void *HANDLE, void *CB, char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries))
236 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_verify_password");
237 if (GUI_dialog_numeric_show_and_verify_password == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
238
239 GUI_dialog_numeric_show_and_verify_input = (bool (*)(void *HANDLE, void *CB, char &strPassword, unsigned int iMaxStringSize, const char *strHeading, bool bGetUserInput))
240 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_verify_input");
241 if (GUI_dialog_numeric_show_and_verify_input == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
242
243 GUI_dialog_numeric_show_and_get_time = (bool (*)(void *HANDLE, void *CB, tm &time, const char *strHeading))
244 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_get_time");
245 if (GUI_dialog_numeric_show_and_get_time == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
246
247 GUI_dialog_numeric_show_and_get_date = (bool (*)(void *HANDLE, void *CB, tm &date, const char *strHeading))
248 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_get_date");
249 if (GUI_dialog_numeric_show_and_get_date == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
250
251 GUI_dialog_numeric_show_and_get_ipaddress = (bool (*)(void *HANDLE, void *CB, char &IPAddress, unsigned int iMaxStringSize, const char *strHeading))
252 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_get_ipaddress");
253 if (GUI_dialog_numeric_show_and_get_ipaddress == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
254
255 GUI_dialog_numeric_show_and_get_number = (bool (*)(void *HANDLE, void *CB, char &strInput, unsigned int iMaxStringSize, const char *strHeading, unsigned int iAutoCloseTimeoutMs))
256 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_get_number");
257 if (GUI_dialog_numeric_show_and_get_number == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
258
259 GUI_dialog_numeric_show_and_get_seconds = (bool (*)(void *HANDLE, void *CB, char &strTime, unsigned int iMaxStringSize, const char *strHeading))
260 dlsym(m_libXBMC_gui, "GUI_dialog_numeric_show_and_get_seconds");
261 if (GUI_dialog_numeric_show_and_get_seconds == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
262
263 GUI_dialog_filebrowser_show_and_get_file = (bool (*)(void *HANDLE, void *CB, const char *directory, const char *mask, const char *heading, char &path, unsigned int iMaxStringSize, bool useThumbs, bool useFileDirectories, bool singleList))
264 dlsym(m_libXBMC_gui, "GUI_dialog_filebrowser_show_and_get_file");
265 if (GUI_dialog_filebrowser_show_and_get_file == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
266
267 GUI_dialog_ok_show_and_get_input_single_text = (void (*)(void *HANDLE, void *CB, const char *heading, const char *text))
268 dlsym(m_libXBMC_gui, "GUI_dialog_ok_show_and_get_input_single_text");
269 if (GUI_dialog_ok_show_and_get_input_single_text == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
270
271 GUI_dialog_ok_show_and_get_input_line_text = (void (*)(void *HANDLE, void *CB, const char *heading, const char *line0, const char *line1, const char *line2))
272 dlsym(m_libXBMC_gui, "GUI_dialog_ok_show_and_get_input_line_text");
273 if (GUI_dialog_ok_show_and_get_input_line_text == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
274
275 GUI_dialog_yesno_show_and_get_input_singletext = (bool (*)(void *HANDLE, void *CB, const char *heading, const char *text, bool& bCanceled, const char *noLabel, const char *yesLabel))
276 dlsym(m_libXBMC_gui, "GUI_dialog_yesno_show_and_get_input_singletext");
277 if (GUI_dialog_yesno_show_and_get_input_singletext == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
278
279 GUI_dialog_yesno_show_and_get_input_linetext = (bool (*)(void *HANDLE, void *CB, const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel, const char *yesLabel))
280 dlsym(m_libXBMC_gui, "GUI_dialog_yesno_show_and_get_input_linetext");
281 if (GUI_dialog_yesno_show_and_get_input_linetext == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
282
283 GUI_dialog_yesno_show_and_get_input_linebuttontext = (bool (*)(void *HANDLE, void *CB, const char *heading, const char *line0, const char *line1, const char *line2, bool &bCanceled, const char *noLabel, const char *yesLabel))
284 dlsym(m_libXBMC_gui, "GUI_dialog_yesno_show_and_get_input_linebuttontext");
285 if (GUI_dialog_yesno_show_and_get_input_linebuttontext == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
286
287 GUI_dialog_text_viewer = (void (*)(void *hdl, void *cb, const char *heading, const char *text))
288 dlsym(m_libXBMC_gui, "GUI_dialog_text_viewer");
289 if (GUI_dialog_text_viewer == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
290
291 GUI_dialog_select = (int (*)(void *hdl, void *cb, const char *heading, const char *entries[], unsigned int size, int selected))
292 dlsym(m_libXBMC_gui, "GUI_dialog_select");
293 if (GUI_dialog_select == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
294
295 m_Callbacks = GUI_register_me(m_Handle);
296 return m_Callbacks != NULL;
297 }
298
299 void Lock()
300 {
301 return GUI_lock(m_Handle, m_Callbacks);
302 }
303
304 void Unlock()
305 {
306 return GUI_unlock(m_Handle, m_Callbacks);
307 }
308
309 int GetScreenHeight()
310 {
311 return GUI_get_screen_height(m_Handle, m_Callbacks);
312 }
313
314 int GetScreenWidth()
315 {
316 return GUI_get_screen_width(m_Handle, m_Callbacks);
317 }
318
319 int GetVideoResolution()
320 {
321 return GUI_get_video_resolution(m_Handle, m_Callbacks);
322 }
323
324 CAddonGUIWindow* Window_create(const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog)
325 {
326 return GUI_Window_create(m_Handle, m_Callbacks, xmlFilename, defaultSkin, forceFallback, asDialog);
327 }
328
329 void Window_destroy(CAddonGUIWindow* p)
330 {
331 return GUI_Window_destroy(p);
332 }
333
334 CAddonGUISpinControl* Control_getSpin(CAddonGUIWindow *window, int controlId)
335 {
336 return GUI_control_get_spin(m_Handle, m_Callbacks, window, controlId);
337 }
338
339 void Control_releaseSpin(CAddonGUISpinControl* p)
340 {
341 return GUI_control_release_spin(p);
342 }
343
344 CAddonGUIRadioButton* Control_getRadioButton(CAddonGUIWindow *window, int controlId)
345 {
346 return GUI_control_get_radiobutton(m_Handle, m_Callbacks, window, controlId);
347 }
348
349 void Control_releaseRadioButton(CAddonGUIRadioButton* p)
350 {
351 return GUI_control_release_radiobutton(p);
352 }
353
354 CAddonGUIProgressControl* Control_getProgress(CAddonGUIWindow *window, int controlId)
355 {
356 return GUI_control_get_progress(m_Handle, m_Callbacks, window, controlId);
357 }
358
359 void Control_releaseProgress(CAddonGUIProgressControl* p)
360 {
361 return GUI_control_release_progress(p);
362 }
363
364 CAddonListItem* ListItem_create(const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path)
365 {
366 return GUI_ListItem_create(m_Handle, m_Callbacks, label, label2, iconImage, thumbnailImage, path);
367 }
368
369 void ListItem_destroy(CAddonListItem* p)
370 {
371 return GUI_ListItem_destroy(p);
372 }
373
374 CAddonGUIRenderingControl* Control_getRendering(CAddonGUIWindow *window, int controlId)
375 {
376 return GUI_control_get_rendering(m_Handle, m_Callbacks, window, controlId);
377 }
378
379 void Control_releaseRendering(CAddonGUIRenderingControl* p)
380 {
381 return GUI_control_release_rendering(p);
382 }
383
384 CAddonGUISliderControl* Control_getSlider(CAddonGUIWindow *window, int controlId)
385 {
386 return GUI_control_get_slider(m_Handle, m_Callbacks, window, controlId);
387 }
388
389 void Control_releaseSlider(CAddonGUISliderControl* p)
390 {
391 return GUI_control_release_slider(p);
392 }
393
394 CAddonGUISettingsSliderControl* Control_getSettingsSlider(CAddonGUIWindow *window, int controlId)
395 {
396 return GUI_control_get_settings_slider(m_Handle, m_Callbacks, window, controlId);
397 }
398
399 void Control_releaseSettingsSlider(CAddonGUISettingsSliderControl* p)
400 {
401 return GUI_control_release_settings_slider(p);
402 }
403
404 /*! @name GUI Keyboard functions */
405 //@{
406 bool Dialog_Keyboard_ShowAndGetInput(char &strText, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, bool hiddenInput, unsigned int autoCloseMs = 0)
407 {
408 return GUI_dialog_keyboard_show_and_get_input_with_head(m_Handle, m_Callbacks, strText, iMaxStringSize, strHeading, allowEmptyResult, hiddenInput, autoCloseMs);
409 }
410
411 bool Dialog_Keyboard_ShowAndGetInput(char &strText, unsigned int iMaxStringSize, bool allowEmptyResult, unsigned int autoCloseMs = 0)
412 {
413 return GUI_dialog_keyboard_show_and_get_input(m_Handle, m_Callbacks, strText, iMaxStringSize, allowEmptyResult, autoCloseMs);
414 }
415
416 bool Dialog_Keyboard_ShowAndGetNewPassword(char &strNewPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, unsigned int autoCloseMs = 0)
417 {
418 return GUI_dialog_keyboard_show_and_get_new_password_with_head(m_Handle, m_Callbacks, strNewPassword, iMaxStringSize, strHeading, allowEmptyResult, autoCloseMs);
419 }
420
421 bool Dialog_Keyboard_ShowAndGetNewPassword(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs = 0)
422 {
423 return GUI_dialog_keyboard_show_and_get_new_password(m_Handle, m_Callbacks, strNewPassword, iMaxStringSize, autoCloseMs);
424 }
425
426 bool Dialog_Keyboard_ShowAndVerifyNewPassword(char &strNewPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, unsigned int autoCloseMs = 0)
427 {
428 return GUI_dialog_keyboard_show_and_verify_new_password_with_head(m_Handle, m_Callbacks, strNewPassword, iMaxStringSize, strHeading, allowEmptyResult, autoCloseMs);
429 }
430
431 bool Dialog_Keyboard_ShowAndVerifyNewPassword(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs = 0)
432 {
433 return GUI_dialog_keyboard_show_and_verify_new_password(m_Handle, m_Callbacks, strNewPassword, iMaxStringSize, autoCloseMs);
434 }
435
436 int Dialog_Keyboard_ShowAndVerifyPassword(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries, unsigned int autoCloseMs = 0)
437 {
438 return GUI_dialog_keyboard_show_and_verify_password(m_Handle, m_Callbacks, strPassword, iMaxStringSize, strHeading, iRetries, autoCloseMs);
439 }
440
441 bool Dialog_Keyboard_ShowAndGetFilter(char &strText, unsigned int iMaxStringSize, bool searching, unsigned int autoCloseMs = 0)
442 {
443 return GUI_dialog_keyboard_show_and_get_filter(m_Handle, m_Callbacks, strText, iMaxStringSize, searching, autoCloseMs);
444 }
445
446 bool Dialog_Keyboard_SendTextToActiveKeyboard(const char *aTextString, bool closeKeyboard = false)
447 {
448 return GUI_dialog_keyboard_send_text_to_active_keyboard(m_Handle, m_Callbacks, aTextString, closeKeyboard);
449 }
450
451 bool Dialog_Keyboard_isKeyboardActivated()
452 {
453 return GUI_dialog_keyboard_is_activated(m_Handle, m_Callbacks);
454 }
455 //@}
456
457 /*! @name GUI Numeric functions */
458 //@{
459 bool Dialog_Numeric_ShowAndVerifyNewPassword(char &strNewPassword, unsigned int iMaxStringSize)
460 {
461 return GUI_dialog_numeric_show_and_verify_new_password(m_Handle, m_Callbacks, strNewPassword, iMaxStringSize);
462 }
463
464 int Dialog_Numeric_ShowAndVerifyPassword(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries)
465 {
466 return GUI_dialog_numeric_show_and_verify_password(m_Handle, m_Callbacks, strPassword, iMaxStringSize, strHeading, iRetries);
467 }
468
469 bool Dialog_Numeric_ShowAndVerifyInput(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, bool bGetUserInput)
470 {
471 return GUI_dialog_numeric_show_and_verify_input(m_Handle, m_Callbacks, strPassword, iMaxStringSize, strHeading, bGetUserInput);
472 }
473
474 bool Dialog_Numeric_ShowAndGetTime(tm &time, const char *strHeading)
475 {
476 return GUI_dialog_numeric_show_and_get_time(m_Handle, m_Callbacks, time, strHeading);
477 }
478
479 bool Dialog_Numeric_ShowAndGetDate(tm &date, const char *strHeading)
480 {
481 return GUI_dialog_numeric_show_and_get_date(m_Handle, m_Callbacks, date, strHeading);
482 }
483
484 bool Dialog_Numeric_ShowAndGetIPAddress(char &strIPAddress, unsigned int iMaxStringSize, const char *strHeading)
485 {
486 return GUI_dialog_numeric_show_and_get_ipaddress(m_Handle, m_Callbacks, strIPAddress, iMaxStringSize, strHeading);
487 }
488
489 bool Dialog_Numeric_ShowAndGetNumber(char &strInput, unsigned int iMaxStringSize, const char *strHeading, unsigned int iAutoCloseTimeoutMs = 0)
490 {
491 return GUI_dialog_numeric_show_and_get_number(m_Handle, m_Callbacks, strInput, iMaxStringSize, strHeading, iAutoCloseTimeoutMs = 0);
492 }
493
494 bool Dialog_Numeric_ShowAndGetSeconds(char &strTime, unsigned int iMaxStringSize, const char *strHeading)
495 {
496 return GUI_dialog_numeric_show_and_get_seconds(m_Handle, m_Callbacks, strTime, iMaxStringSize, strHeading);
497 }
498 //@}
499
500 /*! @name GUI File browser functions */
501 //@{
502 bool Dialog_FileBrowser_ShowAndGetFile(const char *directory, const char *mask, const char *heading, char &strPath, unsigned int iMaxStringSize, bool useThumbs = false, bool useFileDirectories = false, bool singleList = false)
503 {
504 return GUI_dialog_filebrowser_show_and_get_file(m_Handle, m_Callbacks, directory, mask, heading, strPath, iMaxStringSize, useThumbs, useFileDirectories, singleList);
505 }
506 //@}
507
508 /*! @name GUI OK Dialog functions */
509 //@{
510 void Dialog_OK_ShowAndGetInput(const char *heading, const char *text)
511 {
512 GUI_dialog_ok_show_and_get_input_single_text(m_Handle, m_Callbacks, heading, text);
513 }
514
515 void Dialog_OK_ShowAndGetInput(const char *heading, const char *line0, const char *line1, const char *line2)
516 {
517 GUI_dialog_ok_show_and_get_input_line_text(m_Handle, m_Callbacks, heading, line0, line1, line2);
518 }
519 //@}
520
521 /*! @name GUI Yes No Dialog functions */
522 //@{
523 bool Dialog_YesNo_ShowAndGetInput(const char *heading, const char *text, bool& bCanceled, const char *noLabel = "", const char *yesLabel = "")
524 {
525 return GUI_dialog_yesno_show_and_get_input_singletext(m_Handle, m_Callbacks, heading, text, bCanceled, noLabel, yesLabel);
526 }
527
528 bool Dialog_YesNo_ShowAndGetInput(const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel = "", const char *yesLabel = "")
529 {
530 return GUI_dialog_yesno_show_and_get_input_linetext(m_Handle, m_Callbacks, heading, line0, line1, line2, noLabel, yesLabel);
531 }
532
533 bool Dialog_YesNo_ShowAndGetInput(const char *heading, const char *line0, const char *line1, const char *line2, bool &bCanceled, const char *noLabel = "", const char *yesLabel = "")
534 {
535 return GUI_dialog_yesno_show_and_get_input_linebuttontext(m_Handle, m_Callbacks, heading, line0, line1, line2, bCanceled, noLabel, yesLabel);
536 }
537 //@}
538
539 /*! @name GUI Text viewer Dialog */
540 //@{
541 void Dialog_TextViewer(const char *heading, const char *text)
542 {
543 return GUI_dialog_text_viewer(m_Handle, m_Callbacks, heading, text);
544 }
545 //@}
546
547 /*! @name GUI select Dialog */
548 //@{
549 int Dialog_Select(const char *heading, const char *entries[], unsigned int size, int selected = -1)
550 {
551 return GUI_dialog_select(m_Handle, m_Callbacks, heading, entries, size, selected);
552 }
553 //@}
554
555protected:
556 void* (*GUI_register_me)(void *HANDLE);
557 void (*GUI_unregister_me)(void *HANDLE, void* CB);
558 void (*GUI_lock)(void *HANDLE, void* CB);
559 void (*GUI_unlock)(void *HANDLE, void* CB);
560 int (*GUI_get_screen_height)(void *HANDLE, void* CB);
561 int (*GUI_get_screen_width)(void *HANDLE, void* CB);
562 int (*GUI_get_video_resolution)(void *HANDLE, void* CB);
563 CAddonGUIWindow* (*GUI_Window_create)(void *HANDLE, void* CB, const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog);
564 void (*GUI_Window_destroy)(CAddonGUIWindow* p);
565 CAddonGUISpinControl* (*GUI_control_get_spin)(void *HANDLE, void* CB, CAddonGUIWindow *window, int controlId);
566 void (*GUI_control_release_spin)(CAddonGUISpinControl* p);
567 CAddonGUIRadioButton* (*GUI_control_get_radiobutton)(void *HANDLE, void* CB, CAddonGUIWindow *window, int controlId);
568 void (*GUI_control_release_radiobutton)(CAddonGUIRadioButton* p);
569 CAddonGUIProgressControl* (*GUI_control_get_progress)(void *HANDLE, void* CB, CAddonGUIWindow *window, int controlId);
570 void (*GUI_control_release_progress)(CAddonGUIProgressControl* p);
571 CAddonListItem* (*GUI_ListItem_create)(void *HANDLE, void* CB, const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path);
572 void (*GUI_ListItem_destroy)(CAddonListItem* p);
573 CAddonGUIRenderingControl* (*GUI_control_get_rendering)(void *HANDLE, void* CB, CAddonGUIWindow *window, int controlId);
574 void (*GUI_control_release_rendering)(CAddonGUIRenderingControl* p);
575 CAddonGUISliderControl* (*GUI_control_get_slider)(void *HANDLE, void* CB, CAddonGUIWindow *window, int controlId);
576 void (*GUI_control_release_slider)(CAddonGUISliderControl* p);
577 CAddonGUISettingsSliderControl* (*GUI_control_get_settings_slider)(void *HANDLE, void* CB, CAddonGUIWindow *window, int controlId);
578 void (*GUI_control_release_settings_slider)(CAddonGUISettingsSliderControl* p);
579 bool (*GUI_dialog_keyboard_show_and_get_input_with_head)(void *HANDLE, void *CB, char &aTextString, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, bool hiddenInput, unsigned int autoCloseMs);
580 bool (*GUI_dialog_keyboard_show_and_get_input)(void *HANDLE, void *CB, char &aTextString, unsigned int iMaxStringSize, bool allowEmptyResult, unsigned int autoCloseMs);
581 bool (*GUI_dialog_keyboard_show_and_get_new_password_with_head)(void *HANDLE, void *CB, char &newPassword, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, unsigned int autoCloseMs);
582 bool (*GUI_dialog_keyboard_show_and_get_new_password)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs);
583 bool (*GUI_dialog_keyboard_show_and_verify_new_password_with_head)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, unsigned int autoCloseMs);
584 bool (*GUI_dialog_keyboard_show_and_verify_new_password)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs);
585 int (*GUI_dialog_keyboard_show_and_verify_password)(void *HANDLE, void *CB, char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries, unsigned int autoCloseMs);
586 bool (*GUI_dialog_keyboard_show_and_get_filter)(void *HANDLE, void *CB, char &aTextString, unsigned int iMaxStringSize, bool searching, unsigned int autoCloseMs);
587 bool (*GUI_dialog_keyboard_send_text_to_active_keyboard)(void *HANDLE, void *CB, const char *aTextString, bool closeKeyboard);
588 bool (*GUI_dialog_keyboard_is_activated)(void *HANDLE, void *CB);
589 bool (*GUI_dialog_numeric_show_and_verify_new_password)(void *HANDLE, void *CB, char &strNewPassword, unsigned int iMaxStringSize);
590 int (*GUI_dialog_numeric_show_and_verify_password)(void *HANDLE, void *CB, char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries);
591 bool (*GUI_dialog_numeric_show_and_verify_input)(void *HANDLE, void *CB, char &strPassword, unsigned int iMaxStringSize, const char *strHeading, bool bGetUserInput);
592 bool (*GUI_dialog_numeric_show_and_get_time)(void *HANDLE, void *CB, tm &time, const char *strHeading);
593 bool (*GUI_dialog_numeric_show_and_get_date)(void *HANDLE, void *CB, tm &date, const char *strHeading);
594 bool (*GUI_dialog_numeric_show_and_get_ipaddress)(void *HANDLE, void *CB, char &IPAddress, unsigned int iMaxStringSize, const char *strHeading);
595 bool (*GUI_dialog_numeric_show_and_get_number)(void *HANDLE, void *CB, char &strInput, unsigned int iMaxStringSize, const char *strHeading, unsigned int iAutoCloseTimeoutMs);
596 bool (*GUI_dialog_numeric_show_and_get_seconds)(void *HANDLE, void *CB, char &strTime, unsigned int iMaxStringSize, const char *strHeading);
597 bool (*GUI_dialog_filebrowser_show_and_get_file)(void *HANDLE, void *CB, const char *directory, const char *mask, const char *heading, char &path, unsigned int iMaxStringSize, bool useThumbs, bool useFileDirectories, bool singleList);
598 void (*GUI_dialog_ok_show_and_get_input_single_text)(void *HANDLE, void *CB, const char *heading, const char *text);
599 void (*GUI_dialog_ok_show_and_get_input_line_text)(void *HANDLE, void *CB, const char *heading, const char *line0, const char *line1, const char *line2);
600 bool (*GUI_dialog_yesno_show_and_get_input_singletext)(void *HANDLE, void *CB, const char *heading, const char *text, bool& bCanceled, const char *noLabel, const char *yesLabel);
601 bool (*GUI_dialog_yesno_show_and_get_input_linetext)(void *HANDLE, void *CB, const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel, const char *yesLabel);
602 bool (*GUI_dialog_yesno_show_and_get_input_linebuttontext)(void *HANDLE, void *CB, const char *heading, const char *line0, const char *line1, const char *line2, bool &bCanceled, const char *noLabel, const char *yesLabel);
603 void (*GUI_dialog_text_viewer)(void *hdl, void *cb, const char *heading, const char *text);
604 int (*GUI_dialog_select)(void *hdl, void *cb, const char *heading, const char *entries[], unsigned int size, int selected);
605
606private:
607 void *m_libXBMC_gui;
608 void *m_Handle;
609 void *m_Callbacks;
610 struct cb_array
611 {
612 const char* libPath;
613 };
614};
615
616class CAddonGUISpinControl
617{
618public:
619 CAddonGUISpinControl(void *hdl, void *cb, CAddonGUIWindow *window, int controlId);
620 virtual ~CAddonGUISpinControl(void) {}
621
622 virtual void SetVisible(bool yesNo);
623 virtual void SetText(const char *label);
624 virtual void Clear();
625 virtual void AddLabel(const char *label, int iValue);
626 virtual int GetValue();
627 virtual void SetValue(int iValue);
628
629private:
630 CAddonGUIWindow *m_Window;
631 int m_ControlId;
632 GUIHANDLE m_SpinHandle;
633 void *m_Handle;
634 void *m_cb;
635};
636
637class CAddonGUIRadioButton
638{
639public:
640 CAddonGUIRadioButton(void *hdl, void *cb, CAddonGUIWindow *window, int controlId);
641 virtual ~CAddonGUIRadioButton() {}
642
643 virtual void SetVisible(bool yesNo);
644 virtual void SetText(const char *label);
645 virtual void SetSelected(bool yesNo);
646 virtual bool IsSelected();
647
648private:
649 CAddonGUIWindow *m_Window;
650 int m_ControlId;
651 GUIHANDLE m_ButtonHandle;
652 void *m_Handle;
653 void *m_cb;
654};
655
656class CAddonGUIProgressControl
657{
658public:
659 CAddonGUIProgressControl(void *hdl, void *cb, CAddonGUIWindow *window, int controlId);
660 virtual ~CAddonGUIProgressControl(void) {}
661
662 virtual void SetPercentage(float fPercent);
663 virtual float GetPercentage() const;
664 virtual void SetInfo(int iInfo);
665 virtual int GetInfo() const;
666 virtual std::string GetDescription() const;
667
668private:
669 CAddonGUIWindow *m_Window;
670 int m_ControlId;
671 GUIHANDLE m_ProgressHandle;
672 void *m_Handle;
673 void *m_cb;
674};
675
676class CAddonGUISliderControl
677{
678public:
679 CAddonGUISliderControl(void *hdl, void *cb, CAddonGUIWindow *window, int controlId);
680 virtual ~CAddonGUISliderControl(void) {}
681
682 virtual void SetVisible(bool yesNo);
683 virtual std::string GetDescription() const;
684
685 virtual void SetIntRange(int iStart, int iEnd);
686 virtual void SetIntValue(int iValue);
687 virtual int GetIntValue() const;
688 virtual void SetIntInterval(int iInterval);
689
690 virtual void SetPercentage(float fPercent);
691 virtual float GetPercentage() const;
692
693 virtual void SetFloatRange(float fStart, float fEnd);
694 virtual void SetFloatValue(float fValue);
695 virtual float GetFloatValue() const;
696 virtual void SetFloatInterval(float fInterval);
697
698private:
699 CAddonGUIWindow *m_Window;
700 int m_ControlId;
701 GUIHANDLE m_SliderHandle;
702 void *m_Handle;
703 void *m_cb;
704};
705
706class CAddonGUISettingsSliderControl
707{
708public:
709 CAddonGUISettingsSliderControl(void *hdl, void *cb, CAddonGUIWindow *window, int controlId);
710 virtual ~CAddonGUISettingsSliderControl(void) {}
711
712 virtual void SetVisible(bool yesNo);
713 virtual void SetText(const char *label);
714 virtual std::string GetDescription() const;
715
716 virtual void SetIntRange(int iStart, int iEnd);
717 virtual void SetIntValue(int iValue);
718 virtual int GetIntValue() const;
719 virtual void SetIntInterval(int iInterval);
720
721 virtual void SetPercentage(float fPercent);
722 virtual float GetPercentage() const;
723
724 virtual void SetFloatRange(float fStart, float fEnd);
725 virtual void SetFloatValue(float fValue);
726 virtual float GetFloatValue() const;
727 virtual void SetFloatInterval(float fInterval);
728
729private:
730 CAddonGUIWindow *m_Window;
731 int m_ControlId;
732 GUIHANDLE m_SettingsSliderHandle;
733 void *m_Handle;
734 void *m_cb;
735};
736
737class CAddonListItem
738{
739friend class CAddonGUIWindow;
740
741public:
742 CAddonListItem(void *hdl, void *cb, const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path);
743 virtual ~CAddonListItem(void) {}
744
745 virtual const char *GetLabel();
746 virtual void SetLabel(const char *label);
747 virtual const char *GetLabel2();
748 virtual void SetLabel2(const char *label);
749 virtual void SetIconImage(const char *image);
750 virtual void SetThumbnailImage(const char *image);
751 virtual void SetInfo(const char *Info);
752 virtual void SetProperty(const char *key, const char *value);
753 virtual const char *GetProperty(const char *key) const;
754 virtual void SetPath(const char *Path);
755
756// {(char*)"select();
757// {(char*)"isSelected();
758protected:
759 GUIHANDLE m_ListItemHandle;
760 void *m_Handle;
761 void *m_cb;
762};
763
764class CAddonGUIWindow
765{
766friend class CAddonGUISpinControl;
767friend class CAddonGUIRadioButton;
768friend class CAddonGUIProgressControl;
769friend class CAddonGUIRenderingControl;
770friend class CAddonGUISliderControl;
771friend class CAddonGUISettingsSliderControl;
772
773public:
774 CAddonGUIWindow(void *hdl, void *cb, const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog);
775 virtual ~CAddonGUIWindow();
776
777 virtual bool Show();
778 virtual void Close();
779 virtual void DoModal();
780 virtual bool SetFocusId(int iControlId);
781 virtual int GetFocusId();
782 virtual bool SetCoordinateResolution(int res);
783 virtual void SetProperty(const char *key, const char *value);
784 virtual void SetPropertyInt(const char *key, int value);
785 virtual void SetPropertyBool(const char *key, bool value);
786 virtual void SetPropertyDouble(const char *key, double value);
787 virtual const char *GetProperty(const char *key) const;
788 virtual int GetPropertyInt(const char *key) const;
789 virtual bool GetPropertyBool(const char *key) const;
790 virtual double GetPropertyDouble(const char *key) const;
791 virtual void ClearProperties();
792 virtual int GetListSize();
793 virtual void ClearList();
794 virtual GUIHANDLE AddStringItem(const char *name, int itemPosition = -1);
795 virtual void AddItem(GUIHANDLE item, int itemPosition = -1);
796 virtual void AddItem(CAddonListItem *item, int itemPosition = -1);
797 virtual void RemoveItem(int itemPosition);
798 virtual GUIHANDLE GetListItem(int listPos);
799 virtual void SetCurrentListPosition(int listPos);
800 virtual int GetCurrentListPosition();
801 virtual void SetControlLabel(int controlId, const char *label);
802 virtual void MarkDirtyRegion();
803
804 virtual bool OnClick(int controlId);
805 virtual bool OnFocus(int controlId);
806 virtual bool OnInit();
807 virtual bool OnAction(int actionId);
808
809 GUIHANDLE m_cbhdl;
810 bool (*CBOnInit)(GUIHANDLE cbhdl);
811 bool (*CBOnFocus)(GUIHANDLE cbhdl, int controlId);
812 bool (*CBOnClick)(GUIHANDLE cbhdl, int controlId);
813 bool (*CBOnAction)(GUIHANDLE cbhdl, int actionId);
814
815protected:
816 GUIHANDLE m_WindowHandle;
817 void *m_Handle;
818 void *m_cb;
819};
820
821class CAddonGUIRenderingControl
822{
823public:
824 CAddonGUIRenderingControl(void *hdl, void *cb, CAddonGUIWindow *window, int controlId);
825 virtual ~CAddonGUIRenderingControl();
826 virtual void Init();
827
828 virtual bool Create(int x, int y, int w, int h, void *device);
829 virtual void Render();
830 virtual void Stop();
831 virtual bool Dirty();
832
833 GUIHANDLE m_cbhdl;
834 bool (*CBCreate)(GUIHANDLE cbhdl, int x, int y, int w, int h, void *device);
835 void (*CBRender)(GUIHANDLE cbhdl);
836 void (*CBStop)(GUIHANDLE cbhdl);
837 bool (*CBDirty)(GUIHANDLE cbhdl);
838
839private:
840 CAddonGUIWindow *m_Window;
841 int m_ControlId;
842 GUIHANDLE m_RenderingHandle;
843 void *m_Handle;
844 void *m_cb;
845};
diff --git a/addons/library.xbmc.pvr/libXBMC_pvr.h b/addons/library.xbmc.pvr/libXBMC_pvr.h
new file mode 100644
index 0000000..3116514
--- /dev/null
+++ b/addons/library.xbmc.pvr/libXBMC_pvr.h
@@ -0,0 +1,332 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <string>
23#include <vector>
24#include <string.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include "xbmc_pvr_types.h"
28#include "libXBMC_addon.h"
29
30#ifdef _WIN32
31#define PVR_HELPER_DLL "\\library.xbmc.pvr\\libXBMC_pvr" ADDON_HELPER_EXT
32#else
33#define PVR_HELPER_DLL_NAME "libXBMC_pvr-" ADDON_HELPER_ARCH ADDON_HELPER_EXT
34#define PVR_HELPER_DLL "/library.xbmc.pvr/" PVR_HELPER_DLL_NAME
35#endif
36
37#define DVD_TIME_BASE 1000000
38#define DVD_NOPTS_VALUE (-1LL<<52) // should be possible to represent in both double and __int64
39
40class CHelper_libXBMC_pvr
41{
42public:
43 CHelper_libXBMC_pvr(void)
44 {
45 m_libXBMC_pvr = NULL;
46 m_Handle = NULL;
47 }
48
49 ~CHelper_libXBMC_pvr(void)
50 {
51 if (m_libXBMC_pvr)
52 {
53 PVR_unregister_me(m_Handle, m_Callbacks);
54 dlclose(m_libXBMC_pvr);
55 }
56 }
57
58 /*!
59 * @brief Resolve all callback methods
60 * @param handle Pointer to the add-on
61 * @return True when all methods were resolved, false otherwise.
62 */
63 bool RegisterMe(void* handle)
64 {
65 m_Handle = handle;
66
67 std::string libBasePath;
68 libBasePath = ((cb_array*)m_Handle)->libPath;
69 libBasePath += PVR_HELPER_DLL;
70
71#if defined(ANDROID)
72 struct stat st;
73 if(stat(libBasePath.c_str(),&st) != 0)
74 {
75 std::string tempbin = getenv("XBMC_ANDROID_LIBS");
76 libBasePath = tempbin + "/" + PVR_HELPER_DLL_NAME;
77 }
78#endif
79
80 m_libXBMC_pvr = dlopen(libBasePath.c_str(), RTLD_LAZY);
81 if (m_libXBMC_pvr == NULL)
82 {
83 fprintf(stderr, "Unable to load %s\n", dlerror());
84 return false;
85 }
86
87 PVR_register_me = (void* (*)(void *HANDLE))
88 dlsym(m_libXBMC_pvr, "PVR_register_me");
89 if (PVR_register_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
90
91 PVR_unregister_me = (void (*)(void* HANDLE, void* CB))
92 dlsym(m_libXBMC_pvr, "PVR_unregister_me");
93 if (PVR_unregister_me == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
94
95 PVR_transfer_epg_entry = (void (*)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const EPG_TAG *epgentry))
96 dlsym(m_libXBMC_pvr, "PVR_transfer_epg_entry");
97 if (PVR_transfer_epg_entry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
98
99 PVR_transfer_channel_entry = (void (*)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_CHANNEL *chan))
100 dlsym(m_libXBMC_pvr, "PVR_transfer_channel_entry");
101 if (PVR_transfer_channel_entry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
102
103 PVR_transfer_timer_entry = (void (*)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_TIMER *timer))
104 dlsym(m_libXBMC_pvr, "PVR_transfer_timer_entry");
105 if (PVR_transfer_timer_entry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
106
107 PVR_transfer_recording_entry = (void (*)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_RECORDING *recording))
108 dlsym(m_libXBMC_pvr, "PVR_transfer_recording_entry");
109 if (PVR_transfer_recording_entry == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
110
111 PVR_add_menu_hook = (void (*)(void* HANDLE, void* CB, PVR_MENUHOOK *hook))
112 dlsym(m_libXBMC_pvr, "PVR_add_menu_hook");
113 if (PVR_add_menu_hook == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
114
115 PVR_recording = (void (*)(void* HANDLE, void* CB, const char *Name, const char *FileName, bool On))
116 dlsym(m_libXBMC_pvr, "PVR_recording");
117 if (PVR_recording == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
118
119 PVR_trigger_timer_update = (void (*)(void* HANDLE, void* CB))
120 dlsym(m_libXBMC_pvr, "PVR_trigger_timer_update");
121 if (PVR_trigger_timer_update == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
122
123 PVR_trigger_recording_update = (void (*)(void* HANDLE, void* CB))
124 dlsym(m_libXBMC_pvr, "PVR_trigger_recording_update");
125 if (PVR_trigger_recording_update == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
126
127 PVR_trigger_channel_update = (void (*)(void* HANDLE, void* CB))
128 dlsym(m_libXBMC_pvr, "PVR_trigger_channel_update");
129 if (PVR_trigger_channel_update == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
130
131 PVR_trigger_channel_groups_update = (void (*)(void* HANDLE, void* CB))
132 dlsym(m_libXBMC_pvr, "PVR_trigger_channel_groups_update");
133 if (PVR_trigger_channel_groups_update == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
134
135 PVR_trigger_epg_update = (void (*)(void* HANDLE, void* CB, unsigned int iChannelUid))
136 dlsym(m_libXBMC_pvr, "PVR_trigger_epg_update");
137 if (PVR_trigger_epg_update == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
138
139 PVR_transfer_channel_group = (void (*)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group))
140 dlsym(m_libXBMC_pvr, "PVR_transfer_channel_group");
141 if (PVR_transfer_channel_group == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
142
143 PVR_transfer_channel_group_member = (void (*)(void* HANDLE, void* CB, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member))
144 dlsym(m_libXBMC_pvr, "PVR_transfer_channel_group_member");
145 if (PVR_transfer_channel_group_member == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
146
147#ifdef USE_DEMUX
148 PVR_free_demux_packet = (void (*)(void* HANDLE, void* CB, DemuxPacket* pPacket))
149 dlsym(m_libXBMC_pvr, "PVR_free_demux_packet");
150 if (PVR_free_demux_packet == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
151
152 PVR_allocate_demux_packet = (DemuxPacket* (*)(void* HANDLE, void* CB, int iDataSize))
153 dlsym(m_libXBMC_pvr, "PVR_allocate_demux_packet");
154 if (PVR_allocate_demux_packet == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
155#endif
156
157 m_Callbacks = PVR_register_me(m_Handle);
158 return m_Callbacks != NULL;
159 }
160
161 /*!
162 * @brief Transfer an EPG tag from the add-on to XBMC
163 * @param handle The handle parameter that XBMC used when requesting the EPG data
164 * @param entry The entry to transfer to XBMC
165 */
166 void TransferEpgEntry(const ADDON_HANDLE handle, const EPG_TAG* entry)
167 {
168 return PVR_transfer_epg_entry(m_Handle, m_Callbacks, handle, entry);
169 }
170
171 /*!
172 * @brief Transfer a channel entry from the add-on to XBMC
173 * @param handle The handle parameter that XBMC used when requesting the channel list
174 * @param entry The entry to transfer to XBMC
175 */
176 void TransferChannelEntry(const ADDON_HANDLE handle, const PVR_CHANNEL* entry)
177 {
178 return PVR_transfer_channel_entry(m_Handle, m_Callbacks, handle, entry);
179 }
180
181 /*!
182 * @brief Transfer a timer entry from the add-on to XBMC
183 * @param handle The handle parameter that XBMC used when requesting the timers list
184 * @param entry The entry to transfer to XBMC
185 */
186 void TransferTimerEntry(const ADDON_HANDLE handle, const PVR_TIMER* entry)
187 {
188 return PVR_transfer_timer_entry(m_Handle, m_Callbacks, handle, entry);
189 }
190
191 /*!
192 * @brief Transfer a recording entry from the add-on to XBMC
193 * @param handle The handle parameter that XBMC used when requesting the recordings list
194 * @param entry The entry to transfer to XBMC
195 */
196 void TransferRecordingEntry(const ADDON_HANDLE handle, const PVR_RECORDING* entry)
197 {
198 return PVR_transfer_recording_entry(m_Handle, m_Callbacks, handle, entry);
199 }
200
201 /*!
202 * @brief Transfer a channel group from the add-on to XBMC. The group will be created if it doesn't exist.
203 * @param handle The handle parameter that XBMC used when requesting the channel groups list
204 * @param entry The entry to transfer to XBMC
205 */
206 void TransferChannelGroup(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP* entry)
207 {
208 return PVR_transfer_channel_group(m_Handle, m_Callbacks, handle, entry);
209 }
210
211 /*!
212 * @brief Transfer a channel group member entry from the add-on to XBMC. The channel will be added to the group if the group can be found.
213 * @param handle The handle parameter that XBMC used when requesting the channel group members list
214 * @param entry The entry to transfer to XBMC
215 */
216 void TransferChannelGroupMember(const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER* entry)
217 {
218 return PVR_transfer_channel_group_member(m_Handle, m_Callbacks, handle, entry);
219 }
220
221 /*!
222 * @brief Add or replace a menu hook for the context menu for this add-on
223 * @param hook The hook to add
224 */
225 void AddMenuHook(PVR_MENUHOOK* hook)
226 {
227 return PVR_add_menu_hook(m_Handle, m_Callbacks, hook);
228 }
229
230 /*!
231 * @brief Display a notification in XBMC that a recording started or stopped on the server
232 * @param strRecordingName The name of the recording to display
233 * @param strFileName The filename of the recording
234 * @param bOn True when recording started, false when it stopped
235 */
236 void Recording(const char* strRecordingName, const char* strFileName, bool bOn)
237 {
238 return PVR_recording(m_Handle, m_Callbacks, strRecordingName, strFileName, bOn);
239 }
240
241 /*!
242 * @brief Request XBMC to update it's list of timers
243 */
244 void TriggerTimerUpdate(void)
245 {
246 return PVR_trigger_timer_update(m_Handle, m_Callbacks);
247 }
248
249 /*!
250 * @brief Request XBMC to update it's list of recordings
251 */
252 void TriggerRecordingUpdate(void)
253 {
254 return PVR_trigger_recording_update(m_Handle, m_Callbacks);
255 }
256
257 /*!
258 * @brief Request XBMC to update it's list of channels
259 */
260 void TriggerChannelUpdate(void)
261 {
262 return PVR_trigger_channel_update(m_Handle, m_Callbacks);
263 }
264
265 /*!
266 * @brief Schedule an EPG update for the given channel channel
267 * @param iChannelUid The unique id of the channel for this add-on
268 */
269 void TriggerEpgUpdate(unsigned int iChannelUid)
270 {
271 return PVR_trigger_epg_update(m_Handle, m_Callbacks, iChannelUid);
272 }
273
274 /*!
275 * @brief Request XBMC to update it's list of channel groups
276 */
277 void TriggerChannelGroupsUpdate(void)
278 {
279 return PVR_trigger_channel_groups_update(m_Handle, m_Callbacks);
280 }
281
282#ifdef USE_DEMUX
283 /*!
284 * @brief Free a packet that was allocated with AllocateDemuxPacket
285 * @param pPacket The packet to free
286 */
287 void FreeDemuxPacket(DemuxPacket* pPacket)
288 {
289 return PVR_free_demux_packet(m_Handle, m_Callbacks, pPacket);
290 }
291
292 /*!
293 * @brief Allocate a demux packet. Free with FreeDemuxPacket
294 * @param iDataSize The size of the data that will go into the packet
295 * @return The allocated packet
296 */
297 DemuxPacket* AllocateDemuxPacket(int iDataSize)
298 {
299 return PVR_allocate_demux_packet(m_Handle, m_Callbacks, iDataSize);
300 }
301#endif
302
303protected:
304 void* (*PVR_register_me)(void*);
305 void (*PVR_unregister_me)(void*, void*);
306 void (*PVR_transfer_epg_entry)(void*, void*, const ADDON_HANDLE, const EPG_TAG*);
307 void (*PVR_transfer_channel_entry)(void*, void*, const ADDON_HANDLE, const PVR_CHANNEL*);
308 void (*PVR_transfer_timer_entry)(void*, void*, const ADDON_HANDLE, const PVR_TIMER*);
309 void (*PVR_transfer_recording_entry)(void*, void*, const ADDON_HANDLE, const PVR_RECORDING*);
310 void (*PVR_add_menu_hook)(void*, void*, PVR_MENUHOOK*);
311 void (*PVR_recording)(void*, void*, const char*, const char*, bool);
312 void (*PVR_trigger_channel_update)(void*, void*);
313 void (*PVR_trigger_channel_groups_update)(void*, void*);
314 void (*PVR_trigger_timer_update)(void*, void*);
315 void (*PVR_trigger_recording_update)(void* , void*);
316 void (*PVR_trigger_epg_update)(void*, void*, unsigned int);
317 void (*PVR_transfer_channel_group)(void*, void*, const ADDON_HANDLE, const PVR_CHANNEL_GROUP*);
318 void (*PVR_transfer_channel_group_member)(void*, void*, const ADDON_HANDLE, const PVR_CHANNEL_GROUP_MEMBER*);
319#ifdef USE_DEMUX
320 void (*PVR_free_demux_packet)(void*, void*, DemuxPacket*);
321 DemuxPacket* (*PVR_allocate_demux_packet)(void*, void*, int);
322#endif
323
324private:
325 void* m_libXBMC_pvr;
326 void* m_Handle;
327 void* m_Callbacks;
328 struct cb_array
329 {
330 const char* libPath;
331 };
332};
diff --git a/project/cmake/addons/CMakeLists.txt b/project/cmake/addons/CMakeLists.txt
new file mode 100644
index 0000000..0afc622
--- /dev/null
+++ b/project/cmake/addons/CMakeLists.txt
@@ -0,0 +1,249 @@
1project(kodi-addons)
2
3cmake_minimum_required(VERSION 2.8)
4
5list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
6
7if(NOT CMAKE_BUILD_TYPE)
8 set(CMAKE_BUILD_TYPE Release)
9endif()
10
11if(NOT CORE_SYSTEM_NAME)
12 string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME)
13endif()
14
15include(ExternalProject)
16
17### setup all the necessary paths
18if(NOT APP_ROOT AND NOT XBMCROOT)
19 set(APP_ROOT ${PROJECT_SOURCE_DIR}/../../..)
20elseif(NOT APP_ROOT)
21 file(TO_CMAKE_PATH "${XBMCROOT}" APP_ROOT)
22else()
23 file(TO_CMAKE_PATH "${APP_ROOT}" APP_ROOT)
24endif()
25get_filename_component(APP_ROOT "${APP_ROOT}" ABSOLUTE)
26
27if(NOT BUILD_DIR)
28 set(BUILD_DIR "${CMAKE_BINARY_DIR}/build")
29else()
30 file(TO_CMAKE_PATH "${BUILD_DIR}" BUILD_DIR)
31endif()
32get_filename_component(BUILD_DIR "${BUILD_DIR}" ABSOLUTE)
33
34if(NOT DEPENDS_PATH)
35 set(DEPENDS_PATH "${BUILD_DIR}/depends")
36else()
37 file(TO_CMAKE_PATH "${DEPENDS_PATH}" DEPENDS_PATH)
38endif()
39get_filename_component(DEPENDS_PATH "${DEPENDS_PATH}" ABSOLUTE)
40
41if(NOT PLATFORM_DIR)
42 set(PLATFORM_DIR ${APP_ROOT}/project/cmake/platform/${CORE_SYSTEM_NAME})
43 file(TO_CMAKE_PATH "${PLATFORM_DIR}" PLATFORM_DIR)
44endif()
45
46# make sure CMAKE_PREFIX_PATH is set
47if(NOT CMAKE_PREFIX_PATH)
48 set(CMAKE_PREFIX_PATH "${DEPENDS_PATH}")
49else()
50 file(TO_CMAKE_PATH "${CMAKE_PREFIX_PATH}" CMAKE_PREFIX_PATH)
51 list(APPEND CMAKE_PREFIX_PATH "${DEPENDS_PATH}")
52endif()
53
54# check for autoconf stuff to pass on
55if(AUTOCONF_FILES)
56 separate_arguments(AUTOCONF_FILES)
57 set(CROSS_AUTOCONF "yes")
58endif()
59
60if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT OR NOT CMAKE_INSTALL_PREFIX)
61 set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/output/addons")
62endif()
63list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX})
64
65set(BUILD_ARGS -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
66 -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
67 -DPACKAGE_CONFIG_PATH=${DEPENDS_PATH}/lib/pkgconfig
68 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
69 -DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}
70 -DCMAKE_USER_MAKE_RULES_OVERRIDE_CXX=${CMAKE_USER_MAKE_RULES_OVERRIDE_CXX}
71 -DCORE_SYSTEM_NAME=${CORE_SYSTEM_NAME}
72 -DBUILD_SHARED_LIBS=1
73 -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
74 -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS})
75
76if(PACKAGE_ZIP)
77 # needed for project installing
78 list(APPEND BUILD_ARGS -DPACKAGE_ZIP=1)
79 MESSAGE("package zip specified")
80endif()
81
82if(CMAKE_TOOLCHAIN_FILE)
83 list(APPEND BUILD_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
84 MESSAGE("toolchain specified")
85 MESSAGE(${BUILD_ARGS})
86endif()
87
88if(NOT ADDONS_TO_BUILD)
89 set(ADDONS_TO_BUILD "all")
90else()
91 message(STATUS "Building following addons: ${ADDONS_TO_BUILD}")
92 separate_arguments(ADDONS_TO_BUILD)
93endif()
94
95if(NOT KODI_LIB_DIR)
96 set(KODI_LIB_DIR "${DEPENDS_PATH}/lib/kodi")
97else()
98 file(TO_CMAKE_PATH "${KODI_LIB_DIR}" KODI_LIB_DIR)
99endif()
100
101# check for platform specific stuff
102if(EXISTS ${PLATFORM_DIR}/defines.txt)
103 file(STRINGS ${PLATFORM_DIR}/defines.txt platformdefines)
104
105 if(NOT ARCH_DEFINES AND platformdefines)
106 set(ARCH_DEFINES ${platformdefines})
107 endif()
108endif()
109
110# include check_target_platform() function
111include(${APP_ROOT}/project/cmake/scripts/common/check_target_platform.cmake)
112
113# check install permissions
114set(ADDON_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
115check_install_permissions(${CMAKE_INSTALL_PREFIX} can_write)
116if(NOT ${can_write} AND NOT WIN32)
117 set(NEED_SUDO TRUE)
118 set(ADDON_INSTALL_DIR ${CMAKE_BINARY_DIR}/.install)
119 message(STATUS "NEED_SUDO: ${NEED_SUDO}")
120endif()
121
122### prepare the build environment for the binary addons
123# copy the prepare-env.cmake script to the depends path so that we can include it
124file(COPY ${APP_ROOT}/project/cmake/scripts/common/prepare-env.cmake DESTINATION ${KODI_LIB_DIR})
125
126# add the location of prepare-env.cmake to CMAKE_MODULE_PATH so that it is found
127list(APPEND CMAKE_MODULE_PATH ${KODI_LIB_DIR})
128
129# include prepare-env.cmake which contains the logic to install the addon header bindings etc
130include(prepare-env)
131
132### add the depends subdirectory for any general dependencies
133add_subdirectory(depends)
134
135### get and build all the binary addons
136# look for all the addons to be built
137file(GLOB_RECURSE addons ${PROJECT_SOURCE_DIR}/addons/*.txt)
138foreach(addon ${addons})
139 if(NOT (addon MATCHES platforms.txt))
140 file(STRINGS ${addon} def)
141 separate_arguments(def)
142 list(GET def 0 id)
143
144 list(FIND ADDONS_TO_BUILD ${id} idx)
145 if(idx GREATER -1 OR ADDONS_TO_BUILD STREQUAL "all")
146 get_filename_component(dir ${addon} PATH)
147
148 # check if the addon has a platforms.txt
149 set(platform_found FALSE)
150 check_target_platform(${dir} ${CORE_SYSTEM_NAME} platform_found)
151
152 if (${platform_found})
153 # make sure the output directory is clean
154 if(EXISTS "${CMAKE_INSTALL_PREFIX}/${id}")
155 file(REMOVE_RECURSE "${CMAKE_INSTALL_PREFIX}/${id}/")
156 endif()
157
158 # get the URL and revision of the addon
159 list(LENGTH def deflength)
160 list(GET def 1 url)
161
162 set(archive_name ${id})
163
164 # if there is a 3rd parameter in the file, we consider it a git revision
165 if(deflength GREATER 2)
166 list(GET def 2 revision)
167
168 # Note: downloading specific revisions via http in the format below is probably github specific
169 # if we ever use other repositories, this might need adapting
170 set(url ${url}/archive/${revision}.tar.gz)
171 set(archive_name ${archive_name}-${revision})
172 endif()
173
174 # download and extract the addon
175 if(NOT EXISTS ${BUILD_DIR}/download/${archive_name}.tar.gz)
176 # cleanup any of the previously downloaded archives of this addon
177 file(GLOB archives "${BUILD_DIR}/download/${id}*.tar.gz")
178 if(archives)
179 message(STATUS "Removing old archives of ${id}: ${archives}")
180 file(REMOVE ${archives})
181 endif()
182
183 # download the addon
184 file(DOWNLOAD "${url}" "${BUILD_DIR}/download/${archive_name}.tar.gz" STATUS dlstatus LOG dllog SHOW_PROGRESS)
185 list(GET dlstatus 0 retcode)
186 if(NOT ${retcode} EQUAL 0)
187 message(FATAL_ERROR "ERROR downloading ${url} - status: ${dlstatus} log: ${dllog}")
188 endif()
189 endif()
190
191 # remove any previously extracted version of the addon
192 if(EXISTS "${BUILD_DIR}/${id}")
193 file(REMOVE_RECURSE "${BUILD_DIR}/${id}")
194 endif()
195
196 # extract the addon from the archive
197 execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzvf ${BUILD_DIR}/download/${archive_name}.tar.gz
198 WORKING_DIRECTORY ${BUILD_DIR})
199 file(GLOB extract_dir "${BUILD_DIR}/${archive_name}*")
200 if(extract_dir STREQUAL "")
201 message(FATAL_ERROR "Error extracting ${BUILD_DIR}/download/${archive_name}.tar.gz")
202 else()
203 file(RENAME "${extract_dir}" "${BUILD_DIR}/${id}")
204 endif()
205
206 list(APPEND downloaded_addons ${id})
207
208 endif()
209 endif()
210 endif()
211endforeach()
212
213foreach(id ${downloaded_addons})
214 externalproject_add(${id}
215 SOURCE_DIR ${BUILD_DIR}/${id}
216 INSTALL_DIR ${ADDON_INSTALL_DIR}
217 CMAKE_ARGS ${BUILD_ARGS})
218
219 # add a custom step to the external project between the configure and the build step which will always
220 # be executed and therefore forces a re-build of all changed files
221 externalproject_add_step(${id} forcebuild
222 COMMAND ${CMAKE_COMMAND} -E echo "Force build of ${id}"
223 DEPENDEES configure
224 DEPENDERS build
225 ALWAYS 1)
226
227 # add "kodi-platform" as a dependency to every addon
228 add_dependencies(${id} kodi-platform)
229
230 set(${id}_DEPENDS_DIR ${BUILD_DIR}/${id}/depends)
231
232 if(EXISTS ${${id}_DEPENDS_DIR})
233 include(${APP_ROOT}/project/cmake/scripts/common/handle-depends.cmake)
234 add_addon_depends(${id} ${${id}_DEPENDS_DIR})
235 if (${id}_DEPS AND NOT "${${id}_DEPS}" STREQUAL "")
236 message(STATUS "${id} DEPENDENCIES: ${${id}_DEPS}")
237 add_dependencies(${id} ${${id}_DEPS})
238 endif()
239 endif()
240endforeach()
241
242if(NEED_SUDO)
243 add_custom_target(install
244 COMMAND ${CMAKE_COMMAND} -E echo "\n\n"
245 COMMAND ${CMAKE_COMMAND} -E echo "WARNING: sudo rights needed to install to ${CMAKE_INSTALL_PREFIX}\n"
246 COMMAND sudo ${CMAKE_COMMAND} -E copy_directory ${ADDON_INSTALL_DIR}/ ${CMAKE_INSTALL_PREFIX}/
247 COMMAND sudo ${CMAKE_COMMAND} -E remove_directory ${ADDON_INSTALL_DIR}/
248 COMMAND sudo -k)
249endif()
diff --git a/project/cmake/addons/README b/project/cmake/addons/README
new file mode 100644
index 0000000..c66e668
--- /dev/null
+++ b/project/cmake/addons/README
@@ -0,0 +1,68 @@
1KODI ADDONS
2===========
3This directory contains the cmake-based buildsystem for addons. It looks into
4the "addons" sub-directory and parses all *.txt files recursively. Each addon
5must have its own <addon-id>.txt file in a separate sub-directory which must
6follow the defined format:
7 <addon-id> <git-url> <git-revision>
8where
9 * <addon-id> must be identical to the addon's ID as defined in the addon's
10 addon.xml
11 * <git-url> must be the URL of the git repository containing the addon.
12 * <git-revision> must be a valid git tag/branch/commit in the addon's git
13 repository which will be used for the build.
14
15Reserved filenames (for additional information on how to build an addon)
16are:
17 * platforms.txt: List of platforms to build an addon for (or "all"). It is
18 also supported to specify negated platforms with a leading exclamation mark
19 (i), e.g. "!windows".
20 Available platforms are: linux, windows, darwin, ios, android, rbpi
21
22The buildsystem uses the following variables (which can be passed into it when
23executing cmake with the -D<variable-name>=<value> option) to e.g. access
24specific paths:
25 * ADDONS_TO_BUILD is a quoted, space delimited list of <addon-id>s that
26 you want to build (default is "all").
27 * CMAKE_BUILD_TYPE specifies the type of the build. This can be either "Debug"
28 or "Release" (default is "Release").
29 * CMAKE_INSTALL_PREFIX points to the directory where the built addons and their
30 additional files (addon.xml, resources ...) will be installed to (defaults
31 to <DEPENDS_PATH>).
32 * CMAKE_TOOLCHAIN_FILE can be used to pass a toolchain file into the add-on
33 builds.
34 * DEPENDS_PATH points to the directory containing the "include" and "lib"
35 directories of the addons' dependencies.
36 * APP_ROOT points to the root directory of the project (default is the
37 absolute representation of ../../.. starting from this directory).
38 * BUILD_DIR points to the directory where the addons and their dependencies
39 will be downloaded and built.
40 * PACKAGE_ZIP=1 will mean the add-ons will be 'packaged' into a common folder,
41 rather than being placed in <CMAKE_INSTALL_PREFIX>/lib/kodi/addons and
42 <CMAKE_INSTALL_PREFIX>/share/kodi/addons.
43 * ARCH_DEFINES specifies the platform-specific C/C++ preprocessor defines
44 (defaults to empty).
45
46The buildsystem makes some assumptions about the environment which must be met
47by whoever uses it:
48 * Any dependencies of the addons must already be built and their include and
49 library files must be present in the path pointed to by <CMAKE_PREFIX_PATH> (in
50 "include" and "lib" sub-directories).
51
52To trigger the cmake-based buildsystem the following command must be executed
53with <path> being the path to this directory (absolute or relative, allowing for
54in-source and out-of-source builds).
55
56 cmake <path> -G <generator>
57
58cmake supports multiple generators, see
59http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Generators for a list.
60
61In case of additional options the call might look like this
62
63 cmake <path> [-G <generator>] \
64 -DCMAKE_BUILD_TYPE=Release \
65 -DAPP_ROOT="<path-to-app-root>" \
66 -DARCH_DEFINES="-DTARGET_LINUX" \
67 -DDEPENDS_PATH="<path-to-built-depends>" \
68 -DCMAKE_INSTALL_PREFIX="<path-to-install-directory"
diff --git a/project/cmake/addons/addons/audioencoder.flac/audioencoder.flac.txt b/project/cmake/addons/addons/audioencoder.flac/audioencoder.flac.txt
new file mode 100644
index 0000000..5886cfa
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.flac/audioencoder.flac.txt
@@ -0,0 +1 @@
audioencoder.flac https://github.com/xbmc/audioencoder.flac 84acb14
diff --git a/project/cmake/addons/addons/audioencoder.flac/platforms.txt b/project/cmake/addons/addons/audioencoder.flac/platforms.txt
new file mode 100644
index 0000000..174a52e
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.flac/platforms.txt
@@ -0,0 +1 @@
!ios \ No newline at end of file
diff --git a/project/cmake/addons/addons/audioencoder.lame/audioencoder.lame.txt b/project/cmake/addons/addons/audioencoder.lame/audioencoder.lame.txt
new file mode 100644
index 0000000..a55dc44
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.lame/audioencoder.lame.txt
@@ -0,0 +1 @@
audioencoder.lame https://github.com/xbmc/audioencoder.lame 3eb59de
diff --git a/project/cmake/addons/addons/audioencoder.lame/platforms.txt b/project/cmake/addons/addons/audioencoder.lame/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.lame/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/audioencoder.vorbis/audioencoder.vorbis.txt b/project/cmake/addons/addons/audioencoder.vorbis/audioencoder.vorbis.txt
new file mode 100644
index 0000000..8decf52
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.vorbis/audioencoder.vorbis.txt
@@ -0,0 +1 @@
audioencoder.vorbis https://github.com/xbmc/audioencoder.vorbis d556a68
diff --git a/project/cmake/addons/addons/audioencoder.vorbis/platforms.txt b/project/cmake/addons/addons/audioencoder.vorbis/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.vorbis/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/audioencoder.wav/audioencoder.wav.txt b/project/cmake/addons/addons/audioencoder.wav/audioencoder.wav.txt
new file mode 100644
index 0000000..b3209f6
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.wav/audioencoder.wav.txt
@@ -0,0 +1 @@
audioencoder.wav https://github.com/xbmc/audioencoder.wav 40aaedf
diff --git a/project/cmake/addons/addons/audioencoder.wav/platforms.txt b/project/cmake/addons/addons/audioencoder.wav/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/audioencoder.wav/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.argustv/platforms.txt b/project/cmake/addons/addons/pvr.argustv/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.argustv/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.argustv/pvr.argustv.txt b/project/cmake/addons/addons/pvr.argustv/pvr.argustv.txt
new file mode 100644
index 0000000..bb928b6
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.argustv/pvr.argustv.txt
@@ -0,0 +1 @@
pvr.argustv https://github.com/kodi-pvr/pvr.argustv b6a58d3 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.demo/platforms.txt b/project/cmake/addons/addons/pvr.demo/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.demo/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.demo/pvr.demo.txt b/project/cmake/addons/addons/pvr.demo/pvr.demo.txt
new file mode 100644
index 0000000..71e18c0
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.demo/pvr.demo.txt
@@ -0,0 +1 @@
pvr.demo https://github.com/kodi-pvr/pvr.demo e457cf4 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.dvblink/platforms.txt b/project/cmake/addons/addons/pvr.dvblink/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.dvblink/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.dvblink/pvr.dvblink.txt b/project/cmake/addons/addons/pvr.dvblink/pvr.dvblink.txt
new file mode 100644
index 0000000..58e0d5a
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.dvblink/pvr.dvblink.txt
@@ -0,0 +1 @@
pvr.dvblink https://github.com/kodi-pvr/pvr.dvblink 10b9c1d \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.dvbviewer/platforms.txt b/project/cmake/addons/addons/pvr.dvbviewer/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.dvbviewer/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.dvbviewer/pvr.dvbviewer.txt b/project/cmake/addons/addons/pvr.dvbviewer/pvr.dvbviewer.txt
new file mode 100644
index 0000000..8ebacac
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.dvbviewer/pvr.dvbviewer.txt
@@ -0,0 +1 @@
pvr.dvbviewer https://github.com/kodi-pvr/pvr.dvbviewer 3420504 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.hts/platforms.txt b/project/cmake/addons/addons/pvr.hts/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.hts/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.hts/pvr.hts.txt b/project/cmake/addons/addons/pvr.hts/pvr.hts.txt
new file mode 100644
index 0000000..4c8068d
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.hts/pvr.hts.txt
@@ -0,0 +1 @@
pvr.hts https://github.com/kodi-pvr/pvr.hts 3bc77ae \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.iptvsimple/platforms.txt b/project/cmake/addons/addons/pvr.iptvsimple/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.iptvsimple/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt b/project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt
new file mode 100644
index 0000000..73358b7
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.iptvsimple/pvr.iptvsimple.txt
@@ -0,0 +1 @@
pvr.iptvsimple https://github.com/kodi-pvr/pvr.iptvsimple f6ca894 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.mediaportal.tvserver/platforms.txt b/project/cmake/addons/addons/pvr.mediaportal.tvserver/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.mediaportal.tvserver/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.mediaportal.tvserver/pvr.mediaportal.tvserver.txt b/project/cmake/addons/addons/pvr.mediaportal.tvserver/pvr.mediaportal.tvserver.txt
new file mode 100644
index 0000000..534ede1
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.mediaportal.tvserver/pvr.mediaportal.tvserver.txt
@@ -0,0 +1 @@
pvr.mediaportal.tvserver https://github.com/kodi-pvr/pvr.mediaportal.tvserver 87422e6 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.mythtv/platforms.txt b/project/cmake/addons/addons/pvr.mythtv/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.mythtv/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.mythtv/pvr.mythtv.txt b/project/cmake/addons/addons/pvr.mythtv/pvr.mythtv.txt
new file mode 100644
index 0000000..9c77d98
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.mythtv/pvr.mythtv.txt
@@ -0,0 +1 @@
pvr.mythtv https://github.com/kodi-pvr/pvr.mythtv 6e9cf98 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.nextpvr/platforms.txt b/project/cmake/addons/addons/pvr.nextpvr/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.nextpvr/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.nextpvr/pvr.nextpvr.txt b/project/cmake/addons/addons/pvr.nextpvr/pvr.nextpvr.txt
new file mode 100644
index 0000000..0d3df74
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.nextpvr/pvr.nextpvr.txt
@@ -0,0 +1 @@
pvr.nextpvr https://github.com/kodi-pvr/pvr.nextpvr 79557b2 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.njoy/platforms.txt b/project/cmake/addons/addons/pvr.njoy/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.njoy/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.njoy/pvr.njoy.txt b/project/cmake/addons/addons/pvr.njoy/pvr.njoy.txt
new file mode 100644
index 0000000..e33573b
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.njoy/pvr.njoy.txt
@@ -0,0 +1 @@
pvr.njoy https://github.com/kodi-pvr/pvr.njoy dee3094 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.vdr.vnsi/platforms.txt b/project/cmake/addons/addons/pvr.vdr.vnsi/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.vdr.vnsi/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.vdr.vnsi/pvr.vdr.vnsi.txt b/project/cmake/addons/addons/pvr.vdr.vnsi/pvr.vdr.vnsi.txt
new file mode 100644
index 0000000..8d6f770
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.vdr.vnsi/pvr.vdr.vnsi.txt
@@ -0,0 +1 @@
pvr.vdr.vnsi https://github.com/FernetMenta/pvr.vdr.vnsi 3cc618e \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.vuplus/platforms.txt b/project/cmake/addons/addons/pvr.vuplus/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.vuplus/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.vuplus/pvr.vuplus.txt b/project/cmake/addons/addons/pvr.vuplus/pvr.vuplus.txt
new file mode 100644
index 0000000..e3983d8
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.vuplus/pvr.vuplus.txt
@@ -0,0 +1 @@
pvr.vuplus https://github.com/kodi-pvr/pvr.vuplus 6acc177 \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.wmc/platforms.txt b/project/cmake/addons/addons/pvr.wmc/platforms.txt
new file mode 100644
index 0000000..baa6044
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.wmc/platforms.txt
@@ -0,0 +1 @@
all \ No newline at end of file
diff --git a/project/cmake/addons/addons/pvr.wmc/pvr.wmc.txt b/project/cmake/addons/addons/pvr.wmc/pvr.wmc.txt
new file mode 100644
index 0000000..1be8ad5
--- /dev/null
+++ b/project/cmake/addons/addons/pvr.wmc/pvr.wmc.txt
@@ -0,0 +1 @@
pvr.wmc https://github.com/kodi-pvr/pvr.wmc e4b5285 \ No newline at end of file
diff --git a/project/cmake/addons/depends/CMakeLists.txt b/project/cmake/addons/depends/CMakeLists.txt
new file mode 100644
index 0000000..760acf4
--- /dev/null
+++ b/project/cmake/addons/depends/CMakeLists.txt
@@ -0,0 +1,42 @@
1project(kodi-addons-depends)
2
3cmake_minimum_required(VERSION 2.8)
4
5list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
6
7if(NOT CMAKE_BUILD_TYPE)
8 set(CMAKE_BUILD_TYPE Release)
9endif()
10
11if(NOT CORE_SYSTEM_NAME)
12 string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME)
13endif()
14
15include(ExternalProject)
16
17if(NOT DEPENDS_PATH)
18 set(DEPENDS_PATH ${PROJECT_SOURCE_DIR}/../build/depends)
19else()
20 file(TO_CMAKE_PATH "${DEPENDS_PATH}" DEPENDS_PATH)
21endif()
22get_filename_component(DEPENDS_PATH "${DEPENDS_PATH}" ABSOLUTE)
23list(APPEND CMAKE_PREFIX_PATH ${DEPENDS_PATH})
24
25if(NOT BUILD_DIR)
26 set(BUILD_DIR "${CMAKE_BINARY_DIR}/build")
27else()
28 file(TO_CMAKE_PATH "${BUILD_DIR}" BUILD_DIR)
29endif()
30get_filename_component(BUILD_DIR "${BUILD_DIR}" ABSOLUTE)
31
32## use add_addon_depends to handle the cmake based dependencies
33include(${APP_ROOT}/project/cmake/scripts/common/handle-depends.cmake)
34add_addon_depends(depends "${PROJECT_SOURCE_DIR}")
35
36## if there's a platform-specific sub-directory containing a CMakeLists.txt, add it to the build as well
37if(EXISTS ${PROJECT_SOURCE_DIR}/${CORE_SYSTEM_NAME}/CMakeLists.txt)
38 message(STATUS "Processing ${CORE_SYSTEM_NAME}")
39 add_subdirectory(${CORE_SYSTEM_NAME})
40else()
41 message(STATUS "No platform specific file ${PROJECT_SOURCE_DIR}/${CORE_SYSTEM_NAME}/CMakeLists.txt found")
42endif()
diff --git a/project/cmake/addons/depends/README b/project/cmake/addons/depends/README
new file mode 100644
index 0000000..66e924a
--- /dev/null
+++ b/project/cmake/addons/depends/README
@@ -0,0 +1,61 @@
1KODI ADDON DEPENDENCIES
2=======================
3This directory contains the cmake-based buildsystem for addon dependencies. It
4looks into the "common" and the "<platform>/cmake" sub-directories and parses
5all *.txt files recursively. Each dependency must have its own <dependency>.txt
6file (either in the main sub-directory or in a separate subdirectory of the main
7subdirectory) which must follow one of the defined formats:
8 * an empty file means that no extra downloads are necessary
9 * <dependency>
10 * <dependency> <url>
11 * <dependency> <git-url> <git-revision>
12where
13 * <dependency> must be identical to the filename
14 * <url> must be the URL to an archive that is downloaded and extracted.
15 * <git-url> must be the URL of the git repository containing the
16 dependency.
17 * <git-revision> must be a valid git tag/branch/commit in the dependency's git
18 repository which will be used for the build.
19
20Reserved filenames (for additional information on how to build a dependency)
21are:
22 * CMakeLists.txt: build instructions for the dependency
23 * install.txt: instructions on how to install the dependency's built files
24 * noinstall.txt: no installation step required (content is ignored)
25 * flags.txt: additional build flags
26 * deps.txt: whitespace separated list of dependencies of this dependency
27
28The buildsystem uses the following variables (which can be passed into it when
29executing cmake with the -D<variable-name>=<value> option) to e.g. access
30specific paths:
31 * CMAKE_BUILD_TYPE specifies the type of the build. This can be either "Debug"
32 or "Release" (default is "Release").
33 * CMAKE_TOOLCHAIN_FILE can be used to pass a toolchain file into the add-on
34 builds.
35 * CORE_SYSTEM_NAME is the name of the platform (e.g. "linux" or "android") in
36 lower-case (defaults to lowercase(CMAKE_SYSTEM_NAME)).
37 * APP_ROOT points to the root directory of the project (default is the
38 absolute representation of ../../.. starting from this directory).
39 * DEPENDS_PATH points to the directory where the built dependencies
40 (their include and library file) will be installed to.
41 * ARCH_DEFINES specifies the platform-specific C/C++ preprocessor defines
42 (defaults to empty).
43 * DEPENDS_TO_BUILD is a quoted, space delimited list of <dependency>s that
44 you want to build (default is "all").
45
46To trigger the cmake-based buildsystem the following command must be executed
47with <path> being the path to this directory (absolute or relative, allowing for
48in-source and out-of-source builds).
49
50 cmake <path> -G <generator>
51
52cmake supports multiple generators, see
53http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Generators for a list.
54
55In case of additional options the call might look like this
56
57 cmake <path> [-G <generator>] \
58 -DCMAKE_BUILD_TYPE=Release \
59 -DAPP_ROOT="<path-to-project-root>" \
60 -DARCH_DEFINES="-DTARGET_LINUX" \
61 -DCMAKE_INSTALL_PREFIX="<path-to-install-directory"
diff --git a/project/cmake/addons/depends/common/kodi-platform/deps.txt b/project/cmake/addons/depends/common/kodi-platform/deps.txt
new file mode 100644
index 0000000..f0e8246
--- /dev/null
+++ b/project/cmake/addons/depends/common/kodi-platform/deps.txt
@@ -0,0 +1,2 @@
1kodi
2tinyxml \ No newline at end of file
diff --git a/project/cmake/addons/depends/common/kodi-platform/kodi-platform.txt b/project/cmake/addons/depends/common/kodi-platform/kodi-platform.txt
new file mode 100644
index 0000000..fb6916a
--- /dev/null
+++ b/project/cmake/addons/depends/common/kodi-platform/kodi-platform.txt
@@ -0,0 +1 @@
kodi-platform https://github.com/xbmc/kodi-platform 68315f0
diff --git a/project/cmake/addons/depends/common/tinyxml/CMakeLists.txt b/project/cmake/addons/depends/common/tinyxml/CMakeLists.txt
new file mode 100644
index 0000000..5468bfb
--- /dev/null
+++ b/project/cmake/addons/depends/common/tinyxml/CMakeLists.txt
@@ -0,0 +1,23 @@
1project(tinyxml)
2
3cmake_minimum_required(VERSION 2.8)
4
5set(SOURCES src/tinystr.cpp
6 src/tinyxml.cpp
7 src/tinyxmlerror.cpp
8 src/tinyxmlparser.cpp)
9
10if(WIN32)
11 add_definitions(-DWIN32 -D_LIB)
12endif()
13add_definitions(-DTIXML_USE_STL)
14
15add_library(tinyxml ${SOURCES})
16
17include_directories(${PROJECT_SOURCE_DIR}/include)
18
19set(HEADERS ${PROJECT_SOURCE_DIR}/include/tinystr.h
20 ${PROJECT_SOURCE_DIR}/include/tinyxml.h)
21
22install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
23install(TARGETS tinyxml DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
diff --git a/project/cmake/addons/depends/common/tinyxml/tinyxml.txt b/project/cmake/addons/depends/common/tinyxml/tinyxml.txt
new file mode 100644
index 0000000..456b0c5
--- /dev/null
+++ b/project/cmake/addons/depends/common/tinyxml/tinyxml.txt
@@ -0,0 +1 @@
tinyxml http://mirrors.xbmc.org/build-deps/sources/tinyxml-2.6.2_2.tar.gz
diff --git a/project/cmake/addons/depends/windows/CMakeLists.txt b/project/cmake/addons/depends/windows/CMakeLists.txt
new file mode 100644
index 0000000..4480f1e
--- /dev/null
+++ b/project/cmake/addons/depends/windows/CMakeLists.txt
@@ -0,0 +1,55 @@
1project(kodi-addons-depends-windows)
2
3cmake_minimum_required(VERSION 2.8)
4
5list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
6
7if(NOT CMAKE_BUILD_TYPE)
8 set(CMAKE_BUILD_TYPE Release)
9endif()
10
11include(ExternalProject)
12
13if(NOT DEPENDS_PATH)
14 message(FATAL_ERROR "DEPENDS_PATH (${DEPENDS_PATH}) is not a valid target directory.")
15else()
16 file(TO_CMAKE_PATH "${DEPENDS_PATH}" DEPENDS_PATH)
17endif()
18get_filename_component(DEPENDS_PATH "${DEPENDS_PATH}" ABSOLUTE)
19list(APPEND CMAKE_PREFIX_PATH ${DEPENDS_PATH})
20
21if(NOT DEPENDS_TO_BUILD)
22 set(DEPENDS_TO_BUILD "all")
23endif()
24
25function(add_internal id url inputfile)
26 externalproject_add(${id}
27 URL ${url}
28 PREFIX build/${id}
29 CONFIGURE_COMMAND ""
30 BUILD_COMMAND ""
31 INSTALL_COMMAND ${CMAKE_COMMAND}
32 -DINPUTDIR=${PROJECT_BINARY_DIR}/build/${id}/src/${id}
33 -DINPUTFILE=${inputfile}
34 -DDESTDIR=${DEPENDS_PATH}
35 -P ${PROJECT_SOURCE_DIR}/install.cmake
36 )
37endfunction()
38
39#find_package(7Zip REQUIRED)
40
41file(GLOB_RECURSE download_input_files prebuilt/*.txt)
42foreach(file ${download_input_files})
43 if(NOT file MATCHES install.txt)
44 file(STRINGS ${file} def)
45 get_filename_component(dir ${file} PATH)
46 separate_arguments(def)
47 list(GET def 0 id)
48
49 list(FIND DEPENDS_TO_BUILD ${id} idx)
50 if(idx GREATER -1 OR DEPENDS_TO_BUILD STREQUAL "all")
51 list(GET def 1 url)
52 add_internal(${id} ${url} ${dir}/install.txt)
53 endif()
54 endif()
55endforeach()
diff --git a/project/cmake/addons/depends/windows/Find7Zip.cmake b/project/cmake/addons/depends/windows/Find7Zip.cmake
new file mode 100644
index 0000000..82b0902
--- /dev/null
+++ b/project/cmake/addons/depends/windows/Find7Zip.cmake
@@ -0,0 +1,7 @@
1find_program(7ZIP_EXECUTABLE NAMES 7z.exe
2 HINTS PATHS "c:/Program Files/7-Zip")
3
4include(FindPackageHandleStandardArgs)
5find_package_handle_standard_args(7Zip DEFAULT_MSG 7ZIP_EXECUTABLE)
6
7mark_as_advanced(7ZIP_EXECUTABLE)
diff --git a/project/cmake/addons/depends/windows/README b/project/cmake/addons/depends/windows/README
new file mode 100644
index 0000000..67dc594
--- /dev/null
+++ b/project/cmake/addons/depends/windows/README
@@ -0,0 +1,19 @@
1KODI WIN32 ADDON DEPENDENCIES
2=============================
3This directory contains the cmake-based buildsystem for dependencies (currently
4only prebuilt) used by one or multiple addons. The buildsystem looks into the
5"prebuilt" sub-directory, downloads all the specified dependencies, extracts
6them and places them into the "depends" sub-directory.
7
8To trigger the cmake-based buildsystem the following command must be executed
9with <path> being the path to this directory (absolute or relative, allowing for
10in-source and out-of-source builds).
11
12 cmake <path> [-G <generator>]
13
14cmake supports multiple generators, see
15http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Generators for a list.
16For win32 builds one of the "Visual Studio XX" or the "NMake Makefiles"
17generators is preferred. For the "NMake Makefiles" generator to work the above
18command must be called from an environment prepared for VC++ builds (see
19http://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx).
diff --git a/project/cmake/addons/depends/windows/extract-7z.cmake b/project/cmake/addons/depends/windows/extract-7z.cmake
new file mode 100644
index 0000000..95a2672
--- /dev/null
+++ b/project/cmake/addons/depends/windows/extract-7z.cmake
@@ -0,0 +1,10 @@
1get_filename_component(file ${URL} NAME)
2file(DOWNLOAD ${URL} ${DEST}/${file})
3execute_process(COMMAND ${7ZIP_EXECUTABLE} -y x ${DEST}/${file}
4 WORKING_DIRECTORY ${DESTDIR})
5if(${file} MATCHES .tar)
6 string(REPLACE ".7z" "" tarball ${file})
7 string(REPLACE ".lzma" "" tarball ${file})
8 execute_process(COMMAND ${7ZIP_EXECUTABLE} -y x ${DESTDIR}/${tarball}
9 WORKING_DIRECTORY ${DESTDIR})
10endif()
diff --git a/project/cmake/addons/depends/windows/extract-direct.cmake b/project/cmake/addons/depends/windows/extract-direct.cmake
new file mode 100644
index 0000000..13cb74f
--- /dev/null
+++ b/project/cmake/addons/depends/windows/extract-direct.cmake
@@ -0,0 +1,2 @@
1get_filename_component(file ${URL} NAME)
2file(DOWNLOAD ${URL} ${DEST}/${file})
diff --git a/project/cmake/addons/depends/windows/install.cmake b/project/cmake/addons/depends/windows/install.cmake
new file mode 100644
index 0000000..9a3adbb
--- /dev/null
+++ b/project/cmake/addons/depends/windows/install.cmake
@@ -0,0 +1,24 @@
1if(EXISTS "${INPUTFILE}")
2 # if there's an input file we use it to determine which files to copy where
3 file(STRINGS ${INPUTFILE} FILES)
4 string(REPLACE "\n" ";" FILES "${FILES}")
5 foreach(file ${FILES})
6 string(REPLACE " " ";" file "${file}")
7 list(GET file 0 dir)
8 list(GET file 1 dest)
9 list(LENGTH file deflength)
10 if(deflength GREATER 2)
11 list(GET file 2 copy)
12 endif()
13 file(GLOB files ${INPUTDIR}/${dir})
14 foreach(instfile ${files})
15 file(COPY ${instfile} DESTINATION ${DESTDIR}/${dest})
16 if(copy)
17 file(COPY ${instfile} DESTINATION ${DESTDIR}/${copy})
18 endif()
19 endforeach()
20 endforeach()
21else()
22 # otherwise we assume that the content of the extracted archive is already well-formed and can just be copied
23 file(COPY ${INPUTDIR}/${dir} DESTINATION ${DESTDIR})
24endif() \ No newline at end of file
diff --git a/project/cmake/addons/depends/windows/prebuilt/README b/project/cmake/addons/depends/windows/prebuilt/README
new file mode 100644
index 0000000..a0c70d6
--- /dev/null
+++ b/project/cmake/addons/depends/windows/prebuilt/README
@@ -0,0 +1,21 @@
1KODI WIN32 PREBUILT ADDON DEPENDENCIES
2======================================
3This directory contains a file or sub-directory for every prebuilt dependency
4used by one of the addons being built. There are two different modes supported.
5Both include a file named <library-id>.txt which must follow the defined format
6 <library-id> <download-url>
7
8If the archive, which the <download-url> points at, contains
9 * only the necessary files and in the proper directory structure (i.e. an
10 "include" and a "lib" directory) then the file must be put into this
11 directory and nothing else is needed.
12 * unnecessary files and/or does not follow the defined directory structure
13 (i.e. an "include" and a "lib" directory) then the file must be put into a
14 sub-directory named <library-id>. Furthermore an additional file called
15 "install.txt" must be placed in that sub-directory. install.txt contains a
16 line for every path/directory/file with a destination where it must be copied
17 to. It must follow the defined format
18 <source> <destination> [<copy-destination>]
19 where <source> must be an existing file, directory or a path containing
20 wildcards, <destination> and the optional <copy-destination> must be existing
21 directories.
diff --git a/project/cmake/kodi-config.cmake.in b/project/cmake/kodi-config.cmake.in
new file mode 100644
index 0000000..0e3b158
--- /dev/null
+++ b/project/cmake/kodi-config.cmake.in
@@ -0,0 +1,11 @@
1SET(KODI_INCLUDE_DIR @prefix@/include)
2SET(APP_NAME @APP_NAME@)
3SET(APP_VERSION_MAJOR @APP_VERSION_MAJOR@)
4SET(APP_VERSION_MINOR @APP_VERSION_MINOR@)
5IF(NOT WIN32)
6 SET(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} @CXX11_SWITCH@")
7ENDIF()
8LIST(APPEND CMAKE_MODULE_PATH @prefix@/lib/kodi)
9ADD_DEFINITIONS(@ARCH_DEFINES@)
10
11include(addon-helpers)
diff --git a/project/cmake/platform/android/defines.txt b/project/cmake/platform/android/defines.txt
new file mode 100644
index 0000000..fa103d0
--- /dev/null
+++ b/project/cmake/platform/android/defines.txt
@@ -0,0 +1 @@
-DTARGET_POSIX -DTARGET_LINUX -D_LINUX -DTARGET_ANDROID
diff --git a/project/cmake/platform/darwin/defines.txt b/project/cmake/platform/darwin/defines.txt
new file mode 100644
index 0000000..33b009e
--- /dev/null
+++ b/project/cmake/platform/darwin/defines.txt
@@ -0,0 +1 @@
-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_OSX -D_LINUX
diff --git a/project/cmake/platform/freebsd/defines.txt b/project/cmake/platform/freebsd/defines.txt
new file mode 100644
index 0000000..9483597
--- /dev/null
+++ b/project/cmake/platform/freebsd/defines.txt
@@ -0,0 +1 @@
-DTARGET_POSIX -DTARGET_FREEBSD -D_LINUX
diff --git a/project/cmake/platform/ios/defines.txt b/project/cmake/platform/ios/defines.txt
new file mode 100644
index 0000000..d0989ea
--- /dev/null
+++ b/project/cmake/platform/ios/defines.txt
@@ -0,0 +1 @@
-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_IOS -D_LINUX
diff --git a/project/cmake/platform/linux/defines.txt b/project/cmake/platform/linux/defines.txt
new file mode 100644
index 0000000..3fe9c5c
--- /dev/null
+++ b/project/cmake/platform/linux/defines.txt
@@ -0,0 +1 @@
-DTARGET_POSIX -DTARGET_LINUX -D_LINUX -fPIC
diff --git a/project/cmake/platform/rbpi/defines.txt b/project/cmake/platform/rbpi/defines.txt
new file mode 100644
index 0000000..08fe4cb
--- /dev/null
+++ b/project/cmake/platform/rbpi/defines.txt
@@ -0,0 +1 @@
-DTARGET_POSIX -DTARGET_LINUX -D_LINUX -D_ARMEL -DTARGET_RASPBERRY_PI
diff --git a/project/cmake/platform/windows/defines.txt b/project/cmake/platform/windows/defines.txt
new file mode 100644
index 0000000..5ccd98a
--- /dev/null
+++ b/project/cmake/platform/windows/defines.txt
@@ -0,0 +1 @@
-DTARGET_WINDOWS -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -D_USE_32BIT_TIME_T -D_WINSOCKAPI_ \ No newline at end of file
diff --git a/project/cmake/scripts/common/addon-helpers.cmake b/project/cmake/scripts/common/addon-helpers.cmake
new file mode 100644
index 0000000..b94df2a
--- /dev/null
+++ b/project/cmake/scripts/common/addon-helpers.cmake
@@ -0,0 +1,113 @@
1# Workaround for the fact that cpack's filenames are not customizable.
2# Each add-on is added as a separate component to facilitate zip/tgz packaging.
3# The filenames are always of the form basename-component, which is
4# incompatible with the addonid-version scheme we want. This hack renames
5# the files from the file names generated by the 'package' target.
6# Sadly we cannot extend the 'package' target, as it is a builtin target, see
7# http://public.kitware.com/Bug/view.php?id=8438
8# Thus, we have to add an 'addon-package' target.
9add_custom_target(addon-package
10 COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target package)
11
12macro(add_cpack_workaround target version ext)
13 add_custom_command(TARGET addon-package PRE_BUILD
14 COMMAND ${CMAKE_COMMAND} -E rename addon-${target}-${version}.${ext} ${target}-${version}.${ext})
15endmacro()
16
17# Grab the version from a given add-on's addon.xml
18macro (addon_version dir prefix)
19 FILE(READ ${dir}/addon.xml ADDONXML)
20 STRING(REGEX MATCH "<addon[^>]*version.?=.?.[0-9\\.]+" VERSION_STRING ${ADDONXML})
21 STRING(REGEX REPLACE ".*version=.([0-9\\.]+).*" "\\1" ${prefix}_VERSION ${VERSION_STRING})
22 message(STATUS ${prefix}_VERSION=${${prefix}_VERSION})
23endmacro()
24
25# Build, link and optionally package an add-on
26macro (build_addon target prefix libs)
27 ADD_LIBRARY(${target} ${${prefix}_SOURCES})
28 TARGET_LINK_LIBRARIES(${target} ${${libs}})
29 addon_version(${target} ${prefix})
30 SET_TARGET_PROPERTIES(${target} PROPERTIES VERSION ${${prefix}_VERSION}
31 SOVERSION ${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}
32 PREFIX "")
33 IF(OS STREQUAL "android")
34 SET_TARGET_PROPERTIES(${target} PROPERTIES PREFIX "lib")
35 ENDIF(OS STREQUAL "android")
36
37 # set zip as default if addon-package is called without PACKAGE_XXX
38 SET(CPACK_GENERATOR "ZIP")
39 SET(ext "zip")
40 IF(PACKAGE_ZIP OR PACKAGE_TGZ)
41 IF(PACKAGE_TGZ)
42 SET(CPACK_GENERATOR "TGZ")
43 SET(ext "tar.gz")
44 ENDIF(PACKAGE_TGZ)
45 SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
46 set(CPACK_PACKAGE_FILE_NAME addon)
47 IF(CMAKE_BUILD_TYPE STREQUAL "Release")
48 SET(CPACK_STRIP_FILES TRUE)
49 ENDIF(CMAKE_BUILD_TYPE STREQUAL "Release")
50 set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
51 set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
52 list(APPEND CPACK_COMPONENTS_ALL ${target}-${${prefix}_VERSION})
53 # Pack files together to create an archive
54 INSTALL(DIRECTORY ${target} DESTINATION ./ COMPONENT ${target}-${${prefix}_VERSION})
55 IF(WIN32)
56 # get the installation location for the addon's target
57 get_property(dll_location TARGET ${target} PROPERTY LOCATION)
58 # in case of a VC++ project the installation location contains a $(Configuration) VS variable
59 # we replace it with ${CMAKE_BUILD_TYPE} (which doesn't cover the case when the build configuration
60 # is changed within Visual Studio)
61 string(REPLACE "$(Configuration)" "${CMAKE_BUILD_TYPE}" dll_location "${dll_location}")
62
63 # install the generated DLL file
64 INSTALL(PROGRAMS ${dll_location} DESTINATION ${target}
65 COMPONENT ${target}-${${prefix}_VERSION})
66
67 IF(CMAKE_BUILD_TYPE MATCHES Debug)
68 # for debug builds also install the PDB file
69 get_filename_component(dll_directory ${dll_location} DIRECTORY)
70 INSTALL(FILES ${dll_directory}/${target}.pdb DESTINATION ${target}
71 COMPONENT ${target}-${${prefix}_VERSION})
72 ENDIF()
73 ELSE(WIN32)
74 INSTALL(TARGETS ${target} DESTINATION ${target}
75 COMPONENT ${target}-${${prefix}_VERSION})
76 ENDIF(WIN32)
77 add_cpack_workaround(${target} ${${prefix}_VERSION} ${ext})
78 ELSE(PACKAGE_ZIP OR PACKAGE_TGZ)
79 INSTALL(TARGETS ${target} DESTINATION lib/kodi/addons/${target})
80 INSTALL(DIRECTORY ${target} DESTINATION share/kodi/addons)
81 ENDIF(PACKAGE_ZIP OR PACKAGE_TGZ)
82endmacro()
83
84# finds a path to a given file (recursive)
85function (kodi_find_path var_name filename search_path strip_file)
86 file(GLOB_RECURSE PATH_TO_FILE ${search_path} ${filename})
87 if(strip_file)
88 string(REPLACE ${filename} "" PATH_TO_FILE ${PATH_TO_FILE})
89 endif(strip_file)
90 set (${var_name} ${PATH_TO_FILE} PARENT_SCOPE)
91endfunction()
92
93# Cmake build options
94include(addoptions)
95include(TestCXXAcceptsFlag)
96OPTION(PACKAGE_ZIP "Package Zip file?" OFF)
97OPTION(PACKAGE_TGZ "Package TGZ file?" OFF)
98OPTION(BUILD_SHARED_LIBS "Build shared libs?" ON)
99
100# LTO support?
101CHECK_CXX_ACCEPTS_FLAG("-flto" HAVE_LTO)
102IF(HAVE_LTO)
103 OPTION(USE_LTO "use link time optimization" OFF)
104 IF(USE_LTO)
105 add_options(ALL_LANGUAGES ALL_BUILDS "-flto")
106 ENDIF(USE_LTO)
107ENDIF(HAVE_LTO)
108
109# set this to try linking dependencies as static as possible
110IF(ADDONS_PREFER_STATIC_LIBS)
111 SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
112ENDIF(ADDONS_PREFER_STATIC_LIBS)
113
diff --git a/project/cmake/scripts/common/addoptions.cmake b/project/cmake/scripts/common/addoptions.cmake
new file mode 100644
index 0000000..0ebb823
--- /dev/null
+++ b/project/cmake/scripts/common/addoptions.cmake
@@ -0,0 +1,82 @@
1# - Add options without repeating them on the command line
2#
3# Synopsis:
4#
5# add_options (lang build opts)
6#
7# where:
8#
9# lang Name of the language whose compiler should receive the
10# options, e.g. CXX. If a comma-separated list is received
11# then the option is added for all those languages. Use the
12# special value ALL_LANGUAGES for these languages: CXX, C
13# and Fortran
14#
15# build Kind of build to which this options should apply,
16# such as DEBUG and RELEASE. This can also be a comma-
17# separated list. Use the special value ALL_BUILDS to apply
18# to all builds.
19#
20# opts List of options to add. Each should be quoted.
21#
22# Example:
23#
24# add_options (CXX RELEASE "-O3" "-DNDEBUG" "-Wall")
25
26function (add_options langs builds)
27 # special handling of empty language specification
28 if ("${langs}" STREQUAL "ALL_LANGUAGES")
29 set (langs CXX C Fortran)
30 endif ("${langs}" STREQUAL "ALL_LANGUAGES")
31 foreach (lang IN LISTS langs)
32 # prepend underscore if necessary
33 foreach (build IN LISTS builds)
34 if (NOT ("${build}" STREQUAL "ALL_BUILDS"))
35 set (_bld "_${build}")
36 string (TOUPPER "${_bld}" _bld)
37 else (NOT ("${build}" STREQUAL "ALL_BUILDS"))
38 set (_bld "")
39 endif (NOT ("${build}" STREQUAL "ALL_BUILDS"))
40 foreach (_opt IN LISTS ARGN)
41 set (_var "CMAKE_${lang}_FLAGS${_bld}")
42 #message (STATUS "Adding \"${_opt}\" to \${${_var}}")
43 # remove it first
44 string (REPLACE "${_opt}" "" _without "${${_var}}")
45 string (STRIP "${_without}" _without)
46 # we need to strip this one as well, so they are comparable
47 string (STRIP "${${_var}}" _stripped)
48 # if it wasn't there, then add it at the end
49 if ("${_without}" STREQUAL "${_stripped}")
50 # don't add any extra spaces if no options yet are set
51 if (NOT ${_stripped} STREQUAL "")
52 set (${_var} "${_stripped} ${_opt}")
53 else (NOT ${_stripped} STREQUAL "")
54 set (${_var} "${_opt}")
55 endif (NOT ${_stripped} STREQUAL "")
56 set (${_var} "${${_var}}" PARENT_SCOPE)
57 endif ("${_without}" STREQUAL "${_stripped}")
58 endforeach (_opt)
59 endforeach (build)
60 endforeach (lang)
61endfunction (add_options lang build)
62
63# set varname to flag unless user has specified something that matches regex
64function (set_default_option varname flag regex)
65 if (NOT "$ENV{CXXFLAGS}" MATCHES "${regex}"
66 AND NOT "${CMAKE_CXX_FLAGS}" MATCHES "${regex}"
67 AND NOT "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}" MATCHES "${regex}")
68 set (${varname} ${flag} PARENT_SCOPE)
69 else (NOT "$ENV{CXXFLAGS}" MATCHES "${regex}"
70 AND NOT "${CMAKE_CXX_FLAGS}" MATCHES "${regex}"
71 AND NOT "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}" MATCHES "${regex}")
72 set (${varname} PARENT_SCOPE)
73 endif (NOT "$ENV{CXXFLAGS}" MATCHES "${regex}"
74 AND NOT "${CMAKE_CXX_FLAGS}" MATCHES "${regex}"
75 AND NOT "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}" MATCHES "${regex}")
76endfunction (set_default_option)
77
78# note: this must be called before project()
79macro (no_default_options)
80 # prevent the platform probe to set options
81 set (CMAKE_NOT_USING_CONFIG_FLAGS TRUE)
82endmacro (no_default_options)
diff --git a/project/cmake/scripts/common/check_target_platform.cmake b/project/cmake/scripts/common/check_target_platform.cmake
new file mode 100644
index 0000000..fc8b403
--- /dev/null
+++ b/project/cmake/scripts/common/check_target_platform.cmake
@@ -0,0 +1,61 @@
1# handle target platforms
2function(check_target_platform dir target_platform build)
3 # param[in] dir path/directory of the addon/dependency
4 # param[in] target_platform target platform of the build
5 # param[out] build Result whether the addon/dependency should be built for the specified target platform
6
7 set(${build} FALSE)
8 # check if the given directory exists and contains a platforms.txt
9 if(EXISTS ${dir} AND EXISTS ${dir}/platforms.txt)
10 # get all the specified platforms
11 file(STRINGS ${dir}/platforms.txt platforms)
12 separate_arguments(platforms)
13
14 # check if the addon/dependency should be built for the current platform
15 foreach(platform ${platforms})
16 if(${platform} STREQUAL "all" OR ${platform} STREQUAL ${target_platform})
17 set(${build} TRUE)
18 else()
19 # check if the platform is defined as "!<platform>"
20 string(SUBSTRING ${platform} 0 1 platform_first)
21 if(${platform_first} STREQUAL "!")
22 # extract the platform
23 string(LENGTH ${platform} platform_length)
24 MATH(EXPR platform_length "${platform_length} - 1")
25 string(SUBSTRING ${platform} 1 ${platform_length} platform)
26
27 # check if the current platform does not match the extracted platform
28 if (NOT ${platform} STREQUAL ${target_platform})
29 set(${build} TRUE)
30 endif()
31 endif()
32 endif()
33 endforeach()
34 else()
35 set(${build} TRUE)
36 endif()
37
38 # make the ${build} variable available to the calling script
39 set(${build} "${${build}}" PARENT_SCOPE)
40endfunction()
41
42function(check_install_permissions install_dir have_perms)
43 # param[in] install_dir directory to check for write permissions
44 # param[out] have_perms wether we have permissions to install to install_dir
45
46 set(${have_perms} TRUE)
47 execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}/lib/kodi
48 COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}/share/kodi
49 COMMAND ${CMAKE_COMMAND} -E touch ${install_dir}/lib/kodi/.cmake-inst-test ${install_dir}/share/kodi/.cmake-inst-test
50 RESULT_VARIABLE permtest)
51
52 if(${permtest} GREATER 0)
53 message(STATUS "check_install_permissions: ${permtest}")
54 set(${have_perms} FALSE)
55 endif()
56 set(${have_perms} "${${have_perms}}" PARENT_SCOPE)
57
58 if(EXISTS ${install_dir}/lib/kodi/.cmake-inst-test OR EXISTS ${install_dir}/share/kodi/.cmake-inst-test)
59 file(REMOVE ${install_dir}/lib/kodi/.cmake-inst-test ${install_dir}/share/kodi/.cmake-inst-test)
60 endif()
61endfunction()
diff --git a/project/cmake/scripts/common/handle-depends.cmake b/project/cmake/scripts/common/handle-depends.cmake
new file mode 100644
index 0000000..b3bf3cd
--- /dev/null
+++ b/project/cmake/scripts/common/handle-depends.cmake
@@ -0,0 +1,191 @@
1include(${APP_ROOT}/project/cmake/scripts/common/check_target_platform.cmake)
2
3# handle addon depends
4function(add_addon_depends addon searchpath)
5 # input: string addon string searchpath
6
7 set(OUTPUT_DIR ${DEPENDS_PATH})
8 file(GLOB_RECURSE cmake_input_files ${searchpath}/${CORE_SYSTEM_NAME}/*.txt)
9 file(GLOB_RECURSE cmake_input_files2 ${searchpath}/common/*.txt)
10 list(APPEND cmake_input_files ${cmake_input_files2})
11
12 foreach(file ${cmake_input_files})
13 if(NOT (file MATCHES CMakeLists.txt OR
14 file MATCHES install.txt OR
15 file MATCHES noinstall.txt OR
16 file MATCHES flags.txt OR
17 file MATCHES deps.txt OR
18 file MATCHES platforms.txt))
19 message(STATUS "Processing ${file}")
20 file(STRINGS ${file} def)
21 separate_arguments(def)
22 list(LENGTH def deflength)
23 get_filename_component(dir ${file} PATH)
24
25 # get the id of the dependency
26 if(NOT "${def}" STREQUAL "")
27 # read the id from the file
28 list(GET def 0 id)
29 else()
30 # read the id from the filename
31 get_filename_component(id ${file} NAME_WE)
32 endif()
33
34 # check if the dependency has a platforms.txt
35 set(platform_found FALSE)
36 check_target_platform(${dir} ${CORE_SYSTEM_NAME} platform_found)
37
38 if(${platform_found} AND NOT TARGET ${id})
39 # determine the download URL of the dependency
40 set(url "")
41 if(deflength GREATER 1)
42 list(GET def 1 url)
43 message(STATUS "${id} url: ${url}")
44 endif()
45
46 # check if there are any library specific flags that need to be passed on
47 if(EXISTS ${dir}/flags.txt)
48 file(STRINGS ${dir}/flags.txt extraflags)
49 separate_arguments(extraflags)
50 message(STATUS "${id} extraflags: ${extraflags}")
51 endif()
52
53 set(BUILD_ARGS -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
54 -DOUTPUT_DIR=${OUTPUT_DIR}
55 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
56 -DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}
57 -DCMAKE_USER_MAKE_RULES_OVERRIDE_CXX=${CMAKE_USER_MAKE_RULES_OVERRIDE_CXX}
58 -DCMAKE_INSTALL_PREFIX=${OUTPUT_DIR}
59 -DCORE_SYSTEM_NAME=${CORE_SYSTEM_NAME}
60 -DENABLE_STATIC=1
61 -DBUILD_SHARED_LIBS=0)
62 # if there are no make rules override files available take care of manually passing on ARCH_DEFINES
63 if(NOT CMAKE_USER_MAKE_RULES_OVERRIDE AND NOT CMAKE_USER_MAKE_RULES_OVERRIDE_CXX)
64 # make sure we create strings, not lists
65 set(TMP_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH_DEFINES}")
66 set(TMP_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_DEFINES}")
67 list(APPEND BUILD_ARGS -DCMAKE_C_FLAGS=${TMP_C_FLAGS}
68 -DCMAKE_CXX_FLAGS=${TMP_CXX_FLAGS})
69 endif()
70
71 if(CMAKE_TOOLCHAIN_FILE)
72 list(APPEND BUILD_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
73 MESSAGE("toolchain specified")
74 MESSAGE(${BUILD_ARGS})
75 endif()
76
77 # if there's a CMakeLists.txt use it to prepare the build
78 set(PATCH_FILE ${BUILD_DIR}/${id}/tmp/patch.cmake)
79 if(EXISTS ${dir}/CMakeLists.txt)
80 file(APPEND ${PATCH_FILE}
81 "file(COPY ${dir}/CMakeLists.txt
82 DESTINATION ${BUILD_DIR}/${id}/src/${id})\n")
83 endif()
84
85 # check if we have patches to apply
86 file(GLOB patches ${dir}/*.patch)
87 list(SORT patches)
88 foreach(patch ${patches})
89 file(APPEND ${PATCH_FILE}
90 "execute_process(COMMAND patch -p1 -i ${patch})\n")
91 endforeach()
92
93
94 # if there's an install.txt use it to properly install the built files
95 set(INSTALL_COMMAND "")
96 if(EXISTS ${dir}/install.txt)
97 set(INSTALL_COMMAND INSTALL_COMMAND ${CMAKE_COMMAND}
98 -DINPUTDIR=${BUILD_DIR}/${id}/src/${id}-build/
99 -DINPUTFILE=${dir}/install.txt
100 -DDESTDIR=${OUTPUT_DIR}
101 -DENABLE_STATIC=1
102 "${extraflags}"
103 -P ${PROJECT_SOURCE_DIR}/install.cmake)
104 elseif(EXISTS ${dir}/noinstall.txt)
105 set(INSTALL_COMMAND INSTALL_COMMAND "")
106 endif()
107
108 # check if there's a deps.txt containing dependencies on other libraries
109 if(EXISTS ${dir}/deps.txt)
110 file(STRINGS ${dir}/deps.txt deps)
111 message(STATUS "${id} depends: ${deps}")
112 else()
113 set(deps)
114 endif()
115
116 if(CROSS_AUTOCONF AND AUTOCONF_FILES)
117 foreach(afile ${AUTOCONF_FILES})
118 file(APPEND ${PATCH_FILE}
119 "message(STATUS \"AUTOCONF: copying ${afile} to ${BUILD_DIR}/${id}/src/${id}\")\n
120 file(COPY ${afile} DESTINATION ${BUILD_DIR}/${id}/src/${id})\n")
121 endforeach()
122 endif()
123
124 # if the patch file exists we need to set the PATCH_COMMAND
125 set(PATCH_COMMAND "")
126 if (EXISTS ${PATCH_FILE})
127 set(PATCH_COMMAND ${CMAKE_COMMAND} -P ${PATCH_FILE})
128 endif()
129
130 # prepare the setup of the call to externalproject_add()
131 set(EXTERNALPROJECT_SETUP PREFIX ${BUILD_DIR}/${id}
132 CMAKE_ARGS ${extraflags} ${BUILD_ARGS}
133 PATCH_COMMAND ${PATCH_COMMAND}
134 "${INSTALL_COMMAND}")
135
136 # if there's an url defined we need to pass that to externalproject_add()
137 if(DEFINED url AND NOT "${url}" STREQUAL "")
138 # check if there's a third parameter in the file
139 if(deflength GREATER 2)
140 # the third parameter is considered as a revision of a git repository
141 list(GET def 2 revision)
142
143 externalproject_add(${id}
144 GIT_REPOSITORY ${url}
145 GIT_TAG ${revision}
146 "${EXTERNALPROJECT_SETUP}")
147 else()
148 set(CONFIGURE_COMMAND "")
149 if(NOT WIN32)
150 # manually specify the configure command to be able to pass in the custom PKG_CONFIG_PATH
151 set(CONFIGURE_COMMAND PKG_CONFIG_PATH=${OUTPUT_DIR}/lib/pkgconfig
152 ${CMAKE_COMMAND} -DCMAKE_LIBRARY_PATH=${OUTPUT_DIR}/lib ${extraflags} ${BUILD_ARGS}
153 ${BUILD_DIR}/${id}/src/${id}
154 -DPACKAGE_CONFIG_PATH=${OUTPUT_DIR}/lib/pkgconfig
155 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
156 -DOUTPUT_DIR=${OUTPUT_DIR}
157 -DCMAKE_PREFIX_PATH=${OUTPUT_DIR}
158 -DCMAKE_INSTALL_PREFIX=${OUTPUT_DIR}
159 -DCMAKE_EXE_LINKER_FLAGS=-L${OUTPUT_DIR}/lib
160 -DCMAKE_INCLUDE_PATH=${OUTPUT_DIR}/include)
161 endif()
162
163 externalproject_add(${id}
164 URL ${url}
165 DOWNLOAD_DIR ${BUILD_DIR}/download
166 CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
167 "${EXTERNALPROJECT_SETUP}")
168 endif()
169 else()
170 externalproject_add(${id}
171 SOURCE_DIR ${dir}
172 "${EXTERNALPROJECT_SETUP}")
173 endif()
174
175 if(deps)
176 add_dependencies(${id} ${deps})
177 endif()
178 endif()
179
180 # if the dependency is available for the target platform add it to the list of the addon's dependencies
181 # (even if the target already exists as it still has to be built before the addon)
182 if(${platform_found})
183 list(APPEND ${addon}_DEPS ${id})
184 endif()
185 endif()
186 endforeach()
187
188 # make the ${addon}_DEPS variable available to the calling script
189 set(${addon}_DEPS "${${addon}_DEPS}" PARENT_SCOPE)
190endfunction()
191
diff --git a/project/cmake/scripts/common/prepare-env.cmake b/project/cmake/scripts/common/prepare-env.cmake
new file mode 100644
index 0000000..7df421c
--- /dev/null
+++ b/project/cmake/scripts/common/prepare-env.cmake
@@ -0,0 +1,88 @@
1# parse version.txt to get the version info
2if(EXISTS "${APP_ROOT}/version.txt")
3 file(STRINGS "${APP_ROOT}/version.txt" versions)
4 foreach (version ${versions})
5 if(version MATCHES "^VERSION_.*")
6 string(REGEX MATCH "^[^ ]+" version_name ${version})
7 string(REPLACE "${version_name} " "" version_value ${version})
8 set(APP_${version_name} "${version_value}")
9 else()
10 string(REGEX MATCH "^[^ ]+" name ${version})
11 string(REPLACE "${name} " "" value ${version})
12 set(${name} "${value}")
13 endif()
14 endforeach()
15endif()
16
17# bail if we can't parse versions
18if(NOT DEFINED APP_VERSION_MAJOR OR NOT DEFINED APP_VERSION_MINOR)
19 message(FATAL_ERROR "Could not determine app version! make sure that ${APP_ROOT}/version.txt exists")
20endif()
21
22### copy all the addon binding header files to include/kodi
23# make sure include/kodi exists and is empty
24set(KODI_LIB_DIR ${DEPENDS_PATH}/lib/kodi)
25if(NOT EXISTS "${KODI_LIB_DIR}/")
26 file(MAKE_DIRECTORY ${KODI_LIB_DIR})
27endif()
28
29set(KODI_INCLUDE_DIR ${DEPENDS_PATH}/include/kodi)
30if(NOT EXISTS "${KODI_INCLUDE_DIR}/")
31 file(MAKE_DIRECTORY ${KODI_INCLUDE_DIR})
32endif()
33
34# we still need XBMC_INCLUDE_DIR and XBMC_LIB_DIR for backwards compatibility to xbmc
35set(XBMC_LIB_DIR ${DEPENDS_PATH}/lib/xbmc)
36if(NOT EXISTS "${XBMC_LIB_DIR}/")
37 file(MAKE_DIRECTORY ${XBMC_LIB_DIR})
38endif()
39set(XBMC_INCLUDE_DIR ${DEPENDS_PATH}/include/xbmc)
40if(NOT EXISTS "${XBMC_INCLUDE_DIR}/")
41 file(MAKE_DIRECTORY ${XBMC_INCLUDE_DIR})
42endif()
43
44# make sure C++11 is always set
45if(NOT WIN32)
46 string(REGEX MATCH "-std=(gnu|c)\\+\\+11" cxx11flag "${CMAKE_CXX_FLAGS}")
47 if(NOT cxx11flag)
48 set(CXX11_SWITCH "-std=c++11")
49 endif()
50endif()
51
52# kodi-config.cmake.in (further down) expects a "prefix" variable
53get_filename_component(prefix "${DEPENDS_PATH}" ABSOLUTE)
54
55# generate the proper kodi-config.cmake file
56configure_file(${APP_ROOT}/project/cmake/kodi-config.cmake.in ${KODI_LIB_DIR}/kodi-config.cmake @ONLY)
57# copy cmake helpers to lib/kodi
58file(COPY ${APP_ROOT}/project/cmake/scripts/common/addon-helpers.cmake ${APP_ROOT}/project/cmake/scripts/common/addoptions.cmake DESTINATION ${KODI_LIB_DIR})
59
60# generate xbmc-config.cmake for backwards compatibility to xbmc
61configure_file(${APP_ROOT}/project/cmake/xbmc-config.cmake.in ${XBMC_LIB_DIR}/xbmc-config.cmake @ONLY)
62
63### copy all the addon binding header files to include/kodi
64# parse addon-bindings.mk to get the list of header files to copy
65file(STRINGS ${APP_ROOT}/xbmc/addons/addon-bindings.mk bindings)
66string(REPLACE "\n" ";" bindings "${bindings}")
67foreach(binding ${bindings})
68 string(REPLACE " =" ";" binding "${binding}")
69 string(REPLACE "+=" ";" binding "${binding}")
70 list(GET binding 1 header)
71 # copy the header file to include/kodi
72 file(COPY ${APP_ROOT}/${header} DESTINATION ${KODI_INCLUDE_DIR})
73
74 # auto-generate header files for backwards compatibility to xbmc with deprecation warning
75 # but only do it if the file doesn't already exist
76 get_filename_component(headerfile ${header} NAME)
77 if (NOT EXISTS "${XBMC_INCLUDE_DIR}/${headerfile}")
78 file(WRITE ${XBMC_INCLUDE_DIR}/${headerfile}
79"#pragma once
80#define DEPRECATION_WARNING \"Including xbmc/${headerfile} has been deprecated, please use kodi/${headerfile}\"
81#ifdef _MSC_VER
82 #pragma message(\"WARNING: \" DEPRECATION_WARNING)
83#else
84 #warning DEPRECATION_WARNING
85#endif
86#include \"kodi/${headerfile}\"")
87 endif()
88endforeach()
diff --git a/project/cmake/scripts/windows/c-flag-overrides.cmake b/project/cmake/scripts/windows/c-flag-overrides.cmake
new file mode 100644
index 0000000..ab19701
--- /dev/null
+++ b/project/cmake/scripts/windows/c-flag-overrides.cmake
@@ -0,0 +1,5 @@
1if(MSVC)
2 set(CMAKE_C_FLAGS "/MP /DWIN32 /D_WINDOWS /W3 /Zi /arch:SSE2")
3 set(CMAKE_C_FLAGS_DEBUG "/D_DEBUG /MDd /Ob0 /Od /RTC1 /D_HAS_ITERATOR_DEBUGGING=0 /D_SECURE_SCL=0")
4 set(CMAKE_C_FLAGS_RELEASE "/MD /Ox /Ob2 /Oi /Ot /Oy /GL /DNDEBUG")
5endif(MSVC) \ No newline at end of file
diff --git a/project/cmake/scripts/windows/cxx-flag-overrides.cmake b/project/cmake/scripts/windows/cxx-flag-overrides.cmake
new file mode 100644
index 0000000..ad3a090
--- /dev/null
+++ b/project/cmake/scripts/windows/cxx-flag-overrides.cmake
@@ -0,0 +1,5 @@
1if(MSVC)
2 set(CMAKE_CXX_FLAGS "/MP /DWIN32 /D_WINDOWS /W3 /GR /Zi /EHsc /arch:SSE2")
3 set(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob0 /Od /RTC1 /D_HAS_ITERATOR_DEBUGGING=0 /D_SECURE_SCL=0")
4 set(CMAKE_CXX_FLAGS_RELEASE "/MD /Ox /Ob2 /Oi /Ot /Oy /GL /DNDEBUG")
5endif(MSVC) \ No newline at end of file
diff --git a/project/cmake/xbmc-config.cmake.in b/project/cmake/xbmc-config.cmake.in
new file mode 100644
index 0000000..73d1c9c
--- /dev/null
+++ b/project/cmake/xbmc-config.cmake.in
@@ -0,0 +1,4 @@
1message(WARNING "find_package(xbmc) has been deprecated, please use find_package(kodi)")
2
3find_package(kodi REQUIRED)
4set(XBMC_INCLUDE_DIR ${KODI_INCLUDE_DIR}) \ No newline at end of file
diff --git a/scripts/sync_buildenv.sh b/scripts/sync_buildenv.sh
new file mode 100755
index 0000000..24c8176
--- /dev/null
+++ b/scripts/sync_buildenv.sh
@@ -0,0 +1,17 @@
1#!/bin/sh
2
3rbase="/root/kodi/xbmc.git"
4
5for p in \
6 addons/library.xbmc.* \
7 "project/cmake" \
8 "version.txt" \
9 "xbmc/addons" \
10 "xbmc/cores/dvdplayer/DVDDemuxers"
11do
12 d="$p"
13 [ -d "$p" ] && d=$(dirname "$p")/
14
15 #scp -r xbmc:$rbase/$p $d
16 rsync --inplace -avz --delete -e ssh xbmc:$rbase/$p $d
17done
diff --git a/scripts/toolchain/android-arm.cmake b/scripts/toolchain/android-arm.cmake
new file mode 100644
index 0000000..21315b3
--- /dev/null
+++ b/scripts/toolchain/android-arm.cmake
@@ -0,0 +1,58 @@
1set(CMAKE_SYSTEM_VERSION 1)
2set(OS "android")
3set(CPU "armeabi-v7a")
4set(PLATFORM "")
5if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
6 set(CMAKE_SYSTEM_NAME Linux)
7endif()
8
9# set special CORE_SYSTEM_NAME
10if("${OS}" STREQUAL "android")
11 set(CORE_SYSTEM_NAME android)
12elseif("${OS}" STREQUAL "ios")
13 set(CORE_SYSTEM_NAME ios)
14elseif("${PLATFORM}" STREQUAL "raspberry-pi")
15 set(CORE_SYSTEM_NAME rbpi)
16elseif("${PLATFORM}" STREQUAL "darwin")
17 set(CORE_SYSTEM_NAME darwin)
18endif()
19
20#set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
21
22if("${OS}" STREQUAL "ios" OR "${OS}" STREQUAL "osx")
23 set(CMAKE_SYSTEM_NAME Darwin)
24 #set(CMAKE_OSX_SYSROOT @use_sdk_path@)
25 #list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_OSX_SYSROOT}/usr)
26 #set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_sdk_path@/lib)
27 #set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_sdk_path@/include)
28endif()
29
30#if("${CORE_SYSTEM_NAME}" STREQUAL "rbpi")
31# list(APPEND CMAKE_FIND_ROOT_PATH @use_firmware@/opt/vc)
32# set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_firmware@/opt/vc/lib)
33# set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_firmware@/opt/vc/include)
34#endif()
35
36# specify the cross compiler
37set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/android-14/bin/arm-linux-androideabi)
38set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
39set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
40set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver")
41set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker")
42set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
43set(CMAKE_C_FLAGS "-march=armv7-a -mtune=cortex-a9 -mfloat-abi=softfp -mfpu=neon")
44set(CMAKE_CXX_FLAGS "-march=armv7-a -mtune=cortex-a9 -mfloat-abi=softfp -mfpu=neon -frtti")
45set(CMAKE_CPP_FLAGS "")
46set(ENV{CFLAGS} ${CMAKE_C_FLAGS})
47set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS})
48set(ENV{CPPFLAGS} ${CMAKE_CPP_FLAGS})
49
50# search for programs in the build host directories
51#set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
52# for libraries and headers in the target directories
53#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
54#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
55
56if(NOT OS STREQUAL "linux")
57 set(ADDONS_PREFER_STATIC_LIBS ON)
58endif()
diff --git a/scripts/toolchain/ios-arm.cmake b/scripts/toolchain/ios-arm.cmake
new file mode 100644
index 0000000..9bb8b0e
--- /dev/null
+++ b/scripts/toolchain/ios-arm.cmake
@@ -0,0 +1,58 @@
1set(CMAKE_SYSTEM_VERSION 1)
2set(OS "ios")
3set(CPU "armv7")
4set(PLATFORM "darwin")
5if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
6 set(CMAKE_SYSTEM_NAME Linux)
7endif()
8
9# set special CORE_SYSTEM_NAME
10if("${OS}" STREQUAL "android")
11 set(CORE_SYSTEM_NAME android)
12elseif("${OS}" STREQUAL "ios")
13 set(CORE_SYSTEM_NAME ios)
14elseif("${PLATFORM}" STREQUAL "raspberry-pi")
15 set(CORE_SYSTEM_NAME rbpi)
16elseif("${PLATFORM}" STREQUAL "darwin")
17 set(CORE_SYSTEM_NAME darwin)
18endif()
19
20#set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
21
22if("${OS}" STREQUAL "ios" OR "${OS}" STREQUAL "osx")
23 set(CMAKE_SYSTEM_NAME Darwin)
24 #set(CMAKE_OSX_SYSROOT @use_sdk_path@)
25 #list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_OSX_SYSROOT}/usr)
26 #set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_sdk_path@/lib)
27 #set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_sdk_path@/include)
28endif()
29
30#if("${CORE_SYSTEM_NAME}" STREQUAL "rbpi")
31# list(APPEND CMAKE_FIND_ROOT_PATH @use_firmware@/opt/vc)
32# set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_firmware@/opt/vc/lib)
33# set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_firmware@/opt/vc/include)
34#endif()
35
36# specify the cross compiler
37set(COMPILER_PREFIX /var/www/ud_3/xbmc/osx/osxcross/target/bin/arm-apple-darwin14)
38set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-clang)
39set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-clang++)
40set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver")
41set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker")
42set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
43set(CMAKE_C_FLAGS "-mcpu=cortex-a8 -mfpu=neon -ftree-vectorize -mfloat-abi=softfp -pipe -Wno-trigraphs -fpascal-strings -O3 -Wreturn-type -Wunused-variable -fmessage-length=0 -gdwarf-2")
44set(CMAKE_CXX_FLAGS "-mcpu=cortex-a8 -mfpu=neon -ftree-vectorize -mfloat-abi=softfp -pipe -Wno-trigraphs -fpascal-strings -O3 -Wreturn-type -Wunused-variable -fmessage-length=0 -gdwarf-2 -stdlib=libc++")
45set(CMAKE_CPP_FLAGS "")
46set(ENV{CFLAGS} ${CMAKE_C_FLAGS})
47set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS})
48set(ENV{CPPFLAGS} ${CMAKE_CPP_FLAGS})
49
50# search for programs in the build host directories
51#set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
52# for libraries and headers in the target directories
53#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
54#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
55
56if(NOT OS STREQUAL "linux")
57 set(ADDONS_PREFER_STATIC_LIBS ON)
58endif()
diff --git a/scripts/toolchain/linux-i486.cmake b/scripts/toolchain/linux-i486.cmake
new file mode 100644
index 0000000..eb7041a
--- /dev/null
+++ b/scripts/toolchain/linux-i486.cmake
@@ -0,0 +1,58 @@
1set(CMAKE_SYSTEM_VERSION 1)
2set(OS "linux")
3set(CPU "i686")
4set(PLATFORM "")
5if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
6 set(CMAKE_SYSTEM_NAME Linux)
7endif()
8
9# set special CORE_SYSTEM_NAME
10if("${OS}" STREQUAL "android")
11 set(CORE_SYSTEM_NAME android)
12elseif("${OS}" STREQUAL "ios")
13 set(CORE_SYSTEM_NAME ios)
14elseif("${PLATFORM}" STREQUAL "raspberry-pi")
15 set(CORE_SYSTEM_NAME rbpi)
16elseif("${PLATFORM}" STREQUAL "darwin")
17 set(CORE_SYSTEM_NAME darwin)
18endif()
19
20#set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
21
22if("${OS}" STREQUAL "ios" OR "${OS}" STREQUAL "osx")
23 set(CMAKE_SYSTEM_NAME Darwin)
24 #set(CMAKE_OSX_SYSROOT @use_sdk_path@)
25 #list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_OSX_SYSROOT}/usr)
26 #set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_sdk_path@/lib)
27 #set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_sdk_path@/include)
28endif()
29
30#if("${CORE_SYSTEM_NAME}" STREQUAL "rbpi")
31# list(APPEND CMAKE_FIND_ROOT_PATH @use_firmware@/opt/vc)
32# set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_firmware@/opt/vc/lib)
33# set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_firmware@/opt/vc/include)
34#endif()
35
36# specify the cross compiler
37set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu)
38set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
39set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
40set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver")
41set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker")
42set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
43set(CMAKE_C_FLAGS "-m32")
44set(CMAKE_CXX_FLAGS "-m32")
45set(CMAKE_CPP_FLAGS "")
46set(ENV{CFLAGS} ${CMAKE_C_FLAGS})
47set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS})
48set(ENV{CPPFLAGS} ${CMAKE_CPP_FLAGS})
49
50# search for programs in the build host directories
51#set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
52# for libraries and headers in the target directories
53#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
54#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
55
56if(NOT OS STREQUAL "linux")
57 set(ADDONS_PREFER_STATIC_LIBS ON)
58endif()
diff --git a/scripts/toolchain/linux-x86_64.cmake b/scripts/toolchain/linux-x86_64.cmake
new file mode 100644
index 0000000..cb93e39
--- /dev/null
+++ b/scripts/toolchain/linux-x86_64.cmake
@@ -0,0 +1,58 @@
1set(CMAKE_SYSTEM_VERSION 1)
2set(OS "linux")
3set(CPU "x86_64")
4set(PLATFORM "")
5if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
6 set(CMAKE_SYSTEM_NAME Linux)
7endif()
8
9# set special CORE_SYSTEM_NAME
10if("${OS}" STREQUAL "android")
11 set(CORE_SYSTEM_NAME android)
12elseif("${OS}" STREQUAL "ios")
13 set(CORE_SYSTEM_NAME ios)
14elseif("${PLATFORM}" STREQUAL "raspberry-pi")
15 set(CORE_SYSTEM_NAME rbpi)
16elseif("${PLATFORM}" STREQUAL "darwin")
17 set(CORE_SYSTEM_NAME darwin)
18endif()
19
20#set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
21
22if("${OS}" STREQUAL "ios" OR "${OS}" STREQUAL "osx")
23 set(CMAKE_SYSTEM_NAME Darwin)
24 #set(CMAKE_OSX_SYSROOT @use_sdk_path@)
25 #list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_OSX_SYSROOT}/usr)
26 #set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_sdk_path@/lib)
27 #set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_sdk_path@/include)
28endif()
29
30#if("${CORE_SYSTEM_NAME}" STREQUAL "rbpi")
31# list(APPEND CMAKE_FIND_ROOT_PATH @use_firmware@/opt/vc)
32# set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_firmware@/opt/vc/lib)
33# set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_firmware@/opt/vc/include)
34#endif()
35
36# specify the cross compiler
37set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu)
38set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
39set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
40set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver")
41set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker")
42set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
43set(CMAKE_C_FLAGS "")
44set(CMAKE_CXX_FLAGS "")
45set(CMAKE_CPP_FLAGS "")
46set(ENV{CFLAGS} ${CMAKE_C_FLAGS})
47set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS})
48set(ENV{CPPFLAGS} ${CMAKE_CPP_FLAGS})
49
50# search for programs in the build host directories
51#set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
52# for libraries and headers in the target directories
53#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
54#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
55
56if(NOT OS STREQUAL "linux")
57 set(ADDONS_PREFER_STATIC_LIBS ON)
58endif()
diff --git a/scripts/toolchain/osx-i386.cmake b/scripts/toolchain/osx-i386.cmake
new file mode 100644
index 0000000..e2fb927
--- /dev/null
+++ b/scripts/toolchain/osx-i386.cmake
@@ -0,0 +1,58 @@
1set(CMAKE_SYSTEM_VERSION 1)
2set(OS "osx")
3set(CPU "i386")
4set(PLATFORM "darwin")
5if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
6 set(CMAKE_SYSTEM_NAME Linux)
7endif()
8
9# set special CORE_SYSTEM_NAME
10if("${OS}" STREQUAL "android")
11 set(CORE_SYSTEM_NAME android)
12elseif("${OS}" STREQUAL "ios")
13 set(CORE_SYSTEM_NAME ios)
14elseif("${PLATFORM}" STREQUAL "raspberry-pi")
15 set(CORE_SYSTEM_NAME rbpi)
16elseif("${PLATFORM}" STREQUAL "darwin")
17 set(CORE_SYSTEM_NAME darwin)
18endif()
19
20#set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
21
22if("${OS}" STREQUAL "ios" OR "${OS}" STREQUAL "osx")
23 set(CMAKE_SYSTEM_NAME Darwin)
24 #set(CMAKE_OSX_SYSROOT @use_sdk_path@)
25 #list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_OSX_SYSROOT}/usr)
26 #set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_sdk_path@/lib)
27 #set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_sdk_path@/include)
28endif()
29
30#if("${CORE_SYSTEM_NAME}" STREQUAL "rbpi")
31# list(APPEND CMAKE_FIND_ROOT_PATH @use_firmware@/opt/vc)
32# set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_firmware@/opt/vc/lib)
33# set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_firmware@/opt/vc/include)
34#endif()
35
36# specify the cross compiler
37set(COMPILER_PREFIX /var/www/ud_3/xbmc/osx/osxcross/target/bin/i386-apple-darwin14)
38set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-clang)
39set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-clang++)
40set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver")
41set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker")
42set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
43set(CMAKE_C_FLAGS "")
44set(CMAKE_CXX_FLAGS "-stdlib=libc++")
45set(CMAKE_CPP_FLAGS "")
46set(ENV{CFLAGS} ${CMAKE_C_FLAGS})
47set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS})
48set(ENV{CPPFLAGS} ${CMAKE_CPP_FLAGS})
49
50# search for programs in the build host directories
51#set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
52# for libraries and headers in the target directories
53#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
54#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
55
56if(NOT OS STREQUAL "linux")
57 set(ADDONS_PREFER_STATIC_LIBS ON)
58endif()
diff --git a/scripts/toolchain/osx-x86_64.cmake b/scripts/toolchain/osx-x86_64.cmake
new file mode 100644
index 0000000..c14fb06
--- /dev/null
+++ b/scripts/toolchain/osx-x86_64.cmake
@@ -0,0 +1,58 @@
1set(CMAKE_SYSTEM_VERSION 1)
2set(OS "osx")
3set(CPU "x86_64")
4set(PLATFORM "darwin")
5if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
6 set(CMAKE_SYSTEM_NAME Linux)
7endif()
8
9# set special CORE_SYSTEM_NAME
10if("${OS}" STREQUAL "android")
11 set(CORE_SYSTEM_NAME android)
12elseif("${OS}" STREQUAL "ios")
13 set(CORE_SYSTEM_NAME ios)
14elseif("${PLATFORM}" STREQUAL "raspberry-pi")
15 set(CORE_SYSTEM_NAME rbpi)
16elseif("${PLATFORM}" STREQUAL "darwin")
17 set(CORE_SYSTEM_NAME darwin)
18endif()
19
20#set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
21
22if("${OS}" STREQUAL "ios" OR "${OS}" STREQUAL "osx")
23 set(CMAKE_SYSTEM_NAME Darwin)
24 #set(CMAKE_OSX_SYSROOT @use_sdk_path@)
25 #list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_OSX_SYSROOT}/usr)
26 #set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_sdk_path@/lib)
27 #set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_sdk_path@/include)
28endif()
29
30#if("${CORE_SYSTEM_NAME}" STREQUAL "rbpi")
31# list(APPEND CMAKE_FIND_ROOT_PATH @use_firmware@/opt/vc)
32# set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_firmware@/opt/vc/lib)
33# set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_firmware@/opt/vc/include)
34#endif()
35
36# specify the cross compiler
37set(COMPILER_PREFIX /var/www/ud_3/xbmc/osx/osxcross/target/bin/x86_64-apple-darwin14)
38set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-clang)
39set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-clang++)
40set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver")
41set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker")
42set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
43set(CMAKE_C_FLAGS "")
44set(CMAKE_CXX_FLAGS "-stdlib=libc++")
45set(CMAKE_CPP_FLAGS "")
46set(ENV{CFLAGS} ${CMAKE_C_FLAGS})
47set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS})
48set(ENV{CPPFLAGS} ${CMAKE_CPP_FLAGS})
49
50# search for programs in the build host directories
51#set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
52# for libraries and headers in the target directories
53#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
54#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
55
56if(NOT OS STREQUAL "linux")
57 set(ADDONS_PREFER_STATIC_LIBS ON)
58endif()
diff --git a/scripts/toolchain/rbpi-arm.cmake b/scripts/toolchain/rbpi-arm.cmake
new file mode 100644
index 0000000..31c6a94
--- /dev/null
+++ b/scripts/toolchain/rbpi-arm.cmake
@@ -0,0 +1,58 @@
1set(CMAKE_SYSTEM_VERSION 1)
2set(OS "linux")
3set(CPU "arm1176jzf-s")
4set(PLATFORM "raspberry-pi")
5if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android")
6 set(CMAKE_SYSTEM_NAME Linux)
7endif()
8
9# set special CORE_SYSTEM_NAME
10if("${OS}" STREQUAL "android")
11 set(CORE_SYSTEM_NAME android)
12elseif("${OS}" STREQUAL "ios")
13 set(CORE_SYSTEM_NAME ios)
14elseif("${PLATFORM}" STREQUAL "raspberry-pi")
15 set(CORE_SYSTEM_NAME rbpi)
16elseif("${PLATFORM}" STREQUAL "darwin")
17 set(CORE_SYSTEM_NAME darwin)
18endif()
19
20#set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
21
22if("${OS}" STREQUAL "ios" OR "${OS}" STREQUAL "osx")
23 set(CMAKE_SYSTEM_NAME Darwin)
24 #set(CMAKE_OSX_SYSROOT @use_sdk_path@)
25 #list(APPEND CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} ${CMAKE_OSX_SYSROOT}/usr)
26 #set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_sdk_path@/lib)
27 #set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_sdk_path@/include)
28endif()
29
30#if("${CORE_SYSTEM_NAME}" STREQUAL "rbpi")
31# list(APPEND CMAKE_FIND_ROOT_PATH @use_firmware@/opt/vc)
32# set(CMAKE_LIBRARY_PATH @CMAKE_FIND_ROOT_PATH@/lib:@use_firmware@/opt/vc/lib)
33# set(CMAKE_INCLUDE_PATH @CMAKE_FIND_ROOT_PATH@/include:@use_firmware@/opt/vc/include)
34#endif()
35
36# specify the cross compiler
37set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi)
38set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
39set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
40set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver")
41set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker")
42set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib)
43set(CMAKE_C_FLAGS "-mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux")
44set(CMAKE_CXX_FLAGS "-mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux")
45set(CMAKE_CPP_FLAGS "")
46set(ENV{CFLAGS} ${CMAKE_C_FLAGS})
47set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS})
48set(ENV{CPPFLAGS} ${CMAKE_CPP_FLAGS})
49
50# search for programs in the build host directories
51#set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
52# for libraries and headers in the target directories
53#set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
54#set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
55
56if(NOT OS STREQUAL "linux")
57 set(ADDONS_PREFER_STATIC_LIBS ON)
58endif()
diff --git a/version.txt b/version.txt
new file mode 100644
index 0000000..d21c18f
--- /dev/null
+++ b/version.txt
@@ -0,0 +1,11 @@
1APP_NAME Kodi
2COMPANY_NAME XBMC-Foundation
3WEBSITE http://kodi.tv
4VERSION_MAJOR 15
5VERSION_MINOR 0
6VERSION_TAG ALPHA2
7VERSION_CODE 149702
8ADDON_API 14.9.702
9
10# Notes:
11# Change AC_INIT in configure.in
diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp
new file mode 100644
index 0000000..2aa849f
--- /dev/null
+++ b/xbmc/addons/Addon.cpp
@@ -0,0 +1,653 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Addon.h"
22#include "AddonManager.h"
23#include "settings/Settings.h"
24#include "filesystem/Directory.h"
25#include "filesystem/File.h"
26#include "system.h"
27#ifdef HAS_PYTHON
28#include "interfaces/python/XBPython.h"
29#endif
30#if defined(TARGET_DARWIN)
31#include "../osx/OSXGNUReplacements.h"
32#endif
33#ifdef TARGET_FREEBSD
34#include "freebsd/FreeBSDGNUReplacements.h"
35#endif
36#include "utils/log.h"
37#include "utils/StringUtils.h"
38#include "utils/URIUtils.h"
39#include "URL.h"
40#include "Util.h"
41#include <vector>
42#include <string.h>
43#include <ostream>
44
45using XFILE::CDirectory;
46using XFILE::CFile;
47using namespace std;
48
49namespace ADDON
50{
51
52/**
53 * helper functions
54 *
55 */
56
57typedef struct
58{
59 const char* name;
60 TYPE type;
61 int pretty;
62 const char* icon;
63} TypeMapping;
64
65static const TypeMapping types[] =
66 {{"unknown", ADDON_UNKNOWN, 0, "" },
67 {"xbmc.metadata.scraper.albums", ADDON_SCRAPER_ALBUMS, 24016, "DefaultAddonAlbumInfo.png" },
68 {"xbmc.metadata.scraper.artists", ADDON_SCRAPER_ARTISTS, 24017, "DefaultAddonArtistInfo.png" },
69 {"xbmc.metadata.scraper.movies", ADDON_SCRAPER_MOVIES, 24007, "DefaultAddonMovieInfo.png" },
70 {"xbmc.metadata.scraper.musicvideos", ADDON_SCRAPER_MUSICVIDEOS, 24015, "DefaultAddonMusicVideoInfo.png" },
71 {"xbmc.metadata.scraper.tvshows", ADDON_SCRAPER_TVSHOWS, 24014, "DefaultAddonTvInfo.png" },
72 {"xbmc.metadata.scraper.library", ADDON_SCRAPER_LIBRARY, 24083, "DefaultAddonInfoLibrary.png" },
73 {"xbmc.ui.screensaver", ADDON_SCREENSAVER, 24008, "DefaultAddonScreensaver.png" },
74 {"xbmc.player.musicviz", ADDON_VIZ, 24010, "DefaultAddonVisualization.png" },
75 {"visualization-library", ADDON_VIZ_LIBRARY, 24084, "" },
76 {"xbmc.python.pluginsource", ADDON_PLUGIN, 24005, "" },
77 {"xbmc.python.script", ADDON_SCRIPT, 24009, "" },
78 {"xbmc.python.weather", ADDON_SCRIPT_WEATHER, 24027, "DefaultAddonWeather.png" },
79 {"xbmc.python.lyrics", ADDON_SCRIPT_LYRICS, 24013, "DefaultAddonLyrics.png" },
80 {"xbmc.python.library", ADDON_SCRIPT_LIBRARY, 24081, "DefaultAddonHelper.png" },
81 {"xbmc.python.module", ADDON_SCRIPT_MODULE, 24082, "DefaultAddonLibrary.png" },
82 {"xbmc.subtitle.module", ADDON_SUBTITLE_MODULE, 24012, "DefaultAddonSubtitles.png" },
83 {"kodi.context.item", ADDON_CONTEXT_ITEM, 24025, "DefaultAddonContextItem.png" },
84 {"xbmc.gui.skin", ADDON_SKIN, 166, "DefaultAddonSkin.png" },
85 {"xbmc.webinterface", ADDON_WEB_INTERFACE, 199, "DefaultAddonWebSkin.png" },
86 {"xbmc.addon.repository", ADDON_REPOSITORY, 24011, "DefaultAddonRepository.png" },
87 {"xbmc.pvrclient", ADDON_PVRDLL, 24019, "DefaultAddonPVRClient.png" },
88 {"xbmc.addon.video", ADDON_VIDEO, 1037, "DefaultAddonVideo.png" },
89 {"xbmc.addon.audio", ADDON_AUDIO, 1038, "DefaultAddonMusic.png" },
90 {"xbmc.addon.image", ADDON_IMAGE, 1039, "DefaultAddonPicture.png" },
91 {"xbmc.addon.executable", ADDON_EXECUTABLE, 1043, "DefaultAddonProgram.png" },
92 {"xbmc.audioencoder", ADDON_AUDIOENCODER, 200, "DefaultAddonAudioEncoder.png" },
93 {"xbmc.service", ADDON_SERVICE, 24018, "DefaultAddonService.png" }};
94
95const std::string TranslateType(const ADDON::TYPE &type, bool pretty/*=false*/)
96{
97 for (unsigned int index=0; index < ARRAY_SIZE(types); ++index)
98 {
99 const TypeMapping &map = types[index];
100 if (type == map.type)
101 {
102 if (pretty && map.pretty)
103 return g_localizeStrings.Get(map.pretty);
104 else
105 return map.name;
106 }
107 }
108 return "";
109}
110
111TYPE TranslateType(const std::string &string)
112{
113 for (unsigned int index=0; index < ARRAY_SIZE(types); ++index)
114 {
115 const TypeMapping &map = types[index];
116 if (string == map.name)
117 return map.type;
118 }
119
120 return ADDON_UNKNOWN;
121}
122
123const std::string GetIcon(const ADDON::TYPE& type)
124{
125 for (unsigned int index=0; index < ARRAY_SIZE(types); ++index)
126 {
127 const TypeMapping &map = types[index];
128 if (type == map.type)
129 return map.icon;
130 }
131 return "";
132}
133
134#define EMPTY_IF(x,y) \
135 { \
136 std::string fan=CAddonMgr::Get().GetExtValue(metadata->configuration, x); \
137 if (fan == "true") \
138 y.clear(); \
139 }
140
141#define SS(x) (x) ? x : ""
142
143AddonProps::AddonProps(const cp_extension_t *ext)
144 : id(SS(ext->plugin->identifier))
145 , version(SS(ext->plugin->version))
146 , minversion(SS(ext->plugin->abi_bw_compatibility))
147 , name(SS(ext->plugin->name))
148 , path(SS(ext->plugin->plugin_path))
149 , author(SS(ext->plugin->provider_name))
150 , stars(0)
151{
152 if (ext->ext_point_id)
153 type = TranslateType(ext->ext_point_id);
154
155 icon = "icon.png";
156 fanart = URIUtils::AddFileToFolder(path, "fanart.jpg");
157 changelog = URIUtils::AddFileToFolder(path, "changelog.txt");
158 // Grab more detail from the props...
159 const cp_extension_t *metadata = CAddonMgr::Get().GetExtension(ext->plugin, "xbmc.addon.metadata"); //<! backword compatibilty
160 if (!metadata)
161 metadata = CAddonMgr::Get().GetExtension(ext->plugin, "kodi.addon.metadata");
162 if (metadata)
163 {
164 summary = CAddonMgr::Get().GetTranslatedString(metadata->configuration, "summary");
165 description = CAddonMgr::Get().GetTranslatedString(metadata->configuration, "description");
166 disclaimer = CAddonMgr::Get().GetTranslatedString(metadata->configuration, "disclaimer");
167 license = CAddonMgr::Get().GetExtValue(metadata->configuration, "license");
168 std::string language;
169 language = CAddonMgr::Get().GetExtValue(metadata->configuration, "language");
170 if (!language.empty())
171 extrainfo.insert(make_pair("language",language));
172 broken = CAddonMgr::Get().GetExtValue(metadata->configuration, "broken");
173 EMPTY_IF("nofanart",fanart)
174 EMPTY_IF("noicon",icon)
175 EMPTY_IF("nochangelog",changelog)
176 }
177 BuildDependencies(ext->plugin);
178}
179
180AddonProps::AddonProps(const cp_plugin_info_t *plugin)
181 : id(SS(plugin->identifier))
182 , type(ADDON_UNKNOWN)
183 , version(SS(plugin->version))
184 , minversion(SS(plugin->abi_bw_compatibility))
185 , name(SS(plugin->name))
186 , path(SS(plugin->plugin_path))
187 , author(SS(plugin->provider_name))
188 , stars(0)
189{
190 BuildDependencies(plugin);
191}
192
193void AddonProps::Serialize(CVariant &variant) const
194{
195 variant["addonid"] = id;
196 variant["type"] = TranslateType(type);
197 variant["version"] = version.asString();
198 variant["minversion"] = minversion.asString();
199 variant["name"] = name;
200 variant["license"] = license;
201 variant["summary"] = summary;
202 variant["description"] = description;
203 variant["path"] = path;
204 variant["libname"] = libname;
205 variant["author"] = author;
206 variant["source"] = source;
207
208 if (CURL::IsFullPath(icon))
209 variant["icon"] = icon;
210 else
211 variant["icon"] = URIUtils::AddFileToFolder(path, icon);
212
213 variant["thumbnail"] = variant["icon"];
214 variant["disclaimer"] = disclaimer;
215 variant["changelog"] = changelog;
216
217 if (CURL::IsFullPath(fanart))
218 variant["fanart"] = fanart;
219 else
220 variant["fanart"] = URIUtils::AddFileToFolder(path, fanart);
221
222 variant["dependencies"] = CVariant(CVariant::VariantTypeArray);
223 for (ADDONDEPS::const_iterator it = dependencies.begin(); it != dependencies.end(); ++it)
224 {
225 CVariant dep(CVariant::VariantTypeObject);
226 dep["addonid"] = it->first;
227 dep["version"] = it->second.first.asString();
228 dep["optional"] = it->second.second;
229 variant["dependencies"].push_back(dep);
230 }
231 if (broken.empty())
232 variant["broken"] = false;
233 else
234 variant["broken"] = broken;
235 variant["extrainfo"] = CVariant(CVariant::VariantTypeArray);
236 for (InfoMap::const_iterator it = extrainfo.begin(); it != extrainfo.end(); ++it)
237 {
238 CVariant info(CVariant::VariantTypeObject);
239 info["key"] = it->first;
240 info["value"] = it->second;
241 variant["extrainfo"].push_back(info);
242 }
243 variant["rating"] = stars;
244}
245
246void AddonProps::BuildDependencies(const cp_plugin_info_t *plugin)
247{
248 if (!plugin)
249 return;
250 for (unsigned int i = 0; i < plugin->num_imports; ++i)
251 dependencies.insert(make_pair(std::string(plugin->imports[i].plugin_id),
252 make_pair(AddonVersion(SS(plugin->imports[i].version)), plugin->imports[i].optional != 0)));
253}
254
255/**
256 * CAddon
257 *
258 */
259
260CAddon::CAddon(const cp_extension_t *ext)
261 : m_props(ext)
262{
263 BuildLibName(ext);
264 Props().libname = m_strLibName;
265 BuildProfilePath();
266 m_userSettingsPath = URIUtils::AddFileToFolder(Profile(), "settings.xml");
267 m_enabled = true;
268 m_hasSettings = true;
269 m_hasStrings = false;
270 m_checkedStrings = false;
271 m_settingsLoaded = false;
272 m_userSettingsLoaded = false;
273}
274
275CAddon::CAddon(const cp_plugin_info_t *plugin)
276 : m_props(plugin)
277{
278 m_enabled = true;
279 m_hasSettings = false;
280 m_hasStrings = false;
281 m_checkedStrings = true;
282 m_settingsLoaded = false;
283 m_userSettingsLoaded = false;
284}
285
286CAddon::CAddon(const AddonProps &props)
287 : m_props(props)
288{
289 if (props.libname.empty()) BuildLibName();
290 else m_strLibName = props.libname;
291 BuildProfilePath();
292 m_userSettingsPath = URIUtils::AddFileToFolder(Profile(), "settings.xml");
293 m_enabled = true;
294 m_hasSettings = true;
295 m_hasStrings = false;
296 m_checkedStrings = false;
297 m_settingsLoaded = false;
298 m_userSettingsLoaded = false;
299}
300
301CAddon::CAddon(const CAddon &rhs)
302 : m_props(rhs.Props()),
303 m_settings(rhs.m_settings)
304{
305 m_addonXmlDoc = rhs.m_addonXmlDoc;
306 m_settingsLoaded = rhs.m_settingsLoaded;
307 m_userSettingsLoaded = rhs.m_userSettingsLoaded;
308 m_hasSettings = rhs.m_hasSettings;
309 BuildProfilePath();
310 m_userSettingsPath = URIUtils::AddFileToFolder(Profile(), "settings.xml");
311 m_strLibName = rhs.m_strLibName;
312 m_enabled = rhs.Enabled();
313 m_hasStrings = false;
314 m_checkedStrings = false;
315}
316
317AddonPtr CAddon::Clone() const
318{
319 return AddonPtr(new CAddon(*this));
320}
321
322bool CAddon::MeetsVersion(const AddonVersion &version) const
323{
324 return m_props.minversion <= version && version <= m_props.version;
325}
326
327//TODO platform/path crap should be negotiated between the addon and
328// the handler for it's type
329void CAddon::BuildLibName(const cp_extension_t *extension)
330{
331 if (!extension)
332 {
333 m_strLibName = "default";
334 std::string ext;
335 switch (m_props.type)
336 {
337 case ADDON_SCRAPER_ALBUMS:
338 case ADDON_SCRAPER_ARTISTS:
339 case ADDON_SCRAPER_MOVIES:
340 case ADDON_SCRAPER_MUSICVIDEOS:
341 case ADDON_SCRAPER_TVSHOWS:
342 case ADDON_SCRAPER_LIBRARY:
343 ext = ADDON_SCRAPER_EXT;
344 break;
345 case ADDON_SCREENSAVER:
346 ext = ADDON_SCREENSAVER_EXT;
347 break;
348 case ADDON_SKIN:
349 m_strLibName = "skin.xml";
350 return;
351 case ADDON_VIZ:
352 ext = ADDON_VIS_EXT;
353 break;
354 case ADDON_PVRDLL:
355 ext = ADDON_PVRDLL_EXT;
356 break;
357 case ADDON_SCRIPT:
358 case ADDON_SCRIPT_LIBRARY:
359 case ADDON_SCRIPT_LYRICS:
360 case ADDON_SCRIPT_WEATHER:
361 case ADDON_SUBTITLE_MODULE:
362 case ADDON_PLUGIN:
363 case ADDON_SERVICE:
364 case ADDON_CONTEXT_ITEM:
365 ext = ADDON_PYTHON_EXT;
366 break;
367 default:
368 m_strLibName.clear();
369 return;
370 }
371 // extensions are returned as *.ext
372 // so remove the asterisk
373 ext.erase(0,1);
374 m_strLibName.append(ext);
375 }
376 else
377 {
378 switch (m_props.type)
379 {
380 case ADDON_SCREENSAVER:
381 case ADDON_SCRIPT:
382 case ADDON_SCRIPT_LIBRARY:
383 case ADDON_SCRIPT_LYRICS:
384 case ADDON_SCRIPT_WEATHER:
385 case ADDON_SCRIPT_MODULE:
386 case ADDON_SUBTITLE_MODULE:
387 case ADDON_SCRAPER_ALBUMS:
388 case ADDON_SCRAPER_ARTISTS:
389 case ADDON_SCRAPER_MOVIES:
390 case ADDON_SCRAPER_MUSICVIDEOS:
391 case ADDON_SCRAPER_TVSHOWS:
392 case ADDON_SCRAPER_LIBRARY:
393 case ADDON_PVRDLL:
394 case ADDON_PLUGIN:
395 case ADDON_WEB_INTERFACE:
396 case ADDON_SERVICE:
397 case ADDON_REPOSITORY:
398 case ADDON_AUDIOENCODER:
399 case ADDON_CONTEXT_ITEM:
400 {
401 std::string temp = CAddonMgr::Get().GetExtValue(extension->configuration, "@library");
402 m_strLibName = temp;
403 }
404 break;
405 default:
406 m_strLibName.clear();
407 break;
408 }
409 }
410}
411
412/**
413 * Language File Handling
414 */
415bool CAddon::LoadStrings()
416{
417 // Path where the language strings reside
418 std::string chosenPath = URIUtils::AddFileToFolder(m_props.path, "resources/language/");
419
420 m_hasStrings = m_strings.Load(chosenPath, CSettings::Get().GetString("locale.language"));
421 return m_checkedStrings = true;
422}
423
424void CAddon::ClearStrings()
425{
426 // Unload temporary language strings
427 m_strings.Clear();
428 m_hasStrings = false;
429}
430
431std::string CAddon::GetString(uint32_t id)
432{
433 if (!m_hasStrings && ! m_checkedStrings && !LoadStrings())
434 return "";
435
436 return m_strings.Get(id);
437}
438
439/**
440 * Settings Handling
441 */
442bool CAddon::HasSettings()
443{
444 return LoadSettings();
445}
446
447bool CAddon::LoadSettings(bool bForce /* = false*/)
448{
449 if (m_settingsLoaded && !bForce)
450 return true;
451 if (!m_hasSettings)
452 return false;
453 std::string addonFileName = URIUtils::AddFileToFolder(m_props.path, "resources/settings.xml");
454
455 if (!m_addonXmlDoc.LoadFile(addonFileName))
456 {
457 if (CFile::Exists(addonFileName))
458 CLog::Log(LOGERROR, "Unable to load: %s, Line %d\n%s", addonFileName.c_str(), m_addonXmlDoc.ErrorRow(), m_addonXmlDoc.ErrorDesc());
459 m_hasSettings = false;
460 return false;
461 }
462
463 // Make sure that the addon XML has the settings element
464 TiXmlElement *setting = m_addonXmlDoc.RootElement();
465 if (!setting || strcmpi(setting->Value(), "settings") != 0)
466 {
467 CLog::Log(LOGERROR, "Error loading Settings %s: cannot find root element 'settings'", addonFileName.c_str());
468 return false;
469 }
470 SettingsFromXML(m_addonXmlDoc, true);
471 LoadUserSettings();
472 m_settingsLoaded = true;
473 return true;
474}
475
476bool CAddon::HasUserSettings()
477{
478 if (!LoadSettings())
479 return false;
480
481 return m_userSettingsLoaded;
482}
483
484bool CAddon::ReloadSettings()
485{
486 return LoadSettings(true);
487}
488
489bool CAddon::LoadUserSettings()
490{
491 m_userSettingsLoaded = false;
492 CXBMCTinyXML doc;
493 if (doc.LoadFile(m_userSettingsPath))
494 m_userSettingsLoaded = SettingsFromXML(doc);
495 return m_userSettingsLoaded;
496}
497
498void CAddon::SaveSettings(void)
499{
500 if (m_settings.empty())
501 return; // no settings to save
502
503 // break down the path into directories
504 std::string strAddon = URIUtils::GetDirectory(m_userSettingsPath);
505 URIUtils::RemoveSlashAtEnd(strAddon);
506 std::string strRoot = URIUtils::GetDirectory(strAddon);
507 URIUtils::RemoveSlashAtEnd(strRoot);
508
509 // create the individual folders
510 if (!CDirectory::Exists(strRoot))
511 CDirectory::Create(strRoot);
512 if (!CDirectory::Exists(strAddon))
513 CDirectory::Create(strAddon);
514
515 // create the XML file
516 CXBMCTinyXML doc;
517 SettingsToXML(doc);
518 doc.SaveFile(m_userSettingsPath);
519 m_userSettingsLoaded = true;
520
521 CAddonMgr::Get().ReloadSettings(ID());//push the settings changes to the running addon instance
522#ifdef HAS_PYTHON
523 g_pythonParser.OnSettingsChanged(ID());
524#endif
525}
526
527std::string CAddon::GetSetting(const std::string& key)
528{
529 if (!LoadSettings())
530 return ""; // no settings available
531
532 map<std::string, std::string>::const_iterator i = m_settings.find(key);
533 if (i != m_settings.end())
534 return i->second;
535 return "";
536}
537
538void CAddon::UpdateSetting(const std::string& key, const std::string& value)
539{
540 LoadSettings();
541 if (key.empty()) return;
542 m_settings[key] = value;
543}
544
545bool CAddon::SettingsFromXML(const CXBMCTinyXML &doc, bool loadDefaults /*=false */)
546{
547 if (!doc.RootElement())
548 return false;
549
550 if (loadDefaults)
551 m_settings.clear();
552
553 const TiXmlElement* category = doc.RootElement()->FirstChildElement("category");
554 if (!category)
555 category = doc.RootElement();
556
557 bool foundSetting = false;
558 while (category)
559 {
560 const TiXmlElement *setting = category->FirstChildElement("setting");
561 while (setting)
562 {
563 const char *id = setting->Attribute("id");
564 const char *value = setting->Attribute(loadDefaults ? "default" : "value");
565 if (id && value)
566 {
567 m_settings[id] = value;
568 foundSetting = true;
569 }
570 setting = setting->NextSiblingElement("setting");
571 }
572 category = category->NextSiblingElement("category");
573 }
574 return foundSetting;
575}
576
577void CAddon::SettingsToXML(CXBMCTinyXML &doc) const
578{
579 TiXmlElement node("settings");
580 doc.InsertEndChild(node);
581 for (map<std::string, std::string>::const_iterator i = m_settings.begin(); i != m_settings.end(); ++i)
582 {
583 TiXmlElement nodeSetting("setting");
584 nodeSetting.SetAttribute("id", i->first.c_str());
585 nodeSetting.SetAttribute("value", i->second.c_str());
586 doc.RootElement()->InsertEndChild(nodeSetting);
587 }
588 doc.SaveFile(m_userSettingsPath);
589}
590
591TiXmlElement* CAddon::GetSettingsXML()
592{
593 return m_addonXmlDoc.RootElement();
594}
595
596void CAddon::BuildProfilePath()
597{
598 m_profile = StringUtils::Format("special://profile/addon_data/%s/", ID().c_str());
599}
600
601const std::string CAddon::Icon() const
602{
603 if (CURL::IsFullPath(m_props.icon))
604 return m_props.icon;
605 return URIUtils::AddFileToFolder(m_props.path, m_props.icon);
606}
607
608const std::string CAddon::LibPath() const
609{
610 return URIUtils::AddFileToFolder(m_props.path, m_strLibName);
611}
612
613AddonVersion CAddon::GetDependencyVersion(const std::string &dependencyID) const
614{
615 const ADDON::ADDONDEPS &deps = GetDeps();
616 ADDONDEPS::const_iterator it = deps.find(dependencyID);
617 if (it != deps.end())
618 return it->second.first;
619 return AddonVersion("0.0.0");
620}
621
622/**
623 * CAddonLibrary
624 *
625 */
626
627CAddonLibrary::CAddonLibrary(const cp_extension_t *ext)
628 : CAddon(ext)
629 , m_addonType(SetAddonType())
630{
631}
632
633CAddonLibrary::CAddonLibrary(const AddonProps& props)
634 : CAddon(props)
635 , m_addonType(SetAddonType())
636{
637}
638
639AddonPtr CAddonLibrary::Clone() const
640{
641 return AddonPtr(new CAddonLibrary(*this));
642}
643
644TYPE CAddonLibrary::SetAddonType()
645{
646 if (Type() == ADDON_VIZ_LIBRARY)
647 return ADDON_VIZ;
648 else
649 return ADDON_UNKNOWN;
650}
651
652} /* namespace ADDON */
653
diff --git a/xbmc/addons/Addon.h b/xbmc/addons/Addon.h
new file mode 100644
index 0000000..4fbf085
--- /dev/null
+++ b/xbmc/addons/Addon.h
@@ -0,0 +1,278 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "IAddon.h"
23#include "addons/AddonVersion.h"
24#include "utils/XBMCTinyXML.h"
25#include "guilib/LocalizeStrings.h"
26#include "utils/ISerializable.h"
27#include <vector>
28
29class TiXmlElement;
30class CAddonCallbacksAddon;
31
32typedef struct cp_plugin_info_t cp_plugin_info_t;
33typedef struct cp_extension_t cp_extension_t;
34
35namespace ADDON
36{
37 typedef std::vector<AddonPtr> VECADDONS;
38 typedef std::vector<AddonPtr>::iterator IVECADDONS;
39
40// utils
41const std::string TranslateType(const TYPE &type, bool pretty=false);
42const std::string GetIcon(const TYPE &type);
43 TYPE TranslateType(const std::string &string);
44
45class AddonProps : public ISerializable
46{
47public:
48 AddonProps(const std::string &id, TYPE type, const std::string &versionstr, const std::string &minversionstr)
49 : id(id)
50 , type(type)
51 , version(versionstr)
52 , minversion(minversionstr)
53 , stars(0)
54 {
55 }
56
57 virtual ~AddonProps() {}
58
59 AddonProps(const cp_extension_t *ext);
60 AddonProps(const cp_plugin_info_t *plugin);
61
62 bool operator==(const AddonProps &rhs)
63 {
64 return (*this).id == rhs.id
65 && (*this).type == rhs.type
66 && (*this).version == rhs.version;
67 }
68
69 void Serialize(CVariant &variant) const;
70
71 std::string id;
72 TYPE type;
73 AddonVersion version;
74 AddonVersion minversion;
75 std::string name;
76 std::string license;
77 std::string summary;
78 std::string description;
79 std::string path;
80 std::string libname;
81 std::string author;
82 std::string source;
83 std::string icon;
84 std::string disclaimer;
85 std::string changelog;
86 std::string fanart;
87 ADDONDEPS dependencies;
88 std::string broken;
89 InfoMap extrainfo;
90 int stars;
91private:
92 void BuildDependencies(const cp_plugin_info_t *plugin);
93};
94
95typedef std::vector<class AddonProps> VECADDONPROPS;
96
97class CAddon : public IAddon
98{
99public:
100 CAddon(const AddonProps &addonprops);
101 CAddon(const cp_extension_t *ext);
102 CAddon(const cp_plugin_info_t *plugin);
103 virtual ~CAddon() {}
104 virtual AddonPtr Clone() const;
105
106 /*! \brief Check whether the this addon can be configured or not
107 \return true if the addon has settings, false otherwise
108 \sa LoadSettings, LoadUserSettings, SaveSettings, HasUserSettings, GetSetting, UpdateSetting
109 */
110 bool HasSettings();
111
112 /*! \brief Check whether the user has configured this addon or not
113 \return true if previously saved settings are found, false otherwise
114 \sa LoadSettings, LoadUserSettings, SaveSettings, HasSettings, GetSetting, UpdateSetting
115 */
116 bool HasUserSettings();
117
118 /*! \brief Save any user configured settings
119 \sa LoadSettings, LoadUserSettings, HasSettings, HasUserSettings, GetSetting, UpdateSetting
120 */
121 virtual void SaveSettings();
122
123 /*! \brief Update a user-configured setting with a new value
124 \param key the id of the setting to update
125 \param value the value that the setting should take
126 \sa LoadSettings, LoadUserSettings, SaveSettings, HasSettings, HasUserSettings, GetSetting
127 */
128 void UpdateSetting(const std::string& key, const std::string& value);
129
130 /*! \brief Retrieve a particular settings value
131 If a previously configured user setting is available, we return it's value, else we return the default (if available)
132 \param key the id of the setting to retrieve
133 \return the current value of the setting, or the default if the setting has yet to be configured.
134 \sa LoadSettings, LoadUserSettings, SaveSettings, HasSettings, HasUserSettings, UpdateSetting
135 */
136 virtual std::string GetSetting(const std::string& key);
137
138 TiXmlElement* GetSettingsXML();
139 virtual std::string GetString(uint32_t id);
140
141 // properties
142 TYPE Type() const { return m_props.type; }
143 bool IsType(TYPE type) const { return type == m_props.type; }
144 AddonProps Props() const { return m_props; }
145 AddonProps& Props() { return m_props; }
146 const std::string ID() const { return m_props.id; }
147 const std::string Name() const { return m_props.name; }
148 bool Enabled() const { return m_enabled; }
149 virtual bool IsInUse() const { return false; };
150 const AddonVersion Version() const { return m_props.version; }
151 const AddonVersion MinVersion() const { return m_props.minversion; }
152 const std::string Summary() const { return m_props.summary; }
153 const std::string Description() const { return m_props.description; }
154 const std::string Path() const { return m_props.path; }
155 const std::string Profile() const { return m_profile; }
156 const std::string LibPath() const;
157 const std::string Author() const { return m_props.author; }
158 const std::string ChangeLog() const { return m_props.changelog; }
159 const std::string FanArt() const { return m_props.fanart; }
160 const std::string Icon() const;
161 int Stars() const { return m_props.stars; }
162 const std::string Disclaimer() const { return m_props.disclaimer; }
163 const InfoMap &ExtraInfo() const { return m_props.extrainfo; }
164 const ADDONDEPS &GetDeps() const { return m_props.dependencies; }
165
166 /*! \brief get the required version of a dependency.
167 \param dependencyID the addon ID of the dependency.
168 \return the version this addon requires.
169 */
170 AddonVersion GetDependencyVersion(const std::string &dependencyID) const;
171
172 /*! \brief return whether or not this addon satisfies the given version requirements
173 \param version the version to meet.
174 \return true if min_version <= version <= current_version, false otherwise.
175 */
176 bool MeetsVersion(const AddonVersion &version) const;
177 virtual bool ReloadSettings();
178
179 void MarkAsDisabled() { m_enabled = false; }
180
181 /*! \brief callback for when this add-on is disabled.
182 Use to perform any needed actions (e.g. stop a service)
183 */
184 virtual void OnDisabled() {};
185
186 /*! \brief callback for when this add-on is enabled.
187 Use to perform any needed actions (e.g. start a service)
188 */
189 virtual void OnEnabled() {};
190
191 /*! \brief retrieve the running instance of an add-on if it persists while running.
192 */
193 virtual AddonPtr GetRunningInstance() const { return AddonPtr(); }
194
195 /*! \brief callbacks for special install/uninstall behaviour */
196 virtual bool OnPreInstall() { return false; };
197 virtual void OnPostInstall(bool restart, bool update, bool modal) {};
198 virtual void OnPreUnInstall() {};
199 virtual void OnPostUnInstall() {};
200 virtual bool CanInstall(const std::string& referer) { return true; }
201protected:
202 friend class CAddonCallbacksAddon;
203
204 CAddon(const CAddon &rhs); // protected as all copying is handled by Clone()
205 virtual void BuildLibName(const cp_extension_t *ext = NULL);
206
207 /*! \brief Load the default settings and override these with any previously configured user settings
208 \param bForce force the load of settings even if they are already loaded (reload)
209 \return true if settings exist, false otherwise
210 \sa LoadUserSettings, SaveSettings, HasSettings, HasUserSettings, GetSetting, UpdateSetting
211 */
212 virtual bool LoadSettings(bool bForce = false);
213
214 /*! \brief Load the user settings
215 \return true if user settings exist, false otherwise
216 \sa LoadSettings, SaveSettings, HasSettings, HasUserSettings, GetSetting, UpdateSetting
217 */
218 bool LoadUserSettings();
219
220 /*! \brief Parse settings from an XML document
221 \param doc XML document to parse for settings
222 \param loadDefaults if true, the default attribute is used and settings are reset prior to parsing, else the value attribute is used.
223 \return true if settings are loaded, false otherwise
224 \sa SettingsToXML
225 */
226 bool SettingsFromXML(const CXBMCTinyXML &doc, bool loadDefaults = false);
227
228 /*! \brief Parse settings into an XML document
229 \param doc XML document to receive the settings
230 \sa SettingsFromXML
231 */
232 void SettingsToXML(CXBMCTinyXML &doc) const;
233
234 CXBMCTinyXML m_addonXmlDoc;
235 std::string m_strLibName;
236 bool m_settingsLoaded;
237 bool m_userSettingsLoaded;
238
239 virtual void ClearStrings();
240private:
241 friend class CAddonMgr;
242 AddonProps m_props;
243 std::string m_userSettingsPath;
244 void BuildProfilePath();
245
246 virtual bool IsAddonLibrary() { return false; }
247
248 void Enable() { LoadStrings(); m_enabled = true; }
249 void Disable() { m_enabled = false; ClearStrings();}
250
251 virtual bool LoadStrings();
252
253 bool m_hasStrings;
254 bool m_checkedStrings;
255 bool m_hasSettings;
256
257 std::string m_profile;
258 bool m_enabled;
259 CLocalizeStrings m_strings;
260 std::map<std::string, std::string> m_settings;
261};
262
263class CAddonLibrary : public CAddon
264{
265public:
266 CAddonLibrary(const AddonProps &props);
267 CAddonLibrary(const cp_extension_t *ext);
268
269 virtual AddonPtr Clone() const;
270
271private:
272 virtual bool IsAddonLibrary() { return true; }
273 TYPE SetAddonType();
274 const TYPE m_addonType; // addon type this library enhances
275};
276
277}; /* namespace ADDON */
278
diff --git a/xbmc/addons/AddonCallbacks.cpp b/xbmc/addons/AddonCallbacks.cpp
new file mode 100644
index 0000000..8634373
--- /dev/null
+++ b/xbmc/addons/AddonCallbacks.cpp
@@ -0,0 +1,173 @@
1/*
2 * Copyright (C) 2012-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Addon.h"
22#include "AddonCallbacks.h"
23#include "AddonCallbacksAddon.h"
24#include "AddonCallbacksCodec.h"
25#include "AddonCallbacksGUI.h"
26#include "AddonCallbacksPVR.h"
27#include "filesystem/SpecialProtocol.h"
28#include "utils/log.h"
29
30namespace ADDON
31{
32
33CAddonCallbacks::CAddonCallbacks(CAddon* addon)
34{
35 m_addon = addon;
36 m_callbacks = new AddonCB;
37 m_helperAddon = NULL;
38 m_helperGUI = NULL;
39 m_helperPVR = NULL;
40 m_helperCODEC = NULL;
41
42 m_callbacks->libBasePath = strdup(CSpecialProtocol::TranslatePath("special://xbmcbin/addons").c_str());
43 m_callbacks->addonData = this;
44 m_callbacks->AddOnLib_RegisterMe = CAddonCallbacks::AddOnLib_RegisterMe;
45 m_callbacks->AddOnLib_UnRegisterMe = CAddonCallbacks::AddOnLib_UnRegisterMe;
46 m_callbacks->CODECLib_RegisterMe = CAddonCallbacks::CODECLib_RegisterMe;
47 m_callbacks->CODECLib_UnRegisterMe = CAddonCallbacks::CODECLib_UnRegisterMe;
48 m_callbacks->GUILib_RegisterMe = CAddonCallbacks::GUILib_RegisterMe;
49 m_callbacks->GUILib_UnRegisterMe = CAddonCallbacks::GUILib_UnRegisterMe;
50 m_callbacks->PVRLib_RegisterMe = CAddonCallbacks::PVRLib_RegisterMe;
51 m_callbacks->PVRLib_UnRegisterMe = CAddonCallbacks::PVRLib_UnRegisterMe;
52}
53
54CAddonCallbacks::~CAddonCallbacks()
55{
56 delete m_helperAddon;
57 m_helperAddon = NULL;
58 delete m_helperCODEC;
59 m_helperCODEC = NULL;
60 delete m_helperGUI;
61 m_helperGUI = NULL;
62 delete m_helperPVR;
63 m_helperPVR = NULL;
64 free((char*)m_callbacks->libBasePath);
65 delete m_callbacks;
66 m_callbacks = NULL;
67}
68
69CB_AddOnLib* CAddonCallbacks::AddOnLib_RegisterMe(void *addonData)
70{
71 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
72 if (addon == NULL)
73 {
74 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
75 return NULL;
76 }
77
78 addon->m_helperAddon = new CAddonCallbacksAddon(addon->m_addon);
79 return addon->m_helperAddon->GetCallbacks();
80}
81
82void CAddonCallbacks::AddOnLib_UnRegisterMe(void *addonData, CB_AddOnLib *cbTable)
83{
84 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
85 if (addon == NULL)
86 {
87 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
88 return;
89 }
90
91 delete addon->m_helperAddon;
92 addon->m_helperAddon = NULL;
93}
94
95CB_CODECLib* CAddonCallbacks::CODECLib_RegisterMe(void *addonData)
96{
97 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
98 if (addon == NULL)
99 {
100 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
101 return NULL;
102 }
103
104 addon->m_helperCODEC = new CAddonCallbacksCodec(addon->m_addon);
105 return addon->m_helperCODEC->GetCallbacks();
106}
107
108void CAddonCallbacks::CODECLib_UnRegisterMe(void *addonData, CB_CODECLib *cbTable)
109{
110 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
111 if (addon == NULL)
112 {
113 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
114 return;
115 }
116
117 delete addon->m_helperCODEC;
118 addon->m_helperCODEC = NULL;
119}
120
121CB_GUILib* CAddonCallbacks::GUILib_RegisterMe(void *addonData)
122{
123 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
124 if (addon == NULL)
125 {
126 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
127 return NULL;
128 }
129
130 addon->m_helperGUI = new CAddonCallbacksGUI(addon->m_addon);
131 return addon->m_helperGUI->GetCallbacks();
132}
133
134void CAddonCallbacks::GUILib_UnRegisterMe(void *addonData, CB_GUILib *cbTable)
135{
136 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
137 if (addon == NULL)
138 {
139 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
140 return;
141 }
142
143 delete addon->m_helperGUI;
144 addon->m_helperGUI = NULL;
145}
146
147CB_PVRLib* CAddonCallbacks::PVRLib_RegisterMe(void *addonData)
148{
149 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
150 if (addon == NULL)
151 {
152 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
153 return NULL;
154 }
155
156 addon->m_helperPVR = new CAddonCallbacksPVR(addon->m_addon);
157 return addon->m_helperPVR->GetCallbacks();
158}
159
160void CAddonCallbacks::PVRLib_UnRegisterMe(void *addonData, CB_PVRLib *cbTable)
161{
162 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
163 if (addon == NULL)
164 {
165 CLog::Log(LOGERROR, "CAddonCallbacks - %s - called with a null pointer", __FUNCTION__);
166 return;
167 }
168
169 delete addon->m_helperPVR;
170 addon->m_helperPVR = NULL;
171}
172
173}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonCallbacks.h b/xbmc/addons/AddonCallbacks.h
new file mode 100644
index 0000000..f0902e4
--- /dev/null
+++ b/xbmc/addons/AddonCallbacks.h
@@ -0,0 +1,466 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <stdint.h>
23#include "cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h"
24#include "addons/include/xbmc_pvr_types.h"
25#include "addons/include/xbmc_codec_types.h"
26#include "../../addons/library.xbmc.gui/libXBMC_gui.h"
27
28#ifdef TARGET_WINDOWS
29#ifndef _SSIZE_T_DEFINED
30typedef intptr_t ssize_t;
31#define _SSIZE_T_DEFINED
32#endif // !_SSIZE_T_DEFINED
33#endif // TARGET_WINDOWS
34
35typedef void (*AddOnLogCallback)(void *addonData, const ADDON::addon_log_t loglevel, const char *msg);
36typedef void (*AddOnQueueNotification)(void *addonData, const ADDON::queue_msg_t type, const char *msg);
37typedef bool (*AddOnWakeOnLan)(const char* mac);
38typedef bool (*AddOnGetSetting)(void *addonData, const char *settingName, void *settingValue);
39typedef char* (*AddOnUnknownToUTF8)(const char *sourceDest);
40typedef char* (*AddOnGetLocalizedString)(const void* addonData, long dwCode);
41typedef char* (*AddOnGetDVDMenuLanguage)(const void* addonData);
42typedef void (*AddOnFreeString)(const void* addonData, char* str);
43
44typedef void* (*AddOnOpenFile)(const void* addonData, const char* strFileName, unsigned int flags);
45typedef void* (*AddOnOpenFileForWrite)(const void* addonData, const char* strFileName, bool bOverWrite);
46typedef ssize_t (*AddOnReadFile)(const void* addonData, void* file, void* lpBuf, size_t uiBufSize);
47typedef bool (*AddOnReadFileString)(const void* addonData, void* file, char *szLine, int iLineLength);
48typedef ssize_t (*AddOnWriteFile)(const void* addonData, void* file, const void* lpBuf, size_t uiBufSize);
49typedef void (*AddOnFlushFile)(const void* addonData, void* file);
50typedef int64_t (*AddOnSeekFile)(const void* addonData, void* file, int64_t iFilePosition, int iWhence);
51typedef int (*AddOnTruncateFile)(const void* addonData, void* file, int64_t iSize);
52typedef int64_t (*AddOnGetFilePosition)(const void* addonData, void* file);
53typedef int64_t (*AddOnGetFileLength)(const void* addonData, void* file);
54typedef void (*AddOnCloseFile)(const void* addonData, void* file);
55typedef int (*AddOnGetFileChunkSize)(const void* addonData, void* file);
56typedef bool (*AddOnFileExists)(const void* addonData, const char *strFileName, bool bUseCache);
57typedef int (*AddOnStatFile)(const void* addonData, const char *strFileName, struct __stat64* buffer);
58typedef bool (*AddOnDeleteFile)(const void* addonData, const char *strFileName);
59typedef bool (*AddOnCanOpenDirectory)(const void* addonData, const char* strURL);
60typedef bool (*AddOnCreateDirectory)(const void* addonData, const char *strPath);
61typedef bool (*AddOnDirectoryExists)(const void* addonData, const char *strPath);
62typedef bool (*AddOnRemoveDirectory)(const void* addonData, const char *strPath);
63
64typedef struct CB_AddOn
65{
66 AddOnLogCallback Log;
67 AddOnQueueNotification QueueNotification;
68 AddOnWakeOnLan WakeOnLan;
69 AddOnGetSetting GetSetting;
70 AddOnUnknownToUTF8 UnknownToUTF8;
71 AddOnGetLocalizedString GetLocalizedString;
72 AddOnGetDVDMenuLanguage GetDVDMenuLanguage;
73 AddOnFreeString FreeString;
74
75 AddOnOpenFile OpenFile;
76 AddOnOpenFileForWrite OpenFileForWrite;
77 AddOnReadFile ReadFile;
78 AddOnReadFileString ReadFileString;
79 AddOnWriteFile WriteFile;
80 AddOnFlushFile FlushFile;
81 AddOnSeekFile SeekFile;
82 AddOnTruncateFile TruncateFile;
83 AddOnGetFilePosition GetFilePosition;
84 AddOnGetFileLength GetFileLength;
85 AddOnCloseFile CloseFile;
86 AddOnGetFileChunkSize GetFileChunkSize;
87 AddOnFileExists FileExists;
88 AddOnStatFile StatFile;
89 AddOnDeleteFile DeleteFile;
90 AddOnCanOpenDirectory CanOpenDirectory;
91 AddOnCreateDirectory CreateDirectory;
92 AddOnDirectoryExists DirectoryExists;
93 AddOnRemoveDirectory RemoveDirectory;
94} CB_AddOnLib;
95
96typedef xbmc_codec_t (*CODECGetCodecByName)(const void* addonData, const char* strCodecName);
97
98typedef struct CB_CODEC
99{
100 CODECGetCodecByName GetCodecByName;
101} CB_CODECLib;
102
103typedef void (*GUILock)();
104typedef void (*GUIUnlock)();
105typedef int (*GUIGetScreenHeight)();
106typedef int (*GUIGetScreenWidth)();
107typedef int (*GUIGetVideoResolution)();
108typedef GUIHANDLE (*GUIWindow_New)(void *addonData, const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog);
109typedef void (*GUIWindow_Delete)(void *addonData, GUIHANDLE handle);
110typedef void (*GUIWindow_SetCallbacks)(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*)(GUIHANDLE handle), bool (*)(GUIHANDLE handle, int), bool (*)(GUIHANDLE handle, int), bool (*)(GUIHANDLE handle, int));
111typedef bool (*GUIWindow_Show)(void *addonData, GUIHANDLE handle);
112typedef bool (*GUIWindow_Close)(void *addonData, GUIHANDLE handle);
113typedef bool (*GUIWindow_DoModal)(void *addonData, GUIHANDLE handle);
114typedef bool (*GUIWindow_SetFocusId)(void *addonData, GUIHANDLE handle, int iControlId);
115typedef int (*GUIWindow_GetFocusId)(void *addonData, GUIHANDLE handle);
116typedef bool (*GUIWindow_SetCoordinateResolution)(void *addonData, GUIHANDLE handle, int res);
117typedef void (*GUIWindow_SetProperty)(void *addonData, GUIHANDLE handle, const char *key, const char *value);
118typedef void (*GUIWindow_SetPropertyInt)(void *addonData, GUIHANDLE handle, const char *key, int value);
119typedef void (*GUIWindow_SetPropertyBool)(void *addonData, GUIHANDLE handle, const char *key, bool value);
120typedef void (*GUIWindow_SetPropertyDouble)(void *addonData, GUIHANDLE handle, const char *key, double value);
121typedef const char* (*GUIWindow_GetProperty)(void *addonData, GUIHANDLE handle, const char *key);
122typedef int (*GUIWindow_GetPropertyInt)(void *addonData, GUIHANDLE handle, const char *key);
123typedef bool (*GUIWindow_GetPropertyBool)(void *addonData, GUIHANDLE handle, const char *key);
124typedef double (*GUIWindow_GetPropertyDouble)(void *addonData, GUIHANDLE handle, const char *key);
125typedef void (*GUIWindow_ClearProperties)(void *addonData, GUIHANDLE handle);
126typedef int (*GUIWindow_GetListSize)(void *addonData, GUIHANDLE handle);
127typedef void (*GUIWindow_ClearList)(void *addonData, GUIHANDLE handle);
128typedef GUIHANDLE (*GUIWindow_AddItem)(void *addonData, GUIHANDLE handle, GUIHANDLE item, int itemPosition);
129typedef GUIHANDLE (*GUIWindow_AddStringItem)(void *addonData, GUIHANDLE handle, const char *itemName, int itemPosition);
130typedef void (*GUIWindow_RemoveItem)(void *addonData, GUIHANDLE handle, int itemPosition);
131typedef GUIHANDLE (*GUIWindow_GetListItem)(void *addonData, GUIHANDLE handle, int listPos);
132typedef void (*GUIWindow_SetCurrentListPosition)(void *addonData, GUIHANDLE handle, int listPos);
133typedef int (*GUIWindow_GetCurrentListPosition)(void *addonData, GUIHANDLE handle);
134typedef GUIHANDLE (*GUIWindow_GetControl_Spin)(void *addonData, GUIHANDLE handle, int controlId);
135typedef GUIHANDLE (*GUIWindow_GetControl_Button)(void *addonData, GUIHANDLE handle, int controlId);
136typedef GUIHANDLE (*GUIWindow_GetControl_RadioButton)(void *addonData, GUIHANDLE handle, int controlId);
137typedef GUIHANDLE (*GUIWindow_GetControl_Edit)(void *addonData, GUIHANDLE handle, int controlId);
138typedef GUIHANDLE (*GUIWindow_GetControl_Progress)(void *addonData, GUIHANDLE handle, int controlId);
139typedef GUIHANDLE (*GUIWindow_GetControl_RenderAddon)(void *addonData, GUIHANDLE handle, int controlId);
140typedef void (*GUIWindow_SetControlLabel)(void *addonData, GUIHANDLE handle, int controlId, const char *label);
141typedef void (*GUIWindow_MarkDirtyRegion)(void *addonData, GUIHANDLE handle);
142typedef void (*GUIControl_Spin_SetVisible)(void *addonData, GUIHANDLE spinhandle, bool yesNo);
143typedef void (*GUIControl_Spin_SetText)(void *addonData, GUIHANDLE spinhandle, const char *label);
144typedef void (*GUIControl_Spin_Clear)(void *addonData, GUIHANDLE spinhandle);
145typedef void (*GUIControl_Spin_AddLabel)(void *addonData, GUIHANDLE spinhandle, const char *label, int iValue);
146typedef int (*GUIControl_Spin_GetValue)(void *addonData, GUIHANDLE spinhandle);
147typedef void (*GUIControl_Spin_SetValue)(void *addonData, GUIHANDLE spinhandle, int iValue);
148typedef void (*GUIControl_RadioButton_SetVisible)(void *addonData, GUIHANDLE handle, bool yesNo);
149typedef void (*GUIControl_RadioButton_SetText)(void *addonData, GUIHANDLE handle, const char *label);
150typedef void (*GUIControl_RadioButton_SetSelected)(void *addonData, GUIHANDLE handle, bool yesNo);
151typedef bool (*GUIControl_RadioButton_IsSelected)(void *addonData, GUIHANDLE handle);
152typedef void (*GUIControl_Progress_SetPercentage)(void *addonData, GUIHANDLE handle, float fPercent);
153typedef float (*GUIControl_Progress_GetPercentage)(void *addonData, GUIHANDLE handle);
154typedef void (*GUIControl_Progress_SetInfo)(void *addonData, GUIHANDLE handle, int iInfo);
155typedef int (*GUIControl_Progress_GetInfo)(void *addonData, GUIHANDLE handle);
156typedef const char* (*GUIControl_Progress_GetDescription)(void *addonData, GUIHANDLE handle);
157typedef GUIHANDLE (*GUIWindow_GetControl_Slider)(void *addonData, GUIHANDLE handle, int controlId);
158typedef void (*GUIControl_Slider_SetVisible)(void *addonData, GUIHANDLE handle, bool yesNo);
159typedef const char *(*GUIControl_Slider_GetDescription)(void *addonData, GUIHANDLE handle);
160typedef void (*GUIControl_Slider_SetIntRange)(void *addonData, GUIHANDLE handle, int iStart, int iEnd);
161typedef void (*GUIControl_Slider_SetIntValue)(void *addonData, GUIHANDLE handle, int iValue);
162typedef int (*GUIControl_Slider_GetIntValue)(void *addonData, GUIHANDLE handle);
163typedef void (*GUIControl_Slider_SetIntInterval)(void *addonData, GUIHANDLE handle, int iInterval);
164typedef void (*GUIControl_Slider_SetPercentage)(void *addonData, GUIHANDLE handle, float fPercent);
165typedef float (*GUIControl_Slider_GetPercentage)(void *addonData, GUIHANDLE handle);
166typedef void (*GUIControl_Slider_SetFloatRange)(void *addonData, GUIHANDLE handle, float fStart, float fEnd);
167typedef void (*GUIControl_Slider_SetFloatValue)(void *addonData, GUIHANDLE handle, float fValue);
168typedef float (*GUIControl_Slider_GetFloatValue)(void *addonData, GUIHANDLE handle);
169typedef void (*GUIControl_Slider_SetFloatInterval)(void *addonData, GUIHANDLE handle, float fInterval);
170typedef GUIHANDLE (*GUIWindow_GetControl_SettingsSlider)(void *addonData, GUIHANDLE handle, int controlId);
171typedef void (*GUIControl_SettingsSlider_SetVisible)(void *addonData, GUIHANDLE handle, bool yesNo);
172typedef void (*GUIControl_SettingsSlider_SetText)(void *addonData, GUIHANDLE handle, const char *label);
173typedef const char *(*GUIControl_SettingsSlider_GetDescription)(void *addonData, GUIHANDLE handle);
174typedef void (*GUIControl_SettingsSlider_SetIntRange)(void *addonData, GUIHANDLE handle, int iStart, int iEnd);
175typedef void (*GUIControl_SettingsSlider_SetIntValue)(void *addonData, GUIHANDLE handle, int iValue);
176typedef int (*GUIControl_SettingsSlider_GetIntValue)(void *addonData, GUIHANDLE handle);
177typedef void (*GUIControl_SettingsSlider_SetIntInterval)(void *addonData, GUIHANDLE handle, int iInterval);
178typedef void (*GUIControl_SettingsSlider_SetPercentage)(void *addonData, GUIHANDLE handle, float fPercent);
179typedef float (*GUIControl_SettingsSlider_GetPercentage)(void *addonData, GUIHANDLE handle);
180typedef void (*GUIControl_SettingsSlider_SetFloatRange)(void *addonData, GUIHANDLE handle, float fStart, float fEnd);
181typedef void (*GUIControl_SettingsSlider_SetFloatValue)(void *addonData, GUIHANDLE handle, float fValue);
182typedef float (*GUIControl_SettingsSlider_GetFloatValue)(void *addonData, GUIHANDLE handle);
183typedef void (*GUIControl_SettingsSlider_SetFloatInterval)(void *addonData, GUIHANDLE handle, float fInterval);
184typedef GUIHANDLE (*GUIListItem_Create)(void *addonData, const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path);
185typedef const char* (*GUIListItem_GetLabel)(void *addonData, GUIHANDLE handle);
186typedef void (*GUIListItem_SetLabel)(void *addonData, GUIHANDLE handle, const char *label);
187typedef const char* (*GUIListItem_GetLabel2)(void *addonData, GUIHANDLE handle);
188typedef void (*GUIListItem_SetLabel2)(void *addonData, GUIHANDLE handle, const char *label);
189typedef void (*GUIListItem_SetIconImage)(void *addonData, GUIHANDLE handle, const char *image);
190typedef void (*GUIListItem_SetThumbnailImage)(void *addonData, GUIHANDLE handle, const char *image);
191typedef void (*GUIListItem_SetInfo)(void *addonData, GUIHANDLE handle, const char *info);
192typedef void (*GUIListItem_SetProperty)(void *addonData, GUIHANDLE handle, const char *key, const char *value);
193typedef const char* (*GUIListItem_GetProperty)(void *addonData, GUIHANDLE handle, const char *key);
194typedef void (*GUIListItem_SetPath)(void *addonData, GUIHANDLE handle, const char *path);
195typedef void (*GUIRenderAddon_SetCallbacks)(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,void*), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE));
196typedef void (*GUIRenderAddon_Delete)(void *addonData, GUIHANDLE handle);
197typedef void (*GUIRenderAddon_MarkDirty)(void *addonData, GUIHANDLE handle);
198
199typedef bool (*GUIDialog_Keyboard_ShowAndGetInputWithHead)(char &strTextString, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, bool hiddenInput, unsigned int autoCloseMs);
200typedef bool (*GUIDialog_Keyboard_ShowAndGetInput)(char &strTextString, unsigned int iMaxStringSize, bool allowEmptyResult, unsigned int autoCloseMs);
201typedef bool (*GUIDialog_Keyboard_ShowAndGetNewPasswordWithHead)(char &newPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, unsigned int autoCloseMs);
202typedef bool (*GUIDialog_Keyboard_ShowAndGetNewPassword)(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs);
203typedef bool (*GUIDialog_Keyboard_ShowAndVerifyNewPasswordWithHead)(char &strNewPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmpty, unsigned int autoCloseMs);
204typedef bool (*GUIDialog_Keyboard_ShowAndVerifyNewPassword)(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs);
205typedef int (*GUIDialog_Keyboard_ShowAndVerifyPassword)(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries, unsigned int autoCloseMs);
206typedef bool (*GUIDialog_Keyboard_ShowAndGetFilter)(char &aTextString, unsigned int iMaxStringSize, bool searching, unsigned int autoCloseMs);
207typedef bool (*GUIDialog_Keyboard_SendTextToActiveKeyboard)(const char *aTextString, bool closeKeyboard);
208typedef bool (*GUIDialog_Keyboard_isKeyboardActivated)();
209
210typedef bool (*GUIDialog_Numeric_ShowAndVerifyNewPassword)(char &strNewPassword, unsigned int iMaxStringSize);
211typedef int (*GUIDialog_Numeric_ShowAndVerifyPassword)(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries);
212typedef bool (*GUIDialog_Numeric_ShowAndVerifyInput)(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, bool bGetUserInput);
213typedef bool (*GUIDialog_Numeric_ShowAndGetTime)(tm &time, const char *strHeading);
214typedef bool (*GUIDialog_Numeric_ShowAndGetDate)(tm &date, const char *strHeading);
215typedef bool (*GUIDialog_Numeric_ShowAndGetIPAddress)(char &strIPAddress, unsigned int iMaxStringSize, const char *strHeading);
216typedef bool (*GUIDialog_Numeric_ShowAndGetNumber)(char &strInput, unsigned int iMaxStringSize, const char *strHeading, unsigned int iAutoCloseTimeoutMs);
217typedef bool (*GUIDialog_Numeric_ShowAndGetSeconds)(char &timeString, unsigned int iMaxStringSize, const char *strHeading);
218
219typedef bool (*GUIDialog_FileBrowser_ShowAndGetFile)(const char *directory, const char *mask, const char *heading, char &path, unsigned int iMaxStringSize, bool useThumbs, bool useFileDirectories, bool singleList);
220
221typedef void (*GUIDialog_OK_ShowAndGetInputSingleText)(const char *heading, const char *text);
222typedef void (*GUIDialog_OK_ShowAndGetInputLineText)(const char *heading, const char *line0, const char *line1, const char *line2);
223
224typedef bool (*GUIDialog_YesNo_ShowAndGetInputSingleText)(const char *heading, const char *text, bool& bCanceled, const char *noLabel, const char *yesLabel);
225typedef bool (*GUIDialog_YesNo_ShowAndGetInputLineText)(const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel, const char *yesLabel);
226typedef bool (*GUIDialog_YesNo_ShowAndGetInputLineButtonText)(const char *heading, const char *line0, const char *line1, const char *line2, bool &bCanceled, const char *noLabel, const char *yesLabel);
227
228typedef void (*GUIDialog_TextViewer)(const char *heading, const char *text);
229
230typedef int (*GUIDialog_Select)(const char *heading, const char *entries[], unsigned int size, int selected);
231
232typedef struct CB_GUILib
233{
234 GUILock Lock;
235 GUIUnlock Unlock;
236 GUIGetScreenHeight GetScreenHeight;
237 GUIGetScreenWidth GetScreenWidth;
238 GUIGetVideoResolution GetVideoResolution;
239 GUIWindow_New Window_New;
240 GUIWindow_Delete Window_Delete;
241 GUIWindow_SetCallbacks Window_SetCallbacks;
242 GUIWindow_Show Window_Show;
243 GUIWindow_Close Window_Close;
244 GUIWindow_DoModal Window_DoModal;
245 GUIWindow_SetFocusId Window_SetFocusId;
246 GUIWindow_GetFocusId Window_GetFocusId;
247 GUIWindow_SetCoordinateResolution Window_SetCoordinateResolution;
248 GUIWindow_SetProperty Window_SetProperty;
249 GUIWindow_SetPropertyInt Window_SetPropertyInt;
250 GUIWindow_SetPropertyBool Window_SetPropertyBool;
251 GUIWindow_SetPropertyDouble Window_SetPropertyDouble;
252 GUIWindow_GetProperty Window_GetProperty;
253 GUIWindow_GetPropertyInt Window_GetPropertyInt;
254 GUIWindow_GetPropertyBool Window_GetPropertyBool;
255 GUIWindow_GetPropertyDouble Window_GetPropertyDouble;
256 GUIWindow_ClearProperties Window_ClearProperties;
257 GUIWindow_GetListSize Window_GetListSize;
258 GUIWindow_ClearList Window_ClearList;
259 GUIWindow_AddItem Window_AddItem;
260 GUIWindow_AddStringItem Window_AddStringItem;
261 GUIWindow_RemoveItem Window_RemoveItem;
262 GUIWindow_GetListItem Window_GetListItem;
263 GUIWindow_SetCurrentListPosition Window_SetCurrentListPosition;
264 GUIWindow_GetCurrentListPosition Window_GetCurrentListPosition;
265 GUIWindow_GetControl_Spin Window_GetControl_Spin;
266 GUIWindow_GetControl_Button Window_GetControl_Button;
267 GUIWindow_GetControl_RadioButton Window_GetControl_RadioButton;
268 GUIWindow_GetControl_Edit Window_GetControl_Edit;
269 GUIWindow_GetControl_Progress Window_GetControl_Progress;
270 GUIWindow_GetControl_RenderAddon Window_GetControl_RenderAddon;
271 GUIWindow_SetControlLabel Window_SetControlLabel;
272 GUIWindow_MarkDirtyRegion Window_MarkDirtyRegion;
273 GUIControl_Spin_SetVisible Control_Spin_SetVisible;
274 GUIControl_Spin_SetText Control_Spin_SetText;
275 GUIControl_Spin_Clear Control_Spin_Clear;
276 GUIControl_Spin_AddLabel Control_Spin_AddLabel;
277 GUIControl_Spin_GetValue Control_Spin_GetValue;
278 GUIControl_Spin_SetValue Control_Spin_SetValue;
279 GUIControl_RadioButton_SetVisible Control_RadioButton_SetVisible;
280 GUIControl_RadioButton_SetText Control_RadioButton_SetText;
281 GUIControl_RadioButton_SetSelected Control_RadioButton_SetSelected;
282 GUIControl_RadioButton_IsSelected Control_RadioButton_IsSelected;
283 GUIControl_Progress_SetPercentage Control_Progress_SetPercentage;
284 GUIControl_Progress_GetPercentage Control_Progress_GetPercentage;
285 GUIControl_Progress_SetInfo Control_Progress_SetInfo;
286 GUIControl_Progress_GetInfo Control_Progress_GetInfo;
287 GUIControl_Progress_GetDescription Control_Progress_GetDescription;
288 GUIListItem_Create ListItem_Create;
289 GUIListItem_GetLabel ListItem_GetLabel;
290 GUIListItem_SetLabel ListItem_SetLabel;
291 GUIListItem_GetLabel2 ListItem_GetLabel2;
292 GUIListItem_SetLabel2 ListItem_SetLabel2;
293 GUIListItem_SetIconImage ListItem_SetIconImage;
294 GUIListItem_SetThumbnailImage ListItem_SetThumbnailImage;
295 GUIListItem_SetInfo ListItem_SetInfo;
296 GUIListItem_SetProperty ListItem_SetProperty;
297 GUIListItem_GetProperty ListItem_GetProperty;
298 GUIListItem_SetPath ListItem_SetPath;
299 GUIRenderAddon_SetCallbacks RenderAddon_SetCallbacks;
300 GUIRenderAddon_Delete RenderAddon_Delete;
301
302 GUIWindow_GetControl_Slider Window_GetControl_Slider;
303 GUIControl_Slider_SetVisible Control_Slider_SetVisible;
304 GUIControl_Slider_GetDescription Control_Slider_GetDescription;
305 GUIControl_Slider_SetIntRange Control_Slider_SetIntRange;
306 GUIControl_Slider_SetIntValue Control_Slider_SetIntValue;
307 GUIControl_Slider_GetIntValue Control_Slider_GetIntValue;
308 GUIControl_Slider_SetIntInterval Control_Slider_SetIntInterval;
309 GUIControl_Slider_SetPercentage Control_Slider_SetPercentage;
310 GUIControl_Slider_GetPercentage Control_Slider_GetPercentage;
311 GUIControl_Slider_SetFloatRange Control_Slider_SetFloatRange;
312 GUIControl_Slider_SetFloatValue Control_Slider_SetFloatValue;
313 GUIControl_Slider_GetFloatValue Control_Slider_GetFloatValue;
314 GUIControl_Slider_SetFloatInterval Control_Slider_SetFloatInterval;
315
316 GUIWindow_GetControl_SettingsSlider Window_GetControl_SettingsSlider;
317 GUIControl_SettingsSlider_SetVisible Control_SettingsSlider_SetVisible;
318 GUIControl_SettingsSlider_SetText Control_SettingsSlider_SetText;
319 GUIControl_SettingsSlider_GetDescription Control_SettingsSlider_GetDescription;
320 GUIControl_SettingsSlider_SetIntRange Control_SettingsSlider_SetIntRange;
321 GUIControl_SettingsSlider_SetIntValue Control_SettingsSlider_SetIntValue;
322 GUIControl_SettingsSlider_GetIntValue Control_SettingsSlider_GetIntValue;
323 GUIControl_SettingsSlider_SetIntInterval Control_SettingsSlider_SetIntInterval;
324 GUIControl_SettingsSlider_SetPercentage Control_SettingsSlider_SetPercentage;
325 GUIControl_SettingsSlider_GetPercentage Control_SettingsSlider_GetPercentage;
326 GUIControl_SettingsSlider_SetFloatRange Control_SettingsSlider_SetFloatRange;
327 GUIControl_SettingsSlider_SetFloatValue Control_SettingsSlider_SetFloatValue;
328 GUIControl_SettingsSlider_GetFloatValue Control_SettingsSlider_GetFloatValue;
329 GUIControl_SettingsSlider_SetFloatInterval Control_SettingsSlider_SetFloatInterval;
330
331 GUIDialog_Keyboard_ShowAndGetInputWithHead Dialog_Keyboard_ShowAndGetInputWithHead;
332 GUIDialog_Keyboard_ShowAndGetInput Dialog_Keyboard_ShowAndGetInput;
333 GUIDialog_Keyboard_ShowAndGetNewPasswordWithHead Dialog_Keyboard_ShowAndGetNewPasswordWithHead;
334 GUIDialog_Keyboard_ShowAndGetNewPassword Dialog_Keyboard_ShowAndGetNewPassword;
335 GUIDialog_Keyboard_ShowAndVerifyNewPasswordWithHead Dialog_Keyboard_ShowAndVerifyNewPasswordWithHead;
336 GUIDialog_Keyboard_ShowAndVerifyNewPassword Dialog_Keyboard_ShowAndVerifyNewPassword;
337 GUIDialog_Keyboard_ShowAndVerifyPassword Dialog_Keyboard_ShowAndVerifyPassword;
338 GUIDialog_Keyboard_ShowAndGetFilter Dialog_Keyboard_ShowAndGetFilter;
339 GUIDialog_Keyboard_SendTextToActiveKeyboard Dialog_Keyboard_SendTextToActiveKeyboard;
340 GUIDialog_Keyboard_isKeyboardActivated Dialog_Keyboard_isKeyboardActivated;
341
342 GUIDialog_Numeric_ShowAndVerifyNewPassword Dialog_Numeric_ShowAndVerifyNewPassword;
343 GUIDialog_Numeric_ShowAndVerifyPassword Dialog_Numeric_ShowAndVerifyPassword;
344 GUIDialog_Numeric_ShowAndVerifyInput Dialog_Numeric_ShowAndVerifyInput;
345 GUIDialog_Numeric_ShowAndGetTime Dialog_Numeric_ShowAndGetTime;
346 GUIDialog_Numeric_ShowAndGetDate Dialog_Numeric_ShowAndGetDate;
347 GUIDialog_Numeric_ShowAndGetIPAddress Dialog_Numeric_ShowAndGetIPAddress;
348 GUIDialog_Numeric_ShowAndGetNumber Dialog_Numeric_ShowAndGetNumber;
349 GUIDialog_Numeric_ShowAndGetSeconds Dialog_Numeric_ShowAndGetSeconds;
350
351 GUIDialog_FileBrowser_ShowAndGetFile Dialog_FileBrowser_ShowAndGetFile;
352
353 GUIDialog_OK_ShowAndGetInputSingleText Dialog_OK_ShowAndGetInputSingleText;
354 GUIDialog_OK_ShowAndGetInputLineText Dialog_OK_ShowAndGetInputLineText;
355
356 GUIDialog_YesNo_ShowAndGetInputSingleText Dialog_YesNo_ShowAndGetInputSingleText;
357 GUIDialog_YesNo_ShowAndGetInputLineText Dialog_YesNo_ShowAndGetInputLineText;
358 GUIDialog_YesNo_ShowAndGetInputLineButtonText Dialog_YesNo_ShowAndGetInputLineButtonText;
359
360 GUIDialog_TextViewer Dialog_TextViewer;
361 GUIDialog_Select Dialog_Select;
362} CB_GUILib;
363
364typedef void (*PVRTransferEpgEntry)(void *userData, const ADDON_HANDLE handle, const EPG_TAG *epgentry);
365typedef void (*PVRTransferChannelEntry)(void *userData, const ADDON_HANDLE handle, const PVR_CHANNEL *chan);
366typedef void (*PVRTransferTimerEntry)(void *userData, const ADDON_HANDLE handle, const PVR_TIMER *timer);
367typedef void (*PVRTransferRecordingEntry)(void *userData, const ADDON_HANDLE handle, const PVR_RECORDING *recording);
368typedef void (*PVRAddMenuHook)(void *addonData, PVR_MENUHOOK *hook);
369typedef void (*PVRRecording)(void *addonData, const char *Name, const char *FileName, bool On);
370typedef void (*PVRTriggerChannelUpdate)(void *addonData);
371typedef void (*PVRTriggerTimerUpdate)(void *addonData);
372typedef void (*PVRTriggerRecordingUpdate)(void *addonData);
373typedef void (*PVRTriggerChannelGroupsUpdate)(void *addonData);
374typedef void (*PVRTriggerEpgUpdate)(void *addonData, unsigned int iChannelUid);
375
376typedef void (*PVRTransferChannelGroup)(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group);
377typedef void (*PVRTransferChannelGroupMember)(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member);
378
379typedef void (*PVRFreeDemuxPacket)(void *addonData, DemuxPacket* pPacket);
380typedef DemuxPacket* (*PVRAllocateDemuxPacket)(void *addonData, int iDataSize);
381
382typedef struct CB_PVRLib
383{
384 PVRTransferEpgEntry TransferEpgEntry;
385 PVRTransferChannelEntry TransferChannelEntry;
386 PVRTransferTimerEntry TransferTimerEntry;
387 PVRTransferRecordingEntry TransferRecordingEntry;
388 PVRAddMenuHook AddMenuHook;
389 PVRRecording Recording;
390 PVRTriggerChannelUpdate TriggerChannelUpdate;
391 PVRTriggerTimerUpdate TriggerTimerUpdate;
392 PVRTriggerRecordingUpdate TriggerRecordingUpdate;
393 PVRTriggerChannelGroupsUpdate TriggerChannelGroupsUpdate;
394 PVRTriggerEpgUpdate TriggerEpgUpdate;
395 PVRFreeDemuxPacket FreeDemuxPacket;
396 PVRAllocateDemuxPacket AllocateDemuxPacket;
397 PVRTransferChannelGroup TransferChannelGroup;
398 PVRTransferChannelGroupMember TransferChannelGroupMember;
399
400} CB_PVRLib;
401
402
403typedef CB_AddOnLib* (*XBMCAddOnLib_RegisterMe)(void *addonData);
404typedef void (*XBMCAddOnLib_UnRegisterMe)(void *addonData, CB_AddOnLib *cbTable);
405typedef CB_CODECLib* (*XBMCCODECLib_RegisterMe)(void *addonData);
406typedef void (*XBMCCODECLib_UnRegisterMe)(void *addonData, CB_CODECLib *cbTable);
407typedef CB_GUILib* (*XBMCGUILib_RegisterMe)(void *addonData);
408typedef void (*XBMCGUILib_UnRegisterMe)(void *addonData, CB_GUILib *cbTable);
409typedef CB_PVRLib* (*XBMCPVRLib_RegisterMe)(void *addonData);
410typedef void (*XBMCPVRLib_UnRegisterMe)(void *addonData, CB_PVRLib *cbTable);
411
412typedef struct AddonCB
413{
414 const char *libBasePath; ///> Never, never change this!!!
415 void *addonData;
416 XBMCAddOnLib_RegisterMe AddOnLib_RegisterMe;
417 XBMCAddOnLib_UnRegisterMe AddOnLib_UnRegisterMe;
418 XBMCCODECLib_RegisterMe CODECLib_RegisterMe;
419 XBMCCODECLib_UnRegisterMe CODECLib_UnRegisterMe;
420 XBMCGUILib_RegisterMe GUILib_RegisterMe;
421 XBMCGUILib_UnRegisterMe GUILib_UnRegisterMe;
422 XBMCPVRLib_RegisterMe PVRLib_RegisterMe;
423 XBMCPVRLib_UnRegisterMe PVRLib_UnRegisterMe;
424} AddonCB;
425
426
427namespace ADDON
428{
429
430class CAddon;
431class CAddonCallbacksAddon;
432class CAddonCallbacksCodec;
433class CAddonCallbacksGUI;
434class CAddonCallbacksPVR;
435
436class CAddonCallbacks
437{
438public:
439 CAddonCallbacks(CAddon* addon);
440 ~CAddonCallbacks();
441 AddonCB *GetCallbacks() { return m_callbacks; }
442
443 static CB_AddOnLib* AddOnLib_RegisterMe(void *addonData);
444 static void AddOnLib_UnRegisterMe(void *addonData, CB_AddOnLib *cbTable);
445 static CB_CODECLib* CODECLib_RegisterMe(void *addonData);
446 static void CODECLib_UnRegisterMe(void *addonData, CB_CODECLib *cbTable);
447 static CB_GUILib* GUILib_RegisterMe(void *addonData);
448 static void GUILib_UnRegisterMe(void *addonData, CB_GUILib *cbTable);
449 static CB_PVRLib* PVRLib_RegisterMe(void *addonData);
450 static void PVRLib_UnRegisterMe(void *addonData, CB_PVRLib *cbTable);
451
452 CAddonCallbacksAddon *GetHelperAddon() { return m_helperAddon; }
453 CAddonCallbacksCodec *GetHelperCodec() { return m_helperCODEC; }
454 CAddonCallbacksGUI *GetHelperGUI() { return m_helperGUI; }
455 CAddonCallbacksPVR *GetHelperPVR() { return m_helperPVR; }
456
457private:
458 AddonCB *m_callbacks;
459 CAddon *m_addon;
460 CAddonCallbacksAddon *m_helperAddon;
461 CAddonCallbacksCodec *m_helperCODEC;
462 CAddonCallbacksGUI *m_helperGUI;
463 CAddonCallbacksPVR *m_helperPVR;
464};
465
466}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonCallbacksAddon.cpp b/xbmc/addons/AddonCallbacksAddon.cpp
new file mode 100644
index 0000000..e54aebe
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksAddon.cpp
@@ -0,0 +1,532 @@
1/*
2 * Copyright (C) 2012-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Application.h"
22#include "Addon.h"
23#include "AddonCallbacksAddon.h"
24#include "utils/log.h"
25#include "LangInfo.h"
26#include "dialogs/GUIDialogKaiToast.h"
27#include "filesystem/File.h"
28#include "filesystem/Directory.h"
29#include "utils/URIUtils.h"
30#include "FileItem.h"
31#include "network/Network.h"
32#include "utils/CharsetConverter.h"
33#include "utils/StringUtils.h"
34#include "utils/XMLUtils.h"
35#include "cores/dvdplayer/DVDCodecs/DVDCodecs.h"
36
37using namespace XFILE;
38
39namespace ADDON
40{
41
42CAddonCallbacksAddon::CAddonCallbacksAddon(CAddon* addon)
43{
44 m_addon = addon;
45 m_callbacks = new CB_AddOnLib;
46
47 /* write XBMC addon-on specific add-on function addresses to the callback table */
48 m_callbacks->Log = AddOnLog;
49 m_callbacks->QueueNotification = QueueNotification;
50 m_callbacks->WakeOnLan = WakeOnLan;
51 m_callbacks->GetSetting = GetAddonSetting;
52 m_callbacks->UnknownToUTF8 = UnknownToUTF8;
53 m_callbacks->GetLocalizedString = GetLocalizedString;
54 m_callbacks->GetDVDMenuLanguage = GetDVDMenuLanguage;
55 m_callbacks->FreeString = FreeString;
56
57 m_callbacks->OpenFile = OpenFile;
58 m_callbacks->OpenFileForWrite = OpenFileForWrite;
59 m_callbacks->ReadFile = ReadFile;
60 m_callbacks->ReadFileString = ReadFileString;
61 m_callbacks->WriteFile = WriteFile;
62 m_callbacks->FlushFile = FlushFile;
63 m_callbacks->SeekFile = SeekFile;
64 m_callbacks->TruncateFile = TruncateFile;
65 m_callbacks->GetFilePosition = GetFilePosition;
66 m_callbacks->GetFileLength = GetFileLength;
67 m_callbacks->CloseFile = CloseFile;
68 m_callbacks->GetFileChunkSize = GetFileChunkSize;
69 m_callbacks->FileExists = FileExists;
70 m_callbacks->StatFile = StatFile;
71 m_callbacks->DeleteFile = DeleteFile;
72
73 m_callbacks->CanOpenDirectory = CanOpenDirectory;
74 m_callbacks->CreateDirectory = CreateDirectory;
75 m_callbacks->DirectoryExists = DirectoryExists;
76 m_callbacks->RemoveDirectory = RemoveDirectory;
77}
78
79CAddonCallbacksAddon::~CAddonCallbacksAddon()
80{
81 /* delete the callback table */
82 delete m_callbacks;
83}
84
85void CAddonCallbacksAddon::AddOnLog(void *addonData, const addon_log_t addonLogLevel, const char *strMessage)
86{
87 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
88 if (addon == NULL || strMessage == NULL)
89 {
90 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - called with a null pointer", __FUNCTION__);
91 return;
92 }
93
94 CAddonCallbacksAddon* addonHelper = addon->GetHelperAddon();
95
96 try
97 {
98 int xbmcLogLevel = LOGNONE;
99 switch (addonLogLevel)
100 {
101 case LOG_ERROR:
102 xbmcLogLevel = LOGERROR;
103 break;
104 case LOG_INFO:
105 xbmcLogLevel = LOGINFO;
106 break;
107 case LOG_NOTICE:
108 xbmcLogLevel = LOGNOTICE;
109 break;
110 case LOG_DEBUG:
111 default:
112 xbmcLogLevel = LOGDEBUG;
113 break;
114 }
115
116 std::string strXbmcMessage = StringUtils::Format("AddOnLog: %s: %s", addonHelper->m_addon->Name().c_str(), strMessage);
117 CLog::Log(xbmcLogLevel, "%s", strXbmcMessage.c_str());
118 }
119 catch (std::exception &e)
120 {
121 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - exception '%s' caught in call in add-on '%s'. please contact the developer of this addon: %s",
122 __FUNCTION__, e.what(), addonHelper->m_addon->Name().c_str(), addonHelper->m_addon->Author().c_str());
123 }
124}
125
126void CAddonCallbacksAddon::QueueNotification(void *addonData, const queue_msg_t type, const char *strMessage)
127{
128 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
129 if (addon == NULL || strMessage == NULL)
130 {
131 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - called with a null pointer", __FUNCTION__);
132 return;
133 }
134
135 CAddonCallbacksAddon* addonHelper = addon->GetHelperAddon();
136
137 try
138 {
139 switch (type)
140 {
141 case QUEUE_WARNING:
142 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, addonHelper->m_addon->Name(), strMessage, 3000, true);
143 CLog::Log(LOGDEBUG, "CAddonCallbacksAddon - %s - %s - Warning Message: '%s'", __FUNCTION__, addonHelper->m_addon->Name().c_str(), strMessage);
144 break;
145
146 case QUEUE_ERROR:
147 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, addonHelper->m_addon->Name(), strMessage, 3000, true);
148 CLog::Log(LOGDEBUG, "CAddonCallbacksAddon - %s - %s - Error Message : '%s'", __FUNCTION__, addonHelper->m_addon->Name().c_str(), strMessage);
149 break;
150
151 case QUEUE_INFO:
152 default:
153 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, addonHelper->m_addon->Name(), strMessage, 3000, false);
154 CLog::Log(LOGDEBUG, "CAddonCallbacksAddon - %s - %s - Info Message : '%s'", __FUNCTION__, addonHelper->m_addon->Name().c_str(), strMessage);
155 break;
156 }
157 }
158 catch (std::exception &e)
159 {
160 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - exception '%s' caught in call in add-on '%s'. please contact the developer of this addon: %s",
161 __FUNCTION__, e.what(), addonHelper->m_addon->Name().c_str(), addonHelper->m_addon->Author().c_str());
162 }
163}
164
165bool CAddonCallbacksAddon::WakeOnLan(const char *mac)
166{
167 return g_application.getNetwork().WakeOnLan(mac);
168}
169
170bool CAddonCallbacksAddon::GetAddonSetting(void *addonData, const char *strSettingName, void *settingValue)
171{
172 CAddonCallbacks* addon = (CAddonCallbacks*) addonData;
173 if (addon == NULL || strSettingName == NULL || settingValue == NULL)
174 {
175 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - called with a null pointer", __FUNCTION__);
176 return false;
177 }
178
179 CAddonCallbacksAddon* addonHelper = addon->GetHelperAddon();
180
181 try
182 {
183 CLog::Log(LOGDEBUG, "CAddonCallbacksAddon - %s - add-on '%s' requests setting '%s'", __FUNCTION__, addonHelper->m_addon->Name().c_str(), strSettingName);
184
185 if (!addonHelper->m_addon->ReloadSettings())
186 {
187 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - could't get settings for add-on '%s'", __FUNCTION__, addonHelper->m_addon->Name().c_str());
188 return false;
189 }
190
191 const TiXmlElement *category = addonHelper->m_addon->GetSettingsXML()->FirstChildElement("category");
192 if (!category) // add a default one...
193 category = addonHelper->m_addon->GetSettingsXML();
194
195 while (category)
196 {
197 const TiXmlElement *setting = category->FirstChildElement("setting");
198 while (setting)
199 {
200 const std::string id = XMLUtils::GetAttribute(setting, "id");
201 const std::string type = XMLUtils::GetAttribute(setting, "type");
202
203 if (id == strSettingName && !type.empty())
204 {
205 if (type == "text" || type == "ipaddress" ||
206 type == "folder" || type == "action" ||
207 type == "music" || type == "pictures" ||
208 type == "programs" || type == "fileenum" ||
209 type == "file")
210 {
211 strcpy((char*) settingValue, addonHelper->m_addon->GetSetting(id).c_str());
212 return true;
213 }
214 else if (type == "number" || type == "enum" ||
215 type == "labelenum")
216 {
217 *(int*) settingValue = (int) atoi(addonHelper->m_addon->GetSetting(id).c_str());
218 return true;
219 }
220 else if (type == "bool")
221 {
222 *(bool*) settingValue = (bool) (addonHelper->m_addon->GetSetting(id) == "true" ? true : false);
223 return true;
224 }
225 else if (type == "slider")
226 {
227 const char *option = setting->Attribute("option");
228 if (option && strcmpi(option, "int") == 0)
229 {
230 *(int*) settingValue = (int) atoi(addonHelper->m_addon->GetSetting(id).c_str());
231 return true;
232 }
233 else
234 {
235 *(float*) settingValue = (float) atof(addonHelper->m_addon->GetSetting(id).c_str());
236 return true;
237 }
238 }
239 }
240 setting = setting->NextSiblingElement("setting");
241 }
242 category = category->NextSiblingElement("category");
243 }
244 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - can't find setting '%s' in '%s'", __FUNCTION__, strSettingName, addonHelper->m_addon->Name().c_str());
245 }
246 catch (std::exception &e)
247 {
248 CLog::Log(LOGERROR, "CAddonCallbacksAddon - %s - exception '%s' caught in call in add-on '%s'. please contact the developer of this addon: %s",
249 __FUNCTION__, e.what(), addonHelper->m_addon->Name().c_str(), addonHelper->m_addon->Author().c_str());
250 }
251
252 return false;
253}
254
255char* CAddonCallbacksAddon::UnknownToUTF8(const char *strSource)
256{
257 std::string string;
258 if (strSource != NULL)
259 g_charsetConverter.unknownToUTF8(strSource, string);
260 else
261 string = "";
262 char* buffer = strdup(string.c_str());
263 return buffer;
264}
265
266char* CAddonCallbacksAddon::GetLocalizedString(const void* addonData, long dwCode)
267{
268 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
269 if (!helper || g_application.m_bStop)
270 return NULL;
271
272 CAddonCallbacksAddon* addonHelper = helper->GetHelperAddon();
273
274 std::string string;
275 if (dwCode >= 30000 && dwCode <= 30999)
276 string = addonHelper->m_addon->GetString(dwCode).c_str();
277 else if (dwCode >= 32000 && dwCode <= 32999)
278 string = addonHelper->m_addon->GetString(dwCode).c_str();
279 else
280 string = g_localizeStrings.Get(dwCode).c_str();
281
282 char* buffer = strdup(string.c_str());
283 return buffer;
284}
285
286char* CAddonCallbacksAddon::GetDVDMenuLanguage(const void* addonData)
287{
288 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
289 if (!helper)
290 return NULL;
291
292 std::string string = g_langInfo.GetDVDMenuLanguage();
293
294 char* buffer = strdup(string.c_str());
295 return buffer;
296}
297
298void CAddonCallbacksAddon::FreeString(const void* addonData, char* str)
299{
300 free(str);
301}
302
303void* CAddonCallbacksAddon::OpenFile(const void* addonData, const char* strFileName, unsigned int flags)
304{
305 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
306 if (!helper)
307 return NULL;
308
309 CFile* file = new CFile;
310 if (file->Open(strFileName, flags))
311 return ((void*)file);
312
313 delete file;
314 return NULL;
315}
316
317void* CAddonCallbacksAddon::OpenFileForWrite(const void* addonData, const char* strFileName, bool bOverwrite)
318{
319 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
320 if (!helper)
321 return NULL;
322
323 CFile* file = new CFile;
324 if (file->OpenForWrite(strFileName, bOverwrite))
325 return ((void*)file);
326
327 delete file;
328 return NULL;
329}
330
331ssize_t CAddonCallbacksAddon::ReadFile(const void* addonData, void* file, void* lpBuf, size_t uiBufSize)
332{
333 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
334 if (!helper)
335 return 0;
336
337 CFile* cfile = (CFile*)file;
338 if (!cfile)
339 return 0;
340
341 return cfile->Read(lpBuf, uiBufSize);
342}
343
344bool CAddonCallbacksAddon::ReadFileString(const void* addonData, void* file, char *szLine, int iLineLength)
345{
346 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
347 if (!helper)
348 return false;
349
350 CFile* cfile = (CFile*)file;
351 if (!cfile)
352 return false;
353
354 return cfile->ReadString(szLine, iLineLength);
355}
356
357ssize_t CAddonCallbacksAddon::WriteFile(const void* addonData, void* file, const void* lpBuf, size_t uiBufSize)
358{
359 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
360 if (!helper)
361 return -1;
362
363 CFile* cfile = (CFile*)file;
364 if (!cfile)
365 return -1;
366
367 return cfile->Write(lpBuf, uiBufSize);
368}
369
370void CAddonCallbacksAddon::FlushFile(const void* addonData, void* file)
371{
372 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
373 if (!helper)
374 return;
375
376 CFile* cfile = (CFile*)file;
377 if (!cfile)
378 return;
379
380 cfile->Flush();
381}
382
383int64_t CAddonCallbacksAddon::SeekFile(const void* addonData, void* file, int64_t iFilePosition, int iWhence)
384{
385 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
386 if (!helper)
387 return 0;
388
389 CFile* cfile = (CFile*)file;
390 if (!cfile)
391 return 0;
392
393 return cfile->Seek(iFilePosition, iWhence);
394}
395
396int CAddonCallbacksAddon::TruncateFile(const void* addonData, void* file, int64_t iSize)
397{
398 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
399 if (!helper)
400 return 0;
401
402 CFile* cfile = (CFile*)file;
403 if (!cfile)
404 return 0;
405
406 return cfile->Truncate(iSize);
407}
408
409int64_t CAddonCallbacksAddon::GetFilePosition(const void* addonData, void* file)
410{
411 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
412 if (!helper)
413 return 0;
414
415 CFile* cfile = (CFile*)file;
416 if (!cfile)
417 return 0;
418
419 return cfile->GetPosition();
420}
421
422int64_t CAddonCallbacksAddon::GetFileLength(const void* addonData, void* file)
423{
424 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
425 if (!helper)
426 return 0;
427
428 CFile* cfile = (CFile*)file;
429 if (!cfile)
430 return 0;
431
432 return cfile->GetLength();
433}
434
435void CAddonCallbacksAddon::CloseFile(const void* addonData, void* file)
436{
437 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
438 if (!helper)
439 return;
440
441 CFile* cfile = (CFile*)file;
442 if (cfile)
443 {
444 cfile->Close();
445 delete cfile;
446 }
447}
448
449int CAddonCallbacksAddon::GetFileChunkSize(const void* addonData, void* file)
450{
451 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
452 if (!helper)
453 return 0;
454
455 CFile* cfile = (CFile*)file;
456 if (!cfile)
457 return 0;
458
459 return cfile->GetChunkSize();
460}
461
462bool CAddonCallbacksAddon::FileExists(const void* addonData, const char *strFileName, bool bUseCache)
463{
464 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
465 if (!helper)
466 return false;
467
468 return CFile::Exists(strFileName, bUseCache);
469}
470
471int CAddonCallbacksAddon::StatFile(const void* addonData, const char *strFileName, struct __stat64* buffer)
472{
473 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
474 if (!helper)
475 return -1;
476
477 return CFile::Stat(strFileName, buffer);
478}
479
480bool CAddonCallbacksAddon::DeleteFile(const void* addonData, const char *strFileName)
481{
482 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
483 if (!helper)
484 return false;
485
486 return CFile::Delete(strFileName);
487}
488
489bool CAddonCallbacksAddon::CanOpenDirectory(const void* addonData, const char* strURL)
490{
491 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
492 if (!helper)
493 return false;
494
495 CFileItemList items;
496 return CDirectory::GetDirectory(strURL, items);
497}
498
499bool CAddonCallbacksAddon::CreateDirectory(const void* addonData, const char *strPath)
500{
501 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
502 if (!helper)
503 return false;
504
505 return CDirectory::Create(strPath);
506}
507
508bool CAddonCallbacksAddon::DirectoryExists(const void* addonData, const char *strPath)
509{
510 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
511 if (!helper)
512 return false;
513
514 return CDirectory::Exists(strPath);
515}
516
517bool CAddonCallbacksAddon::RemoveDirectory(const void* addonData, const char *strPath)
518{
519 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
520 if (!helper)
521 return false;
522
523 // Empty directory
524 CFileItemList fileItems;
525 CDirectory::GetDirectory(strPath, fileItems);
526 for (int i = 0; i < fileItems.Size(); ++i)
527 CFile::Delete(fileItems.Get(i)->GetPath());
528
529 return CDirectory::Remove(strPath);
530}
531
532}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonCallbacksAddon.h b/xbmc/addons/AddonCallbacksAddon.h
new file mode 100644
index 0000000..6eed7cd
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksAddon.h
@@ -0,0 +1,73 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "AddonCallbacks.h"
23
24namespace ADDON
25{
26
27class CAddonCallbacksAddon
28{
29public:
30 CAddonCallbacksAddon(CAddon* addon);
31 ~CAddonCallbacksAddon();
32
33 /*!
34 * @return The callback table.
35 */
36 CB_AddOnLib *GetCallbacks() { return m_callbacks; }
37
38 static void AddOnLog(void *addonData, const addon_log_t addonLogLevel, const char *strMessage);
39 static bool GetAddonSetting(void *addonData, const char *strSettingName, void *settingValue);
40 static void QueueNotification(void *addonData, const queue_msg_t type, const char *strMessage);
41 static bool WakeOnLan(const char *mac);
42 static char* UnknownToUTF8(const char *strSource);
43 static char* GetLocalizedString(const void* addonData, long dwCode);
44 static char* GetDVDMenuLanguage(const void* addonData);
45 static void FreeString(const void* addonData, char* str);
46
47 // file operations
48 static void* OpenFile(const void* addonData, const char* strFileName, unsigned int flags);
49 static void* OpenFileForWrite(const void* addonData, const char* strFileName, bool bOverwrite);
50 static ssize_t ReadFile(const void* addonData, void* file, void* lpBuf, size_t uiBufSize);
51 static bool ReadFileString(const void* addonData, void* file, char *szLine, int iLineLength);
52 static ssize_t WriteFile(const void* addonData, void* file, const void* lpBuf, size_t uiBufSize);
53 static void FlushFile(const void* addonData, void* file);
54 static int64_t SeekFile(const void* addonData, void* file, int64_t iFilePosition, int iWhence);
55 static int TruncateFile(const void* addonData, void* file, int64_t iSize);
56 static int64_t GetFilePosition(const void* addonData, void* file);
57 static int64_t GetFileLength(const void* addonData, void* file);
58 static void CloseFile(const void* addonData, void* file);
59 static int GetFileChunkSize(const void* addonData, void* file);
60 static bool FileExists(const void* addonData, const char *strFileName, bool bUseCache);
61 static int StatFile(const void* addonData, const char *strFileName, struct __stat64* buffer);
62 static bool DeleteFile(const void* addonData, const char *strFileName);
63 static bool CanOpenDirectory(const void* addonData, const char* strURL);
64 static bool CreateDirectory(const void* addonData, const char *strPath);
65 static bool DirectoryExists(const void* addonData, const char *strPath);
66 static bool RemoveDirectory(const void* addonData, const char *strPath);
67
68private:
69 CB_AddOnLib *m_callbacks; /*!< callback addresses */
70 CAddon *m_addon; /*!< the add-on */
71};
72
73}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonCallbacksCodec.cpp b/xbmc/addons/AddonCallbacksCodec.cpp
new file mode 100644
index 0000000..9c7be30
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksCodec.cpp
@@ -0,0 +1,116 @@
1/*
2 * Copyright (C) 2012-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Application.h"
22#include "Addon.h"
23#include "AddonCallbacksCodec.h"
24#include "utils/StringUtils.h"
25
26extern "C" {
27#include "libavcodec/avcodec.h"
28#include "libavformat/avformat.h"
29}
30
31namespace ADDON
32{
33class CCodecIds
34{
35public:
36 virtual ~CCodecIds(void) {}
37
38 static CCodecIds& Get(void)
39 {
40 static CCodecIds _instance;
41 return _instance;
42 }
43
44 xbmc_codec_t GetCodecByName(const char* strCodecName)
45 {
46 xbmc_codec_t retVal = XBMC_INVALID_CODEC;
47 if (strlen(strCodecName) == 0)
48 return retVal;
49
50 std::string strUpperCodecName = strCodecName;
51 StringUtils::ToUpper(strUpperCodecName);
52
53 std::map<std::string, xbmc_codec_t>::const_iterator it = m_lookup.find(strUpperCodecName);
54 if (it != m_lookup.end())
55 retVal = it->second;
56
57 return retVal;
58 }
59
60private:
61 CCodecIds(void)
62 {
63 // get ids and names
64 AVCodec* codec = NULL;
65 xbmc_codec_t tmp;
66 while ((codec = av_codec_next(codec)))
67 {
68 if (av_codec_is_decoder(codec))
69 {
70 tmp.codec_type = (xbmc_codec_type_t)codec->type;
71 tmp.codec_id = codec->id;
72
73 std::string strUpperCodecName = codec->name;
74 StringUtils::ToUpper(strUpperCodecName);
75
76 m_lookup.insert(std::make_pair(strUpperCodecName, tmp));
77 }
78 }
79
80 // teletext is not returned by av_codec_next. we got our own decoder
81 tmp.codec_type = XBMC_CODEC_TYPE_SUBTITLE;
82 tmp.codec_id = AV_CODEC_ID_DVB_TELETEXT;
83 m_lookup.insert(std::make_pair("TELETEXT", tmp));
84
85 // rds is not returned by av_codec_next. we got our own decoder
86 tmp.codec_type = XBMC_CODEC_TYPE_RDS;
87 tmp.codec_id = AV_CODEC_ID_NONE;
88 m_lookup.insert(std::make_pair("RDS", tmp));
89 }
90
91 std::map<std::string, xbmc_codec_t> m_lookup;
92};
93
94CAddonCallbacksCodec::CAddonCallbacksCodec(CAddon* addon)
95{
96 m_addon = addon;
97 m_callbacks = new CB_CODECLib;
98
99 /* write XBMC addon-on specific add-on function addresses to the callback table */
100 m_callbacks->GetCodecByName = GetCodecByName;
101}
102
103CAddonCallbacksCodec::~CAddonCallbacksCodec()
104{
105 /* delete the callback table */
106 delete m_callbacks;
107}
108
109xbmc_codec_t CAddonCallbacksCodec::GetCodecByName(const void* addonData, const char* strCodecName)
110{
111 (void)addonData;
112 return CCodecIds::Get().GetCodecByName(strCodecName);
113}
114
115}; /* namespace ADDON */
116
diff --git a/xbmc/addons/AddonCallbacksCodec.h b/xbmc/addons/AddonCallbacksCodec.h
new file mode 100644
index 0000000..5b816fe
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksCodec.h
@@ -0,0 +1,46 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "AddonCallbacks.h"
23
24namespace ADDON
25{
26
27class CAddonCallbacksCodec
28{
29public:
30 CAddonCallbacksCodec(CAddon* addon);
31 ~CAddonCallbacksCodec();
32
33 /*!
34 * @return The callback table.
35 */
36 CB_CODECLib *GetCallbacks() { return m_callbacks; }
37
38 static xbmc_codec_t GetCodecByName(const void* addonData, const char* strCodecName);
39
40private:
41 CB_CODECLib* m_callbacks; /*!< callback addresses */
42 CAddon* m_addon; /*!< the add-on */
43};
44
45}; /* namespace ADDON */
46
diff --git a/xbmc/addons/AddonCallbacksGUI.cpp b/xbmc/addons/AddonCallbacksGUI.cpp
new file mode 100644
index 0000000..3069039
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksGUI.cpp
@@ -0,0 +1,2281 @@
1/*
2 * Copyright (C) 2012-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Application.h"
22#include "ApplicationMessenger.h"
23#include "Addon.h"
24#include "AddonCallbacksGUI.h"
25#include "utils/log.h"
26#include "Skin.h"
27#include "FileItem.h"
28#include "filesystem/File.h"
29#include "utils/URIUtils.h"
30#include "utils/TimeUtils.h"
31#include "utils/StringUtils.h"
32#include "guilib/GUIWindowManager.h"
33#include "input/Key.h"
34#include "guilib/TextureManager.h"
35#include "guilib/GUISpinControlEx.h"
36#include "guilib/GUIRadioButtonControl.h"
37#include "guilib/GUISettingsSliderControl.h"
38#include "guilib/GUIEditControl.h"
39#include "guilib/GUIProgressControl.h"
40#include "guilib/GUIRenderingControl.h"
41#include "guilib/GUIKeyboardFactory.h"
42#include "dialogs/GUIDialogNumeric.h"
43#include "dialogs/GUIDialogOK.h"
44#include "dialogs/GUIDialogYesNo.h"
45#include "dialogs/GUIDialogFileBrowser.h"
46#include "dialogs/GUIDialogTextViewer.h"
47#include "dialogs/GUIDialogSelect.h"
48
49#define CONTROL_BTNVIEWASICONS 2
50#define CONTROL_BTNSORTBY 3
51#define CONTROL_BTNSORTASC 4
52#define CONTROL_LABELFILES 12
53
54using namespace std;
55
56namespace ADDON
57{
58
59static int iXBMCGUILockRef = 0;
60
61CAddonCallbacksGUI::CAddonCallbacksGUI(CAddon* addon)
62{
63 m_addon = addon;
64 m_callbacks = new CB_GUILib;
65
66 /* GUI Helper functions */
67 m_callbacks->Lock = CAddonCallbacksGUI::Lock;
68 m_callbacks->Unlock = CAddonCallbacksGUI::Unlock;
69 m_callbacks->GetScreenHeight = CAddonCallbacksGUI::GetScreenHeight;
70 m_callbacks->GetScreenWidth = CAddonCallbacksGUI::GetScreenWidth;
71 m_callbacks->GetVideoResolution = CAddonCallbacksGUI::GetVideoResolution;
72 m_callbacks->Window_New = CAddonCallbacksGUI::Window_New;
73 m_callbacks->Window_Delete = CAddonCallbacksGUI::Window_Delete;
74 m_callbacks->Window_SetCallbacks = CAddonCallbacksGUI::Window_SetCallbacks;
75 m_callbacks->Window_Show = CAddonCallbacksGUI::Window_Show;
76 m_callbacks->Window_Close = CAddonCallbacksGUI::Window_Close;
77 m_callbacks->Window_DoModal = CAddonCallbacksGUI::Window_DoModal;
78 m_callbacks->Window_SetFocusId = CAddonCallbacksGUI::Window_SetFocusId;
79 m_callbacks->Window_GetFocusId = CAddonCallbacksGUI::Window_GetFocusId;
80 m_callbacks->Window_SetCoordinateResolution = CAddonCallbacksGUI::Window_SetCoordinateResolution;
81 m_callbacks->Window_SetProperty = CAddonCallbacksGUI::Window_SetProperty;
82 m_callbacks->Window_SetPropertyInt = CAddonCallbacksGUI::Window_SetPropertyInt;
83 m_callbacks->Window_SetPropertyBool = CAddonCallbacksGUI::Window_SetPropertyBool;
84 m_callbacks->Window_SetPropertyDouble = CAddonCallbacksGUI::Window_SetPropertyDouble;
85 m_callbacks->Window_GetProperty = CAddonCallbacksGUI::Window_GetProperty;
86 m_callbacks->Window_GetPropertyInt = CAddonCallbacksGUI::Window_GetPropertyInt;
87 m_callbacks->Window_GetPropertyBool = CAddonCallbacksGUI::Window_GetPropertyBool;
88 m_callbacks->Window_GetPropertyDouble = CAddonCallbacksGUI::Window_GetPropertyDouble;
89 m_callbacks->Window_ClearProperties = CAddonCallbacksGUI::Window_ClearProperties;
90
91 m_callbacks->Window_GetListSize = CAddonCallbacksGUI::Window_GetListSize;
92 m_callbacks->Window_ClearList = CAddonCallbacksGUI::Window_ClearList;
93 m_callbacks->Window_AddItem = CAddonCallbacksGUI::Window_AddItem;
94 m_callbacks->Window_AddStringItem = CAddonCallbacksGUI::Window_AddStringItem;
95 m_callbacks->Window_RemoveItem = CAddonCallbacksGUI::Window_RemoveItem;
96 m_callbacks->Window_GetListItem = CAddonCallbacksGUI::Window_GetListItem;
97 m_callbacks->Window_SetCurrentListPosition = CAddonCallbacksGUI::Window_SetCurrentListPosition;
98 m_callbacks->Window_GetCurrentListPosition = CAddonCallbacksGUI::Window_GetCurrentListPosition;
99
100 m_callbacks->Window_GetControl_Spin = CAddonCallbacksGUI::Window_GetControl_Spin;
101 m_callbacks->Window_GetControl_Button = CAddonCallbacksGUI::Window_GetControl_Button;
102 m_callbacks->Window_GetControl_RadioButton = CAddonCallbacksGUI::Window_GetControl_RadioButton;
103 m_callbacks->Window_GetControl_Edit = CAddonCallbacksGUI::Window_GetControl_Edit;
104 m_callbacks->Window_GetControl_Progress = CAddonCallbacksGUI::Window_GetControl_Progress;
105 m_callbacks->Window_GetControl_RenderAddon = CAddonCallbacksGUI::Window_GetControl_RenderAddon;
106 m_callbacks->Window_GetControl_Slider = CAddonCallbacksGUI::Window_GetControl_Slider;
107 m_callbacks->Window_GetControl_SettingsSlider= CAddonCallbacksGUI::Window_GetControl_SettingsSlider;
108
109 m_callbacks->Window_SetControlLabel = CAddonCallbacksGUI::Window_SetControlLabel;
110 m_callbacks->Window_MarkDirtyRegion = CAddonCallbacksGUI::Window_MarkDirtyRegion;
111
112 m_callbacks->Control_Spin_SetVisible = CAddonCallbacksGUI::Control_Spin_SetVisible;
113 m_callbacks->Control_Spin_SetText = CAddonCallbacksGUI::Control_Spin_SetText;
114 m_callbacks->Control_Spin_Clear = CAddonCallbacksGUI::Control_Spin_Clear;
115 m_callbacks->Control_Spin_AddLabel = CAddonCallbacksGUI::Control_Spin_AddLabel;
116 m_callbacks->Control_Spin_GetValue = CAddonCallbacksGUI::Control_Spin_GetValue;
117 m_callbacks->Control_Spin_SetValue = CAddonCallbacksGUI::Control_Spin_SetValue;
118
119 m_callbacks->Control_RadioButton_SetVisible = CAddonCallbacksGUI::Control_RadioButton_SetVisible;
120 m_callbacks->Control_RadioButton_SetText = CAddonCallbacksGUI::Control_RadioButton_SetText;
121 m_callbacks->Control_RadioButton_SetSelected= CAddonCallbacksGUI::Control_RadioButton_SetSelected;
122 m_callbacks->Control_RadioButton_IsSelected = CAddonCallbacksGUI::Control_RadioButton_IsSelected;
123
124 m_callbacks->Control_Progress_SetPercentage = CAddonCallbacksGUI::Control_Progress_SetPercentage;
125 m_callbacks->Control_Progress_GetPercentage = CAddonCallbacksGUI::Control_Progress_GetPercentage;
126 m_callbacks->Control_Progress_SetInfo = CAddonCallbacksGUI::Control_Progress_SetInfo;
127 m_callbacks->Control_Progress_GetInfo = CAddonCallbacksGUI::Control_Progress_GetInfo;
128 m_callbacks->Control_Progress_GetDescription= CAddonCallbacksGUI::Control_Progress_GetDescription;
129
130 m_callbacks->ListItem_Create = CAddonCallbacksGUI::ListItem_Create;
131 m_callbacks->ListItem_GetLabel = CAddonCallbacksGUI::ListItem_GetLabel;
132 m_callbacks->ListItem_SetLabel = CAddonCallbacksGUI::ListItem_SetLabel;
133 m_callbacks->ListItem_GetLabel2 = CAddonCallbacksGUI::ListItem_GetLabel2;
134 m_callbacks->ListItem_SetLabel2 = CAddonCallbacksGUI::ListItem_SetLabel2;
135 m_callbacks->ListItem_SetIconImage = CAddonCallbacksGUI::ListItem_SetIconImage;
136 m_callbacks->ListItem_SetThumbnailImage = CAddonCallbacksGUI::ListItem_SetThumbnailImage;
137 m_callbacks->ListItem_SetInfo = CAddonCallbacksGUI::ListItem_SetInfo;
138 m_callbacks->ListItem_SetProperty = CAddonCallbacksGUI::ListItem_SetProperty;
139 m_callbacks->ListItem_GetProperty = CAddonCallbacksGUI::ListItem_GetProperty;
140 m_callbacks->ListItem_SetPath = CAddonCallbacksGUI::ListItem_SetPath;
141
142 m_callbacks->RenderAddon_SetCallbacks = CAddonCallbacksGUI::RenderAddon_SetCallbacks;
143 m_callbacks->RenderAddon_Delete = CAddonCallbacksGUI::RenderAddon_Delete;
144
145 m_callbacks->Control_Slider_SetVisible = CAddonCallbacksGUI::Control_Slider_SetVisible;
146 m_callbacks->Control_Slider_GetDescription = CAddonCallbacksGUI::Control_Slider_GetDescription;
147 m_callbacks->Control_Slider_SetIntRange = CAddonCallbacksGUI::Control_Slider_SetIntRange;
148 m_callbacks->Control_Slider_SetIntValue = CAddonCallbacksGUI::Control_Slider_SetIntValue;
149 m_callbacks->Control_Slider_GetIntValue = CAddonCallbacksGUI::Control_Slider_GetIntValue;
150 m_callbacks->Control_Slider_SetIntInterval = CAddonCallbacksGUI::Control_Slider_SetIntInterval;
151 m_callbacks->Control_Slider_SetPercentage = CAddonCallbacksGUI::Control_Slider_SetPercentage;
152 m_callbacks->Control_Slider_GetPercentage = CAddonCallbacksGUI::Control_Slider_GetPercentage;
153 m_callbacks->Control_Slider_SetFloatRange = CAddonCallbacksGUI::Control_Slider_SetFloatRange;
154 m_callbacks->Control_Slider_SetFloatValue = CAddonCallbacksGUI::Control_Slider_SetFloatValue;
155 m_callbacks->Control_Slider_GetFloatValue = CAddonCallbacksGUI::Control_Slider_GetFloatValue;
156 m_callbacks->Control_Slider_SetFloatInterval = CAddonCallbacksGUI::Control_Slider_SetFloatInterval;
157
158 m_callbacks->Control_SettingsSlider_SetVisible = CAddonCallbacksGUI::Control_SettingsSlider_SetVisible;
159 m_callbacks->Control_SettingsSlider_SetText = CAddonCallbacksGUI::Control_SettingsSlider_SetText;
160 m_callbacks->Control_SettingsSlider_GetDescription = CAddonCallbacksGUI::Control_SettingsSlider_GetDescription;
161 m_callbacks->Control_SettingsSlider_SetIntRange = CAddonCallbacksGUI::Control_SettingsSlider_SetIntRange;
162 m_callbacks->Control_SettingsSlider_SetIntValue = CAddonCallbacksGUI::Control_SettingsSlider_SetIntValue;
163 m_callbacks->Control_SettingsSlider_GetIntValue = CAddonCallbacksGUI::Control_SettingsSlider_GetIntValue;
164 m_callbacks->Control_SettingsSlider_SetIntInterval = CAddonCallbacksGUI::Control_SettingsSlider_SetIntInterval;
165 m_callbacks->Control_SettingsSlider_SetPercentage = CAddonCallbacksGUI::Control_SettingsSlider_SetPercentage;
166 m_callbacks->Control_SettingsSlider_GetPercentage = CAddonCallbacksGUI::Control_SettingsSlider_GetPercentage;
167 m_callbacks->Control_SettingsSlider_SetFloatRange = CAddonCallbacksGUI::Control_SettingsSlider_SetFloatRange;
168 m_callbacks->Control_SettingsSlider_SetFloatValue = CAddonCallbacksGUI::Control_SettingsSlider_SetFloatValue;
169 m_callbacks->Control_SettingsSlider_GetFloatValue = CAddonCallbacksGUI::Control_SettingsSlider_GetFloatValue;
170 m_callbacks->Control_SettingsSlider_SetFloatInterval = CAddonCallbacksGUI::Control_SettingsSlider_SetFloatInterval;
171
172 m_callbacks->Dialog_Keyboard_ShowAndGetInputWithHead = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetInputWithHead;
173 m_callbacks->Dialog_Keyboard_ShowAndGetInput = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetInput;
174 m_callbacks->Dialog_Keyboard_ShowAndGetNewPasswordWithHead = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetNewPasswordWithHead;
175 m_callbacks->Dialog_Keyboard_ShowAndGetNewPassword = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetNewPassword;
176 m_callbacks->Dialog_Keyboard_ShowAndVerifyNewPasswordWithHead = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndVerifyNewPasswordWithHead;
177 m_callbacks->Dialog_Keyboard_ShowAndVerifyNewPassword = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndVerifyNewPassword;
178 m_callbacks->Dialog_Keyboard_ShowAndVerifyPassword = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndVerifyPassword;
179 m_callbacks->Dialog_Keyboard_ShowAndGetFilter = CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetFilter;
180 m_callbacks->Dialog_Keyboard_SendTextToActiveKeyboard = CAddonCallbacksGUI::Dialog_Keyboard_SendTextToActiveKeyboard;
181 m_callbacks->Dialog_Keyboard_isKeyboardActivated = CAddonCallbacksGUI::Dialog_Keyboard_isKeyboardActivated;
182
183 m_callbacks->Dialog_Numeric_ShowAndVerifyNewPassword = CAddonCallbacksGUI::Dialog_Numeric_ShowAndVerifyNewPassword;
184 m_callbacks->Dialog_Numeric_ShowAndVerifyPassword = CAddonCallbacksGUI::Dialog_Numeric_ShowAndVerifyPassword;
185 m_callbacks->Dialog_Numeric_ShowAndVerifyInput = CAddonCallbacksGUI::Dialog_Numeric_ShowAndVerifyInput;
186 m_callbacks->Dialog_Numeric_ShowAndGetTime = CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetTime;
187 m_callbacks->Dialog_Numeric_ShowAndGetDate = CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetDate;
188 m_callbacks->Dialog_Numeric_ShowAndGetIPAddress = CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetIPAddress;
189 m_callbacks->Dialog_Numeric_ShowAndGetNumber = CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetNumber;
190 m_callbacks->Dialog_Numeric_ShowAndGetSeconds = CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetSeconds;
191
192 m_callbacks->Dialog_FileBrowser_ShowAndGetFile = CAddonCallbacksGUI::Dialog_FileBrowser_ShowAndGetFile;
193
194 m_callbacks->Dialog_OK_ShowAndGetInputSingleText = CAddonCallbacksGUI::Dialog_OK_ShowAndGetInputSingleText;
195 m_callbacks->Dialog_OK_ShowAndGetInputLineText = CAddonCallbacksGUI::Dialog_OK_ShowAndGetInputLineText;
196
197 m_callbacks->Dialog_YesNo_ShowAndGetInputSingleText = CAddonCallbacksGUI::Dialog_YesNo_ShowAndGetInputSingleText;
198 m_callbacks->Dialog_YesNo_ShowAndGetInputLineText = CAddonCallbacksGUI::Dialog_YesNo_ShowAndGetInputLineText;
199 m_callbacks->Dialog_YesNo_ShowAndGetInputLineButtonText = CAddonCallbacksGUI::Dialog_YesNo_ShowAndGetInputLineButtonText;
200
201 m_callbacks->Dialog_TextViewer = CAddonCallbacksGUI::Dialog_TextViewer;
202
203 m_callbacks->Dialog_Select = CAddonCallbacksGUI::Dialog_Select;
204}
205
206CAddonCallbacksGUI::~CAddonCallbacksGUI()
207{
208 delete m_callbacks;
209}
210
211void CAddonCallbacksGUI::Lock()
212{
213 if (iXBMCGUILockRef == 0) g_graphicsContext.Lock();
214 iXBMCGUILockRef++;
215}
216
217void CAddonCallbacksGUI::Unlock()
218{
219 if (iXBMCGUILockRef > 0)
220 {
221 iXBMCGUILockRef--;
222 if (iXBMCGUILockRef == 0) g_graphicsContext.Unlock();
223 }
224}
225
226int CAddonCallbacksGUI::GetScreenHeight()
227{
228 return g_graphicsContext.GetHeight();
229}
230
231int CAddonCallbacksGUI::GetScreenWidth()
232{
233 return g_graphicsContext.GetWidth();
234}
235
236int CAddonCallbacksGUI::GetVideoResolution()
237{
238 return (int)g_graphicsContext.GetVideoResolution();
239}
240
241GUIHANDLE CAddonCallbacksGUI::Window_New(void *addonData, const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog)
242{
243 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
244 if (!helper)
245 return NULL;
246
247 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
248
249 RESOLUTION_INFO res;
250 std::string strSkinPath;
251 if (!forceFallback)
252 {
253 /* Check to see if the XML file exists in current skin. If not use
254 fallback path to find a skin for the addon */
255 strSkinPath = g_SkinInfo->GetSkinPath(xmlFilename, &res);
256
257 if (!XFILE::CFile::Exists(strSkinPath))
258 {
259 /* Check for the matching folder for the skin in the fallback skins folder */
260 std::string basePath = URIUtils::AddFileToFolder(guiHelper->m_addon->Path(), "resources");
261 basePath = URIUtils::AddFileToFolder(basePath, "skins");
262 basePath = URIUtils::AddFileToFolder(basePath, URIUtils::GetFileName(g_SkinInfo->Path()));
263 strSkinPath = g_SkinInfo->GetSkinPath(xmlFilename, &res, basePath);
264 if (!XFILE::CFile::Exists(strSkinPath))
265 {
266 /* Finally fallback to the DefaultSkin as it didn't exist in either the
267 XBMC Skin folder or the fallback skin folder */
268 forceFallback = true;
269 }
270 }
271 }
272
273 if (forceFallback)
274 {
275 //FIXME make this static method of current skin?
276 std::string str("none");
277 AddonProps props(str, ADDON_SKIN, str, str);
278 std::string basePath = URIUtils::AddFileToFolder(guiHelper->m_addon->Path(), "resources");
279 basePath = URIUtils::AddFileToFolder(basePath, "skins");
280 basePath = URIUtils::AddFileToFolder(basePath, defaultSkin);
281 props.path = basePath;
282
283 CSkinInfo skinInfo(props);
284 skinInfo.Start();
285 strSkinPath = skinInfo.GetSkinPath(xmlFilename, &res, basePath);
286
287 if (!XFILE::CFile::Exists(strSkinPath))
288 {
289 CLog::Log(LOGERROR, "Window_New: %s/%s - XML File '%s' for Window is missing, contact Developer '%s' of this AddOn", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str(), strSkinPath.c_str(), guiHelper->m_addon->Author().c_str());
290 return NULL;
291 }
292 }
293 // window id's 14000 - 14100 are reserved for addons
294 // get first window id that is not in use
295 int id = WINDOW_ADDON_START;
296 // if window 14099 is in use it means addon can't create more windows
297 Lock();
298 if (g_windowManager.GetWindow(WINDOW_ADDON_END))
299 {
300 Unlock();
301 CLog::Log(LOGERROR, "Window_New: %s/%s - maximum number of windows reached", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
302 return NULL;
303 }
304 while(id < WINDOW_ADDON_END && g_windowManager.GetWindow(id) != NULL) id++;
305 Unlock();
306
307 CGUIWindow *window;
308 if (!asDialog)
309 window = new CGUIAddonWindow(id, strSkinPath, guiHelper->m_addon);
310 else
311 window = new CGUIAddonWindowDialog(id, strSkinPath, guiHelper->m_addon);
312
313 Lock();
314 g_windowManager.Add(window);
315 Unlock();
316
317 window->SetCoordsRes(res);
318
319 return window;
320}
321
322void CAddonCallbacksGUI::Window_Delete(void *addonData, GUIHANDLE handle)
323{
324 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
325 if (!helper)
326 return;
327
328 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
329
330 if (!handle)
331 {
332 CLog::Log(LOGERROR, "Window_Show: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
333 return;
334 }
335
336 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
337 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
338 if (!pWindow)
339 return;
340
341 Lock();
342 // first change to an existing window
343 if (g_windowManager.GetActiveWindow() == pAddonWindow->m_iWindowId && !g_application.m_bStop)
344 {
345 if(g_windowManager.GetWindow(pAddonWindow->m_iOldWindowId))
346 g_windowManager.ActivateWindow(pAddonWindow->m_iOldWindowId);
347 else // old window does not exist anymore, switch to home
348 g_windowManager.ActivateWindow(WINDOW_HOME);
349 }
350 // Free any window properties
351 pAddonWindow->ClearProperties();
352 // free the window's resources and unload it (free all guicontrols)
353 pAddonWindow->FreeResources(true);
354
355 g_windowManager.Remove(pAddonWindow->GetID());
356 delete pAddonWindow;
357 Unlock();
358}
359
360void CAddonCallbacksGUI::Window_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*initCB)(GUIHANDLE), bool (*clickCB)(GUIHANDLE, int), bool (*focusCB)(GUIHANDLE, int), bool (*onActionCB)(GUIHANDLE handle, int))
361{
362 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
363 if (!helper || !handle)
364 return;
365
366 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
367
368 Lock();
369 pAddonWindow->m_clientHandle = clienthandle;
370 pAddonWindow->CBOnInit = initCB;
371 pAddonWindow->CBOnClick = clickCB;
372 pAddonWindow->CBOnFocus = focusCB;
373 pAddonWindow->CBOnAction = onActionCB;
374 Unlock();
375}
376
377bool CAddonCallbacksGUI::Window_Show(void *addonData, GUIHANDLE handle)
378{
379 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
380 if (!helper)
381 return false;
382
383 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
384
385 if (!handle)
386 {
387 CLog::Log(LOGERROR, "Window_Show: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
388 return false;
389 }
390
391 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
392 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
393 if (!pWindow)
394 return false;
395
396 if (pAddonWindow->m_iOldWindowId != pAddonWindow->m_iWindowId && pAddonWindow->m_iWindowId != g_windowManager.GetActiveWindow())
397 pAddonWindow->m_iOldWindowId = g_windowManager.GetActiveWindow();
398
399 Lock();
400 if (pAddonWindow->IsDialog())
401 ((CGUIAddonWindowDialog*)pAddonWindow)->Show();
402 else
403 g_windowManager.ActivateWindow(pAddonWindow->m_iWindowId);
404 Unlock();
405
406 return true;
407}
408
409bool CAddonCallbacksGUI::Window_Close(void *addonData, GUIHANDLE handle)
410{
411 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
412 if (!helper)
413 return false;
414
415 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
416
417 if (!handle)
418 {
419 CLog::Log(LOGERROR, "Window_Close: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
420 return false;
421 }
422
423 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
424 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
425 if (!pWindow)
426 return false;
427
428 pAddonWindow->m_bModal = false;
429 if (pAddonWindow->IsDialog())
430 ((CGUIAddonWindowDialog*)pAddonWindow)->PulseActionEvent();
431 else
432 ((CGUIAddonWindow*)pAddonWindow)->PulseActionEvent();
433
434 Lock();
435 // if it's a dialog, we have to close it a bit different
436 if (pAddonWindow->IsDialog())
437 ((CGUIAddonWindowDialog*)pAddonWindow)->Show(false);
438 else
439 g_windowManager.ActivateWindow(pAddonWindow->m_iOldWindowId);
440 pAddonWindow->m_iOldWindowId = 0;
441
442 Unlock();
443
444 return true;
445}
446
447bool CAddonCallbacksGUI::Window_DoModal(void *addonData, GUIHANDLE handle)
448{
449 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
450 if (!helper)
451 return false;
452
453 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
454
455 if (!handle)
456 {
457 CLog::Log(LOGERROR, "Window_DoModal: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
458 return false;
459 }
460
461 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
462 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
463 if (!pWindow)
464 return false;
465
466 pAddonWindow->m_bModal = true;
467
468 if (pAddonWindow->m_iWindowId != g_windowManager.GetActiveWindow())
469 Window_Show(addonData, handle);
470
471 return true;
472}
473
474bool CAddonCallbacksGUI::Window_SetFocusId(void *addonData, GUIHANDLE handle, int iControlId)
475{
476 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
477 if (!helper)
478 return false;
479
480 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
481
482 if (!handle)
483 {
484 CLog::Log(LOGERROR, "Window_SetFocusId: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
485 return false;
486 }
487
488 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
489 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
490 if (!pWindow)
491 return false;
492
493 if(!pWindow->GetControl(iControlId))
494 {
495 CLog::Log(LOGERROR, "Window_SetFocusId: %s/%s - Control does not exist in window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
496 return false;
497 }
498
499 Lock();
500 CGUIMessage msg = CGUIMessage(GUI_MSG_SETFOCUS, pAddonWindow->m_iWindowId, iControlId);
501 pWindow->OnMessage(msg);
502 Unlock();
503
504 return true;
505}
506
507int CAddonCallbacksGUI::Window_GetFocusId(void *addonData, GUIHANDLE handle)
508{
509 int iControlId = -1;
510
511 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
512 if (!helper)
513 return iControlId;
514
515 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
516
517 if (!handle)
518 {
519 CLog::Log(LOGERROR, "Window_GetFocusId: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
520 return iControlId;
521 }
522
523 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
524 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
525 if (!pWindow)
526 return iControlId;
527
528 Lock();
529 iControlId = pWindow->GetFocusedControlID();
530 Unlock();
531
532 if (iControlId == -1)
533 {
534 CLog::Log(LOGERROR, "Window_GetFocusId: %s/%s - No control in this window has focus", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
535 return iControlId;
536 }
537
538 return iControlId;
539}
540
541bool CAddonCallbacksGUI::Window_SetCoordinateResolution(void *addonData, GUIHANDLE handle, int res)
542{
543 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
544 if (!helper)
545 return false;
546
547 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
548
549 if (!handle)
550 {
551 CLog::Log(LOGERROR, "SetCoordinateResolution: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
552 return false;
553 }
554
555 if (res < RES_HDTV_1080i || res > RES_AUTORES)
556 {
557 CLog::Log(LOGERROR, "SetCoordinateResolution: %s/%s - Invalid resolution", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
558 return false;
559 }
560
561 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
562 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
563 if (!pWindow)
564 return false;
565
566 pWindow->SetCoordsRes((RESOLUTION)res);
567
568 return true;
569}
570
571void CAddonCallbacksGUI::Window_SetProperty(void *addonData, GUIHANDLE handle, const char *key, const char *value)
572{
573 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
574 if (!helper)
575 return;
576
577 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
578
579 if (!handle || !key || !value)
580 {
581 CLog::Log(LOGERROR, "Window_SetProperty: %s/%s - No Window or NULL key or value", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
582 return;
583 }
584
585 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
586 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
587 if (!pWindow)
588 return;
589
590 std::string lowerKey = key;
591 StringUtils::ToLower(lowerKey);
592
593 Lock();
594 pWindow->SetProperty(lowerKey, value);
595 Unlock();
596}
597
598void CAddonCallbacksGUI::Window_SetPropertyInt(void *addonData, GUIHANDLE handle, const char *key, int value)
599{
600 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
601 if (!helper)
602 return;
603
604 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
605
606 if (!handle || !key)
607 {
608 CLog::Log(LOGERROR, "Window_SetPropertyInt: %s/%s - No Window or NULL key", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
609 return;
610 }
611
612 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
613 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
614 if (!pWindow)
615 return;
616
617 std::string lowerKey = key;
618 StringUtils::ToLower(lowerKey);
619
620 Lock();
621 pWindow->SetProperty(lowerKey, value);
622 Unlock();
623}
624
625void CAddonCallbacksGUI::Window_SetPropertyBool(void *addonData, GUIHANDLE handle, const char *key, bool value)
626{
627 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
628 if (!helper)
629 return;
630
631 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
632
633 if (!handle || !key)
634 {
635 CLog::Log(LOGERROR, "Window_SetPropertyBool: %s/%s - No Window or NULL key", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
636 return;
637 }
638
639 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
640 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
641 if (!pWindow)
642 return;
643
644 std::string lowerKey = key;
645 StringUtils::ToLower(lowerKey);
646
647 Lock();
648 pWindow->SetProperty(lowerKey, value);
649 Unlock();
650}
651
652void CAddonCallbacksGUI::Window_SetPropertyDouble(void *addonData, GUIHANDLE handle, const char *key, double value)
653{
654 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
655 if (!helper)
656 return;
657
658 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
659
660 if (!handle || !key)
661 {
662 CLog::Log(LOGERROR, "Window_SetPropertyDouble: %s/%s - No Window or NULL key", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
663 return;
664 }
665
666 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
667 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
668 if (!pWindow)
669 return;
670
671 std::string lowerKey = key;
672 StringUtils::ToLower(lowerKey);
673
674 Lock();
675 pWindow->SetProperty(lowerKey, value);
676 Unlock();
677}
678
679const char* CAddonCallbacksGUI::Window_GetProperty(void *addonData, GUIHANDLE handle, const char *key)
680{
681 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
682 if (!helper)
683 return NULL;
684
685 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
686
687 if (!handle || !key)
688 {
689 CLog::Log(LOGERROR, "Window_GetProperty: %s/%s - No Window or NULL key", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
690 return NULL;
691 }
692
693 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
694 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
695 if (!pWindow)
696 return NULL;
697
698 std::string lowerKey = key;
699 StringUtils::ToLower(lowerKey);
700
701 Lock();
702 string value = pWindow->GetProperty(lowerKey).asString();
703 Unlock();
704
705 return strdup(value.c_str());
706}
707
708int CAddonCallbacksGUI::Window_GetPropertyInt(void *addonData, GUIHANDLE handle, const char *key)
709{
710 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
711 if (!helper)
712 return -1;
713
714 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
715
716 if (!handle || !key)
717 {
718 CLog::Log(LOGERROR, "Window_GetPropertyInt: %s/%s - No Window or NULL key", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
719 return -1;
720 }
721
722 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
723 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
724 if (!pWindow)
725 return -1;
726
727 std::string lowerKey = key;
728 StringUtils::ToLower(lowerKey);
729
730 Lock();
731 int value = (int)pWindow->GetProperty(lowerKey).asInteger();
732 Unlock();
733
734 return value;
735}
736
737bool CAddonCallbacksGUI::Window_GetPropertyBool(void *addonData, GUIHANDLE handle, const char *key)
738{
739 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
740 if (!helper)
741 return false;
742
743 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
744
745 if (!handle || !key)
746 {
747 CLog::Log(LOGERROR, "Window_GetPropertyBool: %s/%s - No Window or NULL key", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
748 return false;
749 }
750
751 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
752 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
753 if (!pWindow)
754 return false;
755
756 std::string lowerKey = key;
757 StringUtils::ToLower(lowerKey);
758
759 Lock();
760 bool value = pWindow->GetProperty(lowerKey).asBoolean();
761 Unlock();
762
763 return value;
764}
765
766double CAddonCallbacksGUI::Window_GetPropertyDouble(void *addonData, GUIHANDLE handle, const char *key)
767{
768 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
769 if (!helper)
770 return 0.0;
771
772 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
773
774 if (!handle || !key)
775 {
776 CLog::Log(LOGERROR, "Window_GetPropertyDouble: %s/%s - No Window or NULL key", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
777 return 0.0;
778 }
779
780 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
781 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
782 if (!pWindow)
783 return 0.0;
784
785 std::string lowerKey = key;
786 StringUtils::ToLower(lowerKey);
787
788 Lock();
789 double value = pWindow->GetProperty(lowerKey).asDouble();
790 Unlock();
791
792 return value;
793}
794
795void CAddonCallbacksGUI::Window_ClearProperties(void *addonData, GUIHANDLE handle)
796{
797 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
798 if (!helper)
799 return;
800
801 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
802
803 if (!handle)
804 {
805 CLog::Log(LOGERROR, "Window_ClearProperties: %s/%s - No Window", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
806 return;
807 }
808
809 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
810 CGUIWindow *pWindow = (CGUIWindow*)g_windowManager.GetWindow(pAddonWindow->m_iWindowId);
811 if (!pWindow)
812 return;
813
814 Lock();
815 pWindow->ClearProperties();
816 Unlock();
817}
818
819int CAddonCallbacksGUI::Window_GetListSize(void *addonData, GUIHANDLE handle)
820{
821 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
822 if (!helper || !handle)
823 return -1;
824
825 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
826
827 Lock();
828 int listSize = pAddonWindow->GetListSize();
829 Unlock();
830
831 return listSize;
832}
833
834void CAddonCallbacksGUI::Window_ClearList(void *addonData, GUIHANDLE handle)
835{
836 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
837 if (!helper || !handle)
838 return;
839
840 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
841
842 Lock();
843 pAddonWindow->ClearList();
844 Unlock();
845
846 return;
847}
848
849GUIHANDLE CAddonCallbacksGUI::Window_AddItem(void *addonData, GUIHANDLE handle, GUIHANDLE item, int itemPosition)
850{
851 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
852 if (!helper || !handle || !item)
853 return NULL;
854
855 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
856 CFileItemPtr pItem((CFileItem*)item);
857 Lock();
858 pAddonWindow->AddItem(pItem, itemPosition);
859 Unlock();
860
861 return item;
862}
863
864GUIHANDLE CAddonCallbacksGUI::Window_AddStringItem(void *addonData, GUIHANDLE handle, const char *itemName, int itemPosition)
865{
866 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
867 if (!helper || !handle || !itemName)
868 return NULL;
869
870 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
871 CFileItemPtr item(new CFileItem(itemName));
872 Lock();
873 pAddonWindow->AddItem(item, itemPosition);
874 Unlock();
875
876 return item.get();
877}
878
879void CAddonCallbacksGUI::Window_RemoveItem(void *addonData, GUIHANDLE handle, int itemPosition)
880{
881 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
882 if (!helper || !handle)
883 return;
884
885 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
886
887 Lock();
888 pAddonWindow->RemoveItem(itemPosition);
889 Unlock();
890
891 return;
892}
893
894GUIHANDLE CAddonCallbacksGUI::Window_GetListItem(void *addonData, GUIHANDLE handle, int listPos)
895{
896 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
897 if (!helper || !handle)
898 return NULL;
899
900 CAddonCallbacksGUI* guiHelper = helper->GetHelperGUI();
901 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
902
903 Lock();
904 CFileItemPtr fi = pAddonWindow->GetListItem(listPos);
905 if (fi == NULL)
906 {
907 Unlock();
908 CLog::Log(LOGERROR, "Window_GetListItem: %s/%s - Index out of range", TranslateType(guiHelper->m_addon->Type()).c_str(), guiHelper->m_addon->Name().c_str());
909 return NULL;
910 }
911 Unlock();
912
913 return fi.get();
914}
915
916void CAddonCallbacksGUI::Window_SetCurrentListPosition(void *addonData, GUIHANDLE handle, int listPos)
917{
918 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
919 if (!helper || !handle)
920 return;
921
922 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
923
924 Lock();
925 pAddonWindow->SetCurrentListPosition(listPos);
926 Unlock();
927
928 return;
929}
930
931int CAddonCallbacksGUI::Window_GetCurrentListPosition(void *addonData, GUIHANDLE handle)
932{
933 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
934 if (!helper || !handle)
935 return -1;
936
937 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
938
939 Lock();
940 int listPos = pAddonWindow->GetCurrentListPosition();
941 Unlock();
942
943 return listPos;
944}
945
946GUIHANDLE CAddonCallbacksGUI::Window_GetControl_Spin(void *addonData, GUIHANDLE handle, int controlId)
947{
948 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
949 if (!helper || !handle)
950 return NULL;
951
952 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
953 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
954 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_SPINEX)
955 return NULL;
956
957 return pGUIControl;
958}
959
960GUIHANDLE CAddonCallbacksGUI::Window_GetControl_Button(void *addonData, GUIHANDLE handle, int controlId)
961{
962 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
963 if (!helper || !handle)
964 return NULL;
965
966 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
967 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
968 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_BUTTON)
969 return NULL;
970
971 return pGUIControl;
972}
973
974GUIHANDLE CAddonCallbacksGUI::Window_GetControl_RadioButton(void *addonData, GUIHANDLE handle, int controlId)
975{
976 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
977 if (!helper || !handle)
978 return NULL;
979
980 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
981 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
982 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_RADIO)
983 return NULL;
984
985 return pGUIControl;
986}
987
988GUIHANDLE CAddonCallbacksGUI::Window_GetControl_Edit(void *addonData, GUIHANDLE handle, int controlId)
989{
990 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
991 if (!helper || !handle)
992 return NULL;
993
994 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
995 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
996 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_EDIT)
997 return NULL;
998
999 return pGUIControl;
1000}
1001
1002GUIHANDLE CAddonCallbacksGUI::Window_GetControl_Progress(void *addonData, GUIHANDLE handle, int controlId)
1003{
1004 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1005 if (!helper || !handle)
1006 return NULL;
1007
1008 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
1009 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
1010 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_PROGRESS)
1011 return NULL;
1012
1013 return pGUIControl;
1014}
1015
1016GUIHANDLE CAddonCallbacksGUI::Window_GetControl_RenderAddon(void *addonData, GUIHANDLE handle, int controlId)
1017{
1018 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1019 if (!helper || !handle)
1020 return NULL;
1021
1022 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
1023 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
1024 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_RENDERADDON)
1025 return NULL;
1026
1027 CGUIAddonRenderingControl *pProxyControl;
1028 pProxyControl = new CGUIAddonRenderingControl((CGUIRenderingControl*)pGUIControl);
1029 return pProxyControl;
1030}
1031
1032void CAddonCallbacksGUI::Window_SetControlLabel(void *addonData, GUIHANDLE handle, int controlId, const char *label)
1033{
1034 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1035 if (!helper || !handle)
1036 return;
1037
1038 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
1039
1040 CGUIMessage msg(GUI_MSG_LABEL_SET, pAddonWindow->m_iWindowId, controlId);
1041 msg.SetLabel(label);
1042 pAddonWindow->OnMessage(msg);
1043}
1044
1045void CAddonCallbacksGUI::Window_MarkDirtyRegion(void *addonData, GUIHANDLE handle)
1046{
1047 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1048 if (!helper || !handle)
1049 return;
1050
1051 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
1052
1053 pAddonWindow->MarkDirtyRegion();
1054}
1055
1056void CAddonCallbacksGUI::Control_Spin_SetVisible(void *addonData, GUIHANDLE spinhandle, bool yesNo)
1057{
1058 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1059 if (!helper || !spinhandle)
1060 return;
1061
1062 CGUISpinControlEx *pSpin = (CGUISpinControlEx*)spinhandle;
1063 pSpin->SetVisible(yesNo);
1064}
1065
1066void CAddonCallbacksGUI::Control_Spin_SetText(void *addonData, GUIHANDLE spinhandle, const char *label)
1067{
1068 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1069 if (!helper || !spinhandle)
1070 return;
1071
1072 CGUISpinControlEx *pSpin = (CGUISpinControlEx*)spinhandle;
1073 pSpin->SetText(label);
1074}
1075
1076void CAddonCallbacksGUI::Control_Spin_Clear(void *addonData, GUIHANDLE spinhandle)
1077{
1078 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1079 if (!helper || !spinhandle)
1080 return;
1081
1082 CGUISpinControlEx *pSpin = (CGUISpinControlEx*)spinhandle;
1083 pSpin->Clear();
1084}
1085
1086void CAddonCallbacksGUI::Control_Spin_AddLabel(void *addonData, GUIHANDLE spinhandle, const char *label, int iValue)
1087{
1088 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1089 if (!helper || !spinhandle)
1090 return;
1091
1092 CGUISpinControlEx *pSpin = (CGUISpinControlEx*)spinhandle;
1093 pSpin->AddLabel(label, iValue);
1094}
1095
1096int CAddonCallbacksGUI::Control_Spin_GetValue(void *addonData, GUIHANDLE spinhandle)
1097{
1098 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1099 if (!helper || !spinhandle)
1100 return -1;
1101
1102 CGUISpinControlEx *pSpin = (CGUISpinControlEx*)spinhandle;
1103 return pSpin->GetValue();
1104}
1105
1106void CAddonCallbacksGUI::Control_Spin_SetValue(void *addonData, GUIHANDLE spinhandle, int iValue)
1107{
1108 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1109 if (!helper || !spinhandle)
1110 return;
1111
1112 CGUISpinControlEx *pSpin = (CGUISpinControlEx*)spinhandle;
1113 pSpin->SetValue(iValue);
1114}
1115
1116void CAddonCallbacksGUI::Control_RadioButton_SetVisible(void *addonData, GUIHANDLE handle, bool yesNo)
1117{
1118 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1119 if (!helper || !handle)
1120 return;
1121
1122 CGUIRadioButtonControl *pRadioButton = (CGUIRadioButtonControl*)handle;
1123 pRadioButton->SetVisible(yesNo);
1124}
1125
1126void CAddonCallbacksGUI::Control_RadioButton_SetText(void *addonData, GUIHANDLE handle, const char *label)
1127{
1128 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1129 if (!helper || !handle)
1130 return;
1131
1132 CGUIRadioButtonControl *pRadioButton = (CGUIRadioButtonControl*)handle;
1133 pRadioButton->SetLabel(label);
1134}
1135
1136void CAddonCallbacksGUI::Control_RadioButton_SetSelected(void *addonData, GUIHANDLE handle, bool yesNo)
1137{
1138 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1139 if (!helper || !handle)
1140 return;
1141
1142 CGUIRadioButtonControl *pRadioButton = (CGUIRadioButtonControl*)handle;
1143 pRadioButton->SetSelected(yesNo);
1144}
1145
1146bool CAddonCallbacksGUI::Control_RadioButton_IsSelected(void *addonData, GUIHANDLE handle)
1147{
1148 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1149 if (!helper || !handle)
1150 return false;
1151
1152 CGUIRadioButtonControl *pRadioButton = (CGUIRadioButtonControl*)handle;
1153 return pRadioButton->IsSelected();
1154}
1155
1156void CAddonCallbacksGUI::Control_Progress_SetPercentage(void *addonData, GUIHANDLE handle, float fPercent)
1157{
1158 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1159 if (!helper || !handle)
1160 return;
1161
1162 CGUIProgressControl *pControl = (CGUIProgressControl*)handle;
1163 pControl->SetPercentage(fPercent);
1164}
1165
1166float CAddonCallbacksGUI::Control_Progress_GetPercentage(void *addonData, GUIHANDLE handle)
1167{
1168 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1169 if (!helper || !handle)
1170 return 0.0;
1171
1172 CGUIProgressControl *pControl = (CGUIProgressControl*)handle;
1173 return pControl->GetPercentage();
1174}
1175
1176void CAddonCallbacksGUI::Control_Progress_SetInfo(void *addonData, GUIHANDLE handle, int iInfo)
1177{
1178 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1179 if (!helper || !handle)
1180 return;
1181
1182 CGUIProgressControl *pControl = (CGUIProgressControl*)handle;
1183 pControl->SetInfo(iInfo);
1184}
1185
1186int CAddonCallbacksGUI::Control_Progress_GetInfo(void *addonData, GUIHANDLE handle)
1187{
1188 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1189 if (!helper || !handle)
1190 return -1;
1191
1192 CGUIProgressControl *pControl = (CGUIProgressControl*)handle;
1193 return pControl->GetInfo();
1194}
1195
1196const char* CAddonCallbacksGUI::Control_Progress_GetDescription(void *addonData, GUIHANDLE handle)
1197{
1198 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1199 if (!helper || !handle)
1200 return NULL;
1201
1202 CGUIProgressControl *pControl = (CGUIProgressControl*)handle;
1203 std::string string = pControl->GetDescription();
1204
1205 char *buffer = (char*) malloc (string.length()+1);
1206 strcpy(buffer, string.c_str());
1207 return buffer;
1208}
1209
1210/*
1211 * GUI slider control callback functions
1212 */
1213GUIHANDLE CAddonCallbacksGUI::Window_GetControl_Slider(void *addonData, GUIHANDLE handle, int controlId)
1214{
1215 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1216 if (!helper || !handle)
1217 return NULL;
1218
1219 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
1220 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
1221 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_SLIDER)
1222 return NULL;
1223
1224 return pGUIControl;
1225}
1226
1227void CAddonCallbacksGUI::Control_Slider_SetVisible(void *addonData, GUIHANDLE handle, bool yesNo)
1228{
1229 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1230 if (!helper || !handle)
1231 return;
1232
1233 CGUIControl *pControl = (CGUIControl*)handle;
1234 pControl->SetVisible(yesNo);
1235}
1236
1237const char* CAddonCallbacksGUI::Control_Slider_GetDescription(void *addonData, GUIHANDLE handle)
1238{
1239 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1240 if (!helper || !handle)
1241 return NULL;
1242
1243 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1244 std::string string = pControl->GetDescription();
1245
1246 char *buffer = (char*) malloc (string.length()+1);
1247 strcpy(buffer, string.c_str());
1248 return buffer;
1249}
1250
1251void CAddonCallbacksGUI::Control_Slider_SetIntRange(void *addonData, GUIHANDLE handle, int iStart, int iEnd)
1252{
1253 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1254 if (!helper || !handle)
1255 return;
1256
1257 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1258 pControl->SetRange(iStart, iEnd);
1259}
1260
1261void CAddonCallbacksGUI::Control_Slider_SetIntValue(void *addonData, GUIHANDLE handle, int iValue)
1262{
1263 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1264 if (!helper || !handle)
1265 return;
1266
1267 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1268 pControl->SetType(SPIN_CONTROL_TYPE_INT);
1269 pControl->SetIntValue(iValue);
1270}
1271
1272int CAddonCallbacksGUI::Control_Slider_GetIntValue(void *addonData, GUIHANDLE handle)
1273{
1274 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1275 if (!helper || !handle)
1276 return 0;
1277
1278 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1279 return pControl->GetIntValue();
1280}
1281
1282void CAddonCallbacksGUI::Control_Slider_SetIntInterval(void *addonData, GUIHANDLE handle, int iInterval)
1283{
1284 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1285 if (!helper || !handle)
1286 return;
1287
1288 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1289 pControl->SetIntInterval(iInterval);
1290}
1291
1292void CAddonCallbacksGUI::Control_Slider_SetPercentage(void *addonData, GUIHANDLE handle, float fPercent)
1293{
1294 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1295 if (!helper || !handle)
1296 return;
1297
1298 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1299 pControl->SetType(SPIN_CONTROL_TYPE_FLOAT);
1300 pControl->SetPercentage(fPercent);
1301}
1302
1303float CAddonCallbacksGUI::Control_Slider_GetPercentage(void *addonData, GUIHANDLE handle)
1304{
1305 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1306 if (!helper || !handle)
1307 return 0.0f;
1308
1309 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1310 return pControl->GetPercentage();
1311}
1312
1313void CAddonCallbacksGUI::Control_Slider_SetFloatRange(void *addonData, GUIHANDLE handle, float fStart, float fEnd)
1314{
1315 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1316 if (!helper || !handle)
1317 return;
1318
1319 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1320 pControl->SetFloatRange(fStart, fEnd);
1321}
1322
1323void CAddonCallbacksGUI::Control_Slider_SetFloatValue(void *addonData, GUIHANDLE handle, float iValue)
1324{
1325 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1326 if (!helper || !handle)
1327 return;
1328
1329 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1330 pControl->SetType(SPIN_CONTROL_TYPE_FLOAT);
1331 pControl->SetFloatValue(iValue);
1332}
1333
1334float CAddonCallbacksGUI::Control_Slider_GetFloatValue(void *addonData, GUIHANDLE handle)
1335{
1336 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1337 if (!helper || !handle)
1338 return 0.0f;
1339
1340 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1341 return pControl->GetFloatValue();
1342}
1343
1344void CAddonCallbacksGUI::Control_Slider_SetFloatInterval(void *addonData, GUIHANDLE handle, float fInterval)
1345{
1346 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1347 if (!helper || !handle)
1348 return;
1349
1350 CGUISliderControl *pControl = (CGUISliderControl*)handle;
1351 pControl->SetFloatInterval(fInterval);
1352}
1353
1354/*
1355 * GUI settings slider control callback functions
1356 */
1357GUIHANDLE CAddonCallbacksGUI::Window_GetControl_SettingsSlider(void *addonData, GUIHANDLE handle, int controlId)
1358{
1359 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1360 if (!helper || !handle)
1361 return NULL;
1362
1363 CGUIAddonWindow *pAddonWindow = (CGUIAddonWindow*)handle;
1364 CGUIControl* pGUIControl = (CGUIControl*)pAddonWindow->GetControl(controlId);
1365 if (pGUIControl && pGUIControl->GetControlType() != CGUIControl::GUICONTROL_SETTINGS_SLIDER)
1366 return NULL;
1367
1368 return pGUIControl;
1369}
1370
1371void CAddonCallbacksGUI::Control_SettingsSlider_SetVisible(void *addonData, GUIHANDLE handle, bool yesNo)
1372{
1373 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1374 if (!helper || !handle)
1375 return;
1376
1377 CGUIControl *pControl = (CGUIControl*)handle;
1378 pControl->SetVisible(yesNo);
1379}
1380
1381void CAddonCallbacksGUI::Control_SettingsSlider_SetText(void *addonData, GUIHANDLE handle, const char *label)
1382{
1383 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1384 if (!helper || !handle)
1385 return;
1386
1387 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1388 pControl->SetText(label);
1389}
1390
1391const char* CAddonCallbacksGUI::Control_SettingsSlider_GetDescription(void *addonData, GUIHANDLE handle)
1392{
1393 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1394 if (!helper || !handle)
1395 return NULL;
1396
1397 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1398 std::string string = pControl->GetDescription();
1399
1400 char *buffer = (char*) malloc (string.length()+1);
1401 strcpy(buffer, string.c_str());
1402 return buffer;
1403}
1404
1405void CAddonCallbacksGUI::Control_SettingsSlider_SetIntRange(void *addonData, GUIHANDLE handle, int iStart, int iEnd)
1406{
1407 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1408 if (!helper || !handle)
1409 return;
1410
1411 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1412 pControl->SetRange(iStart, iEnd);
1413}
1414
1415void CAddonCallbacksGUI::Control_SettingsSlider_SetIntValue(void *addonData, GUIHANDLE handle, int iValue)
1416{
1417 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1418 if (!helper || !handle)
1419 return;
1420
1421 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1422 pControl->SetType(SPIN_CONTROL_TYPE_INT);
1423 pControl->SetIntValue(iValue);
1424}
1425
1426int CAddonCallbacksGUI::Control_SettingsSlider_GetIntValue(void *addonData, GUIHANDLE handle)
1427{
1428 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1429 if (!helper || !handle)
1430 return 0;
1431
1432 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1433 return pControl->GetIntValue();
1434}
1435
1436void CAddonCallbacksGUI::Control_SettingsSlider_SetIntInterval(void *addonData, GUIHANDLE handle, int iInterval)
1437{
1438 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1439 if (!helper || !handle)
1440 return;
1441
1442 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1443 pControl->SetIntInterval(iInterval);
1444}
1445
1446void CAddonCallbacksGUI::Control_SettingsSlider_SetPercentage(void *addonData, GUIHANDLE handle, float fPercent)
1447{
1448 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1449 if (!helper || !handle)
1450 return;
1451
1452 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1453 pControl->SetType(SPIN_CONTROL_TYPE_FLOAT);
1454 pControl->SetPercentage(fPercent);
1455}
1456
1457float CAddonCallbacksGUI::Control_SettingsSlider_GetPercentage(void *addonData, GUIHANDLE handle)
1458{
1459 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1460 if (!helper || !handle)
1461 return 0.0f;
1462
1463 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1464 return pControl->GetPercentage();
1465}
1466
1467void CAddonCallbacksGUI::Control_SettingsSlider_SetFloatRange(void *addonData, GUIHANDLE handle, float fStart, float fEnd)
1468{
1469 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1470 if (!helper || !handle)
1471 return;
1472
1473 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1474 pControl->SetFloatRange(fStart, fEnd);
1475}
1476
1477void CAddonCallbacksGUI::Control_SettingsSlider_SetFloatValue(void *addonData, GUIHANDLE handle, float fValue)
1478{
1479 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1480 if (!helper || !handle)
1481 return;
1482
1483 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1484 pControl->SetType(SPIN_CONTROL_TYPE_FLOAT);
1485 pControl->SetFloatValue(fValue);
1486}
1487
1488float CAddonCallbacksGUI::Control_SettingsSlider_GetFloatValue(void *addonData, GUIHANDLE handle)
1489{
1490 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1491 if (!helper || !handle)
1492 return 0.0f;
1493
1494 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1495 return pControl->GetFloatValue();
1496}
1497
1498void CAddonCallbacksGUI::Control_SettingsSlider_SetFloatInterval(void *addonData, GUIHANDLE handle, float fInterval)
1499{
1500 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1501 if (!helper || !handle)
1502 return;
1503
1504 CGUISettingsSliderControl *pControl = (CGUISettingsSliderControl*)handle;
1505 pControl->SetFloatInterval(fInterval);
1506}
1507
1508/*
1509 * GUI list item control callback functions
1510 */
1511GUIHANDLE CAddonCallbacksGUI::ListItem_Create(void *addonData, const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path)
1512{
1513 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1514 if (!helper)
1515 return NULL;
1516
1517 // create CFileItem
1518 CFileItem *pItem = new CFileItem();
1519 if (!pItem)
1520 return NULL;
1521
1522 if (label)
1523 pItem->SetLabel(label);
1524 if (label2)
1525 pItem->SetLabel2(label2);
1526 if (iconImage)
1527 pItem->SetIconImage(iconImage);
1528 if (thumbnailImage)
1529 pItem->SetArt("thumb", thumbnailImage);
1530 if (path)
1531 pItem->SetPath(path);
1532
1533 return pItem;
1534}
1535
1536const char* CAddonCallbacksGUI::ListItem_GetLabel(void *addonData, GUIHANDLE handle)
1537{
1538 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1539 if (!helper || !handle)
1540 return NULL;
1541
1542 std::string string = ((CFileItem*)handle)->GetLabel();
1543 char *buffer = (char*) malloc (string.length()+1);
1544 strcpy(buffer, string.c_str());
1545 return buffer;
1546}
1547
1548void CAddonCallbacksGUI::ListItem_SetLabel(void *addonData, GUIHANDLE handle, const char *label)
1549{
1550 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1551 if (!helper || !handle)
1552 return;
1553
1554 ((CFileItem*)handle)->SetLabel(label);
1555}
1556
1557const char* CAddonCallbacksGUI::ListItem_GetLabel2(void *addonData, GUIHANDLE handle)
1558{
1559 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1560 if (!helper || !handle)
1561 return NULL;
1562
1563 std::string string = ((CFileItem*)handle)->GetLabel2();
1564
1565 char *buffer = (char*) malloc (string.length()+1);
1566 strcpy(buffer, string.c_str());
1567 return buffer;
1568}
1569
1570void CAddonCallbacksGUI::ListItem_SetLabel2(void *addonData, GUIHANDLE handle, const char *label)
1571{
1572 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1573 if (!helper || !handle)
1574 return;
1575
1576 ((CFileItem*)handle)->SetLabel2(label);
1577}
1578
1579void CAddonCallbacksGUI::ListItem_SetIconImage(void *addonData, GUIHANDLE handle, const char *image)
1580{
1581 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1582 if (!helper || !handle)
1583 return;
1584
1585 ((CFileItem*)handle)->SetIconImage(image);
1586}
1587
1588void CAddonCallbacksGUI::ListItem_SetThumbnailImage(void *addonData, GUIHANDLE handle, const char *image)
1589{
1590 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1591 if (!helper || !handle)
1592 return;
1593
1594 ((CFileItem*)handle)->SetArt("thumb", image);
1595}
1596
1597void CAddonCallbacksGUI::ListItem_SetInfo(void *addonData, GUIHANDLE handle, const char *info)
1598{
1599 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1600 if (!helper || !handle)
1601 return;
1602
1603}
1604
1605void CAddonCallbacksGUI::ListItem_SetProperty(void *addonData, GUIHANDLE handle, const char *key, const char *value)
1606{
1607 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1608 if (!helper || !handle)
1609 return;
1610
1611 ((CFileItem*)handle)->SetProperty(key, value);
1612}
1613
1614const char* CAddonCallbacksGUI::ListItem_GetProperty(void *addonData, GUIHANDLE handle, const char *key)
1615{
1616 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1617 if (!helper || !handle)
1618 return NULL;
1619
1620 string string = ((CFileItem*)handle)->GetProperty(key).asString();
1621 char *buffer = (char*) malloc (string.length()+1);
1622 strcpy(buffer, string.c_str());
1623 return buffer;
1624}
1625
1626void CAddonCallbacksGUI::ListItem_SetPath(void *addonData, GUIHANDLE handle, const char *path)
1627{
1628 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1629 if (!helper || !handle)
1630 return;
1631
1632 ((CFileItem*)handle)->SetPath(path);
1633}
1634
1635void CAddonCallbacksGUI::RenderAddon_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,void*), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE))
1636{
1637 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1638 if (!helper || !handle)
1639 return;
1640
1641 CGUIAddonRenderingControl *pAddonControl = (CGUIAddonRenderingControl*)handle;
1642
1643 Lock();
1644 pAddonControl->m_clientHandle = clienthandle;
1645 pAddonControl->CBCreate = createCB;
1646 pAddonControl->CBRender = renderCB;
1647 pAddonControl->CBStop = stopCB;
1648 pAddonControl->CBDirty = dirtyCB;
1649 Unlock();
1650
1651 pAddonControl->m_pControl->InitCallback(pAddonControl);
1652}
1653
1654void CAddonCallbacksGUI::RenderAddon_Delete(void *addonData, GUIHANDLE handle)
1655{
1656 CAddonCallbacks* helper = (CAddonCallbacks*) addonData;
1657 if (!helper || !handle)
1658 return;
1659
1660 CGUIAddonRenderingControl *pAddonControl = (CGUIAddonRenderingControl*)handle;
1661
1662 Lock();
1663 pAddonControl->Delete();
1664 Unlock();
1665}
1666
1667/*! @name GUI Keyboard functions */
1668//@{
1669bool CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetInputWithHead(char &aTextString, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, bool hiddenInput, unsigned int autoCloseMs)
1670{
1671 std::string str = &aTextString;
1672 bool bRet = CGUIKeyboardFactory::ShowAndGetInput(str, strHeading, allowEmptyResult, hiddenInput, autoCloseMs);
1673 if (bRet)
1674 strncpy(&aTextString, str.c_str(), iMaxStringSize);
1675 return bRet;
1676}
1677
1678bool CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetInput(char &aTextString, unsigned int iMaxStringSize, bool allowEmptyResult, unsigned int autoCloseMs)
1679{
1680 std::string str = &aTextString;
1681 bool bRet = CGUIKeyboardFactory::ShowAndGetInput(str, allowEmptyResult, autoCloseMs);
1682 if (bRet)
1683 strncpy(&aTextString, str.c_str(), iMaxStringSize);
1684 return bRet;
1685}
1686
1687bool CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetNewPasswordWithHead(char &strNewPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, unsigned int autoCloseMs)
1688{
1689 std::string str = &strNewPassword;
1690 bool bRet = CGUIKeyboardFactory::ShowAndGetNewPassword(str, strHeading, allowEmptyResult, autoCloseMs);
1691 if (bRet)
1692 strncpy(&strNewPassword, str.c_str(), iMaxStringSize);
1693 return bRet;
1694}
1695
1696bool CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetNewPassword(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs)
1697{
1698 std::string str = &strNewPassword;
1699 bool bRet = CGUIKeyboardFactory::ShowAndGetNewPassword(str, autoCloseMs);
1700 if (bRet)
1701 strncpy(&strNewPassword, str.c_str(), iMaxStringSize);
1702 return bRet;
1703}
1704
1705bool CAddonCallbacksGUI::Dialog_Keyboard_ShowAndVerifyNewPasswordWithHead(char &strNewPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, unsigned int autoCloseMs)
1706{
1707 std::string str = &strNewPassword;
1708 bool bRet = CGUIKeyboardFactory::ShowAndVerifyNewPassword(str, strHeading, allowEmptyResult, autoCloseMs);
1709 if (bRet)
1710 strncpy(&strNewPassword, str.c_str(), iMaxStringSize);
1711 return bRet;
1712}
1713
1714bool CAddonCallbacksGUI::Dialog_Keyboard_ShowAndVerifyNewPassword(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs)
1715{
1716 std::string str = &strNewPassword;
1717 bool bRet = CGUIKeyboardFactory::ShowAndVerifyNewPassword(str, autoCloseMs);
1718 if (bRet)
1719 strncpy(&strNewPassword, str.c_str(), iMaxStringSize);
1720 return bRet;
1721}
1722
1723int CAddonCallbacksGUI::Dialog_Keyboard_ShowAndVerifyPassword(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries, unsigned int autoCloseMs)
1724{
1725 std::string str = &strPassword;
1726 int iRet = CGUIKeyboardFactory::ShowAndVerifyPassword(str, strHeading, iRetries, autoCloseMs);
1727 if (iRet)
1728 strncpy(&strPassword, str.c_str(), iMaxStringSize);
1729 return iRet;
1730}
1731
1732bool CAddonCallbacksGUI::Dialog_Keyboard_ShowAndGetFilter(char &aTextString, unsigned int iMaxStringSize, bool searching, unsigned int autoCloseMs)
1733{
1734 std::string strText = &aTextString;
1735 bool bRet = CGUIKeyboardFactory::ShowAndGetFilter(strText, searching, autoCloseMs);
1736 if (bRet)
1737 strncpy(&aTextString, strText.c_str(), iMaxStringSize);
1738 return bRet;
1739}
1740
1741bool CAddonCallbacksGUI::Dialog_Keyboard_SendTextToActiveKeyboard(const char *aTextString, bool closeKeyboard)
1742{
1743 return CGUIKeyboardFactory::SendTextToActiveKeyboard(aTextString, closeKeyboard);
1744}
1745
1746bool CAddonCallbacksGUI::Dialog_Keyboard_isKeyboardActivated()
1747{
1748 return CGUIKeyboardFactory::isKeyboardActivated();
1749}
1750//@}
1751
1752/*! @name GUI Numeric functions */
1753//@{
1754bool CAddonCallbacksGUI::Dialog_Numeric_ShowAndVerifyNewPassword(char &strNewPassword, unsigned int iMaxStringSize)
1755{
1756 std::string str = &strNewPassword;
1757 bool bRet = CGUIDialogNumeric::ShowAndVerifyNewPassword(str);
1758 if (bRet)
1759 strncpy(&strNewPassword, str.c_str(), iMaxStringSize);
1760 return bRet;
1761}
1762
1763int CAddonCallbacksGUI::Dialog_Numeric_ShowAndVerifyPassword(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries)
1764{
1765 std::string str = &strPassword;
1766 int bRet = CGUIDialogNumeric::ShowAndVerifyPassword(str, strHeading, iRetries);
1767 if (bRet)
1768 strncpy(&strPassword, str.c_str(), iMaxStringSize);
1769 return bRet;
1770}
1771
1772bool CAddonCallbacksGUI::Dialog_Numeric_ShowAndVerifyInput(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, bool bGetUserInput)
1773{
1774 std::string str = &strPassword;
1775 bool bRet = CGUIDialogNumeric::ShowAndVerifyInput(str, strHeading, bGetUserInput);
1776 if (bRet)
1777 strncpy(&strPassword, str.c_str(), iMaxStringSize);
1778 return bRet;
1779}
1780
1781bool CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetTime(tm &time, const char *strHeading)
1782{
1783 SYSTEMTIME systemTime;
1784 CDateTime dateTime(time);
1785 dateTime.GetAsSystemTime(systemTime);
1786 if (CGUIDialogNumeric::ShowAndGetTime(systemTime, strHeading))
1787 {
1788 dateTime = systemTime;
1789 dateTime.GetAsTm(time);
1790 return true;
1791 }
1792 return false;
1793}
1794
1795bool CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetDate(tm &date, const char *strHeading)
1796{
1797 SYSTEMTIME systemTime;
1798 CDateTime dateTime(date);
1799 dateTime.GetAsSystemTime(systemTime);
1800 if (CGUIDialogNumeric::ShowAndGetDate(systemTime, strHeading))
1801 {
1802 dateTime = systemTime;
1803 dateTime.GetAsTm(date);
1804 return true;
1805 }
1806 return false;
1807}
1808
1809bool CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetIPAddress(char &strIPAddress, unsigned int iMaxStringSize, const char *strHeading)
1810{
1811 std::string strIP = &strIPAddress;
1812 bool bRet = CGUIDialogNumeric::ShowAndGetIPAddress(strIP, strHeading);
1813 if (bRet)
1814 strncpy(&strIPAddress, strIP.c_str(), iMaxStringSize);
1815 return bRet;
1816}
1817
1818bool CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetNumber(char &strInput, unsigned int iMaxStringSize, const char *strHeading, unsigned int iAutoCloseTimeoutMs)
1819{
1820 std::string str = &strInput;
1821 bool bRet = CGUIDialogNumeric::ShowAndGetNumber(str, strHeading, iAutoCloseTimeoutMs);
1822 if (bRet)
1823 strncpy(&strInput, str.c_str(), iMaxStringSize);
1824 return bRet;
1825}
1826
1827bool CAddonCallbacksGUI::Dialog_Numeric_ShowAndGetSeconds(char &timeString, unsigned int iMaxStringSize, const char *strHeading)
1828{
1829 std::string str = &timeString;
1830 bool bRet = CGUIDialogNumeric::ShowAndGetSeconds(str, strHeading);
1831 if (bRet)
1832 strncpy(&timeString, str.c_str(), iMaxStringSize);
1833 return bRet;
1834}
1835//@}
1836
1837/*! @name GUI File browser functions */
1838//@{
1839bool CAddonCallbacksGUI::Dialog_FileBrowser_ShowAndGetFile(const char *directory, const char *mask, const char *heading, char &path, unsigned int iMaxStringSize, bool useThumbs, bool useFileDirectories, bool singleList)
1840{
1841 std::string strPath = &path;
1842 bool bRet = CGUIDialogFileBrowser::ShowAndGetFile(directory, mask, heading, strPath, useThumbs, useFileDirectories, singleList);
1843 if (bRet)
1844 strncpy(&path, strPath.c_str(), iMaxStringSize);
1845 return bRet;
1846}
1847//@}
1848
1849/*! @name GUI OK Dialog */
1850//@{
1851void CAddonCallbacksGUI::Dialog_OK_ShowAndGetInputSingleText(const char *heading, const char *text)
1852{
1853 CGUIDialogOK::ShowAndGetInput(heading, text);
1854}
1855
1856void CAddonCallbacksGUI::Dialog_OK_ShowAndGetInputLineText(const char *heading, const char *line0, const char *line1, const char *line2)
1857{
1858 CGUIDialogOK::ShowAndGetInput(heading, line0, line1, line2);
1859}
1860//@}
1861
1862/*! @name GUI Yes No Dialog */
1863//@{
1864bool CAddonCallbacksGUI::Dialog_YesNo_ShowAndGetInputSingleText(const char *heading, const char *text, bool& bCanceled, const char *noLabel, const char *yesLabel)
1865{
1866 return CGUIDialogYesNo::ShowAndGetInput(heading, text, bCanceled, noLabel, yesLabel);
1867}
1868
1869bool CAddonCallbacksGUI::Dialog_YesNo_ShowAndGetInputLineText(const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel, const char *yesLabel)
1870{
1871 return CGUIDialogYesNo::ShowAndGetInput(heading, line0, line1, line2, noLabel, yesLabel);
1872}
1873
1874bool CAddonCallbacksGUI::Dialog_YesNo_ShowAndGetInputLineButtonText(const char *heading, const char *line0, const char *line1, const char *line2, bool &bCanceled, const char *noLabel, const char *yesLabel)
1875{
1876 return CGUIDialogYesNo::ShowAndGetInput(heading, line0, line1, line2, bCanceled, noLabel, yesLabel);
1877}
1878//@}
1879
1880/*! @name GUI Text viewer Dialog */
1881//@{
1882void CAddonCallbacksGUI::Dialog_TextViewer(const char *heading, const char *text)
1883{
1884 CGUIDialogTextViewer* pDialog = (CGUIDialogTextViewer*)g_windowManager.GetWindow(WINDOW_DIALOG_TEXT_VIEWER);
1885 pDialog->SetHeading(heading);
1886 pDialog->SetText(text);
1887 pDialog->DoModal();
1888}
1889//@}
1890
1891/*! @name GUI select Dialog */
1892//@{
1893int CAddonCallbacksGUI::Dialog_Select(const char *heading, const char *entries[], unsigned int size, int selected)
1894{
1895 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1896 pDialog->Reset();
1897 pDialog->SetHeading(heading);
1898
1899 for (unsigned int i = 0; i < size; i++)
1900 pDialog->Add(entries[i]);
1901
1902 if (selected > 0)
1903 pDialog->SetSelected(selected);
1904
1905 pDialog->DoModal();
1906 return pDialog->GetSelectedLabel();
1907}
1908//@}
1909
1910CGUIAddonWindow::CGUIAddonWindow(int id, const std::string& strXML, CAddon* addon)
1911 : CGUIMediaWindow(id, strXML.c_str())
1912 , m_iWindowId(id)
1913 , m_iOldWindowId(0)
1914 , m_bModal(false)
1915 , m_bIsDialog(false)
1916 , m_actionEvent(true)
1917 , m_addon(addon)
1918{
1919 m_loadType = LOAD_ON_GUI_INIT;
1920 CBOnInit = NULL;
1921 CBOnFocus = NULL;
1922 CBOnClick = NULL;
1923 CBOnAction = NULL;
1924}
1925
1926CGUIAddonWindow::~CGUIAddonWindow(void)
1927{
1928}
1929
1930bool CGUIAddonWindow::OnAction(const CAction &action)
1931{
1932 // Let addon decide whether it wants to hande action first
1933 if (CBOnAction && CBOnAction(m_clientHandle, action.GetID()))
1934 return true;
1935
1936 return CGUIWindow::OnAction(action);
1937}
1938
1939bool CGUIAddonWindow::OnMessage(CGUIMessage& message)
1940{
1941 // TODO: We shouldn't be dropping down to CGUIWindow in any of this ideally.
1942 // We have to make up our minds about what python should be doing and
1943 // what this side of things should be doing
1944 switch (message.GetMessage())
1945 {
1946 case GUI_MSG_WINDOW_DEINIT:
1947 {
1948 return CGUIMediaWindow::OnMessage(message);
1949 }
1950 break;
1951
1952 case GUI_MSG_WINDOW_INIT:
1953 {
1954 CGUIMediaWindow::OnMessage(message);
1955 if (CBOnInit)
1956 CBOnInit(m_clientHandle);
1957
1958 return true;
1959 }
1960 break;
1961
1962 case GUI_MSG_SETFOCUS:
1963 {
1964 if (m_viewControl.HasControl(message.GetControlId()) && m_viewControl.GetCurrentControl() != (int)message.GetControlId())
1965 {
1966 m_viewControl.SetFocused();
1967 return true;
1968 }
1969 // check if our focused control is one of our category buttons
1970 int iControl = message.GetControlId();
1971 if (CBOnFocus)
1972 {
1973 CBOnFocus(m_clientHandle, iControl);
1974 }
1975 }
1976 break;
1977
1978 case GUI_MSG_FOCUSED:
1979 {
1980 if (HasID(message.GetSenderId()) && CBOnFocus)
1981 {
1982 CBOnFocus(m_clientHandle, message.GetControlId());
1983 }
1984 }
1985 break;
1986
1987 case GUI_MSG_CLICKED:
1988 {
1989 int iControl=message.GetSenderId();
1990 // Handle Sort/View internally. Scripters shouldn't use ID 2, 3 or 4.
1991 if (iControl == CONTROL_BTNSORTASC) // sort asc
1992 {
1993 CLog::Log(LOGINFO, "WindowXML: Internal asc/dsc button not implemented");
1994 /*if (m_guiState.get())
1995 m_guiState->SetNextSortOrder();
1996 UpdateFileList();*/
1997 return true;
1998 }
1999 else if (iControl == CONTROL_BTNSORTBY) // sort by
2000 {
2001 CLog::Log(LOGINFO, "WindowXML: Internal sort button not implemented");
2002 /*if (m_guiState.get())
2003 m_guiState->SetNextSortMethod();
2004 UpdateFileList();*/
2005 return true;
2006 }
2007
2008 if (CBOnClick && iControl && iControl != (int)this->GetID())
2009 {
2010 CGUIControl* controlClicked = (CGUIControl*)this->GetControl(iControl);
2011
2012 // The old python way used to check list AND SELECITEM method or if its a button, checkmark.
2013 // Its done this way for now to allow other controls without a python version like togglebutton to still raise a onAction event
2014 if (controlClicked) // Will get problems if we the id is not on the window and we try to do GetControlType on it. So check to make sure it exists
2015 {
2016 if ((controlClicked->IsContainer() && (message.GetParam1() == ACTION_SELECT_ITEM ||
2017 message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)) ||
2018 !controlClicked->IsContainer())
2019 {
2020 if (CBOnClick(m_clientHandle, iControl))
2021 return true;
2022 }
2023 else if (controlClicked->IsContainer() && message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK)
2024 {
2025// PyXBMCAction* inf = new PyXBMCAction;
2026// inf->pObject = Action_FromAction(CAction(ACTION_CONTEXT_MENU));
2027// inf->pCallbackWindow = pCallbackWindow;
2028//
2029// // aquire lock?
2030// PyXBMC_AddPendingCall(Py_XBMC_Event_OnAction, inf);
2031// PulseActionEvent();
2032 }
2033 }
2034 }
2035 }
2036 break;
2037 }
2038
2039 return CGUIMediaWindow::OnMessage(message);
2040}
2041
2042void CGUIAddonWindow::AllocResources(bool forceLoad /*= FALSE */)
2043{
2044 std::string tmpDir = URIUtils::GetDirectory(GetProperty("xmlfile").asString());
2045 std::string fallbackMediaPath;
2046 URIUtils::GetParentPath(tmpDir, fallbackMediaPath);
2047 URIUtils::RemoveSlashAtEnd(fallbackMediaPath);
2048 m_mediaDir = fallbackMediaPath;
2049
2050 //CLog::Log(LOGDEBUG, "CGUIPythonWindowXML::AllocResources called: %s", fallbackMediaPath.c_str());
2051 g_TextureManager.AddTexturePath(m_mediaDir);
2052 CGUIMediaWindow::AllocResources(forceLoad);
2053 g_TextureManager.RemoveTexturePath(m_mediaDir);
2054}
2055
2056void CGUIAddonWindow::FreeResources(bool forceUnLoad /*= FALSE */)
2057{
2058 CGUIMediaWindow::FreeResources(forceUnLoad);
2059}
2060
2061void CGUIAddonWindow::Render()
2062{
2063 g_TextureManager.AddTexturePath(m_mediaDir);
2064 CGUIMediaWindow::Render();
2065 g_TextureManager.RemoveTexturePath(m_mediaDir);
2066}
2067
2068void CGUIAddonWindow::Update()
2069{
2070}
2071
2072void CGUIAddonWindow::AddItem(CFileItemPtr fileItem, int itemPosition)
2073{
2074 if (itemPosition == -1 || itemPosition > m_vecItems->Size())
2075 {
2076 m_vecItems->Add(fileItem);
2077 }
2078 else if (itemPosition < -1 && !(itemPosition-1 < m_vecItems->Size()))
2079 {
2080 m_vecItems->AddFront(fileItem,0);
2081 }
2082 else
2083 {
2084 m_vecItems->AddFront(fileItem,itemPosition);
2085 }
2086 m_viewControl.SetItems(*m_vecItems);
2087 UpdateButtons();
2088}
2089
2090void CGUIAddonWindow::RemoveItem(int itemPosition)
2091{
2092 m_vecItems->Remove(itemPosition);
2093 m_viewControl.SetItems(*m_vecItems);
2094 UpdateButtons();
2095}
2096
2097int CGUIAddonWindow::GetCurrentListPosition()
2098{
2099 return m_viewControl.GetSelectedItem();
2100}
2101
2102void CGUIAddonWindow::SetCurrentListPosition(int item)
2103{
2104 m_viewControl.SetSelectedItem(item);
2105}
2106
2107int CGUIAddonWindow::GetListSize()
2108{
2109 return m_vecItems->Size();
2110}
2111
2112CFileItemPtr CGUIAddonWindow::GetListItem(int position)
2113{
2114 if (position < 0 || position >= m_vecItems->Size()) return CFileItemPtr();
2115 return m_vecItems->Get(position);
2116}
2117
2118void CGUIAddonWindow::ClearList()
2119{
2120 ClearFileItems();
2121
2122 m_viewControl.SetItems(*m_vecItems);
2123 UpdateButtons();
2124}
2125
2126void CGUIAddonWindow::GetContextButtons(int itemNumber, CContextButtons &buttons)
2127{
2128 // maybe on day we can make an easy way to do this context menu
2129 // with out this method overriding the MediaWindow version, it will display 'Add to Favorites'
2130}
2131
2132void CGUIAddonWindow::WaitForActionEvent(unsigned int timeout)
2133{
2134 m_actionEvent.WaitMSec(timeout);
2135 m_actionEvent.Reset();
2136}
2137
2138void CGUIAddonWindow::PulseActionEvent()
2139{
2140 m_actionEvent.Set();
2141}
2142
2143bool CGUIAddonWindow::OnClick(int iItem)
2144{
2145 // Hook Over calling CGUIMediaWindow::OnClick(iItem) results in it trying to PLAY the file item
2146 // which if its not media is BAD and 99 out of 100 times undesireable.
2147 return false;
2148}
2149
2150// SetupShares();
2151/*
2152 CGUIMediaWindow::OnWindowLoaded() calls SetupShares() so override it
2153and just call UpdateButtons();
2154*/
2155void CGUIAddonWindow::SetupShares()
2156{
2157 UpdateButtons();
2158}
2159
2160
2161CGUIAddonWindowDialog::CGUIAddonWindowDialog(int id, const std::string& strXML, CAddon* addon)
2162: CGUIAddonWindow(id,strXML,addon)
2163{
2164 m_bRunning = false;
2165 m_bIsDialog = true;
2166}
2167
2168CGUIAddonWindowDialog::~CGUIAddonWindowDialog(void)
2169{
2170}
2171
2172bool CGUIAddonWindowDialog::OnMessage(CGUIMessage &message)
2173{
2174 if (message.GetMessage() == GUI_MSG_WINDOW_DEINIT)
2175 {
2176 CGUIWindow *pWindow = g_windowManager.GetWindow(g_windowManager.GetActiveWindow());
2177 if (pWindow)
2178 g_windowManager.ShowOverlay(pWindow->GetOverlayState());
2179 return CGUIWindow::OnMessage(message);
2180 }
2181 return CGUIAddonWindow::OnMessage(message);
2182}
2183
2184void CGUIAddonWindowDialog::Show(bool show /* = true */)
2185{
2186 unsigned int iCount = g_graphicsContext.exit();
2187 ThreadMessage tMsg = {TMSG_GUI_ADDON_DIALOG, 1, show ? 1 : 0};
2188 tMsg.lpVoid = this;
2189 CApplicationMessenger::Get().SendMessage(tMsg, true);
2190 g_graphicsContext.restore(iCount);
2191}
2192
2193void CGUIAddonWindowDialog::Show_Internal(bool show /* = true */)
2194{
2195 if (show)
2196 {
2197 m_bModal = true;
2198 m_bRunning = true;
2199 g_windowManager.RouteToWindow(this);
2200
2201 // active this window...
2202 CGUIMessage msg(GUI_MSG_WINDOW_INIT, 0, 0, WINDOW_INVALID, m_iWindowId);
2203 OnMessage(msg);
2204
2205 // this dialog is derived from GUiMediaWindow
2206 // make sure it is rendered last
2207 m_renderOrder = 1;
2208 while (m_bRunning && !g_application.m_bStop)
2209 {
2210 g_windowManager.ProcessRenderLoop();
2211 }
2212 }
2213 else // hide
2214 {
2215 m_bRunning = false;
2216
2217 CGUIMessage msg(GUI_MSG_WINDOW_DEINIT,0,0);
2218 OnMessage(msg);
2219
2220 g_windowManager.RemoveDialog(GetID());
2221 }
2222}
2223
2224CGUIAddonRenderingControl::CGUIAddonRenderingControl(CGUIRenderingControl *pControl)
2225{
2226 m_pControl = pControl;
2227 m_refCount = 1;
2228}
2229
2230bool CGUIAddonRenderingControl::Create(int x, int y, int w, int h, void *device)
2231{
2232 if (CBCreate)
2233 {
2234 if (CBCreate(m_clientHandle, x, y, w, h, device))
2235 {
2236 m_refCount++;
2237 return true;
2238 }
2239 }
2240 return false;
2241}
2242
2243void CGUIAddonRenderingControl::Render()
2244{
2245 if (CBRender)
2246 {
2247 g_graphicsContext.BeginPaint();
2248 CBRender(m_clientHandle);
2249 g_graphicsContext.EndPaint();
2250 }
2251}
2252
2253void CGUIAddonRenderingControl::Stop()
2254{
2255 if (CBStop)
2256 {
2257 CBStop(m_clientHandle);
2258 }
2259 m_refCount--;
2260 if (m_refCount <= 0)
2261 delete this;
2262}
2263
2264void CGUIAddonRenderingControl::Delete()
2265{
2266 m_refCount--;
2267 if (m_refCount <= 0)
2268 delete this;
2269}
2270
2271bool CGUIAddonRenderingControl::IsDirty()
2272{
2273 bool ret = true;
2274 if (CBDirty)
2275 {
2276 ret = CBDirty(m_clientHandle);
2277 }
2278 return ret;
2279}
2280
2281}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonCallbacksGUI.h b/xbmc/addons/AddonCallbacksGUI.h
new file mode 100644
index 0000000..ae032a7
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksGUI.h
@@ -0,0 +1,272 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22
23#include "AddonCallbacks.h"
24#include "windows/GUIMediaWindow.h"
25#include "threads/Event.h"
26#include "guilib/IRenderingCallback.h"
27
28class CGUISpinControlEx;
29class CGUIButtonControl;
30class CGUIRadioButtonControl;
31class CGUISliderControl;
32class CGUISettingsSliderControl;
33class CGUIEditControl;
34class CGUIRenderingControl;
35
36namespace ADDON
37{
38
39class CAddonCallbacksGUI
40{
41public:
42 CAddonCallbacksGUI(CAddon* addon);
43 ~CAddonCallbacksGUI();
44
45 /**! \name General Functions */
46 CB_GUILib *GetCallbacks() { return m_callbacks; }
47
48 static void Lock();
49 static void Unlock();
50 static int GetScreenHeight();
51 static int GetScreenWidth();
52 static int GetVideoResolution();
53
54 static GUIHANDLE Window_New(void *addonData, const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog);
55 static void Window_Delete(void *addonData, GUIHANDLE handle);
56 static void Window_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*initCB)(GUIHANDLE), bool (*clickCB)(GUIHANDLE, int), bool (*focusCB)(GUIHANDLE, int), bool (*onActionCB)(GUIHANDLE handle, int));
57 static bool Window_Show(void *addonData, GUIHANDLE handle);
58 static bool Window_Close(void *addonData, GUIHANDLE handle);
59 static bool Window_DoModal(void *addonData, GUIHANDLE handle);
60 static bool Window_SetFocusId(void *addonData, GUIHANDLE handle, int iControlId);
61 static int Window_GetFocusId(void *addonData, GUIHANDLE handle);
62 static bool Window_SetCoordinateResolution(void *addonData, GUIHANDLE handle, int res);
63 static void Window_SetProperty(void *addonData, GUIHANDLE handle, const char *key, const char *value);
64 static void Window_SetPropertyInt(void *addonData, GUIHANDLE handle, const char *key, int value);
65 static void Window_SetPropertyBool(void *addonData, GUIHANDLE handle, const char *key, bool value);
66 static void Window_SetPropertyDouble(void *addonData, GUIHANDLE handle, const char *key, double value);
67 static const char * Window_GetProperty(void *addonData, GUIHANDLE handle, const char *key);
68 static int Window_GetPropertyInt(void *addonData, GUIHANDLE handle, const char *key);
69 static bool Window_GetPropertyBool(void *addonData, GUIHANDLE handle, const char *key);
70 static double Window_GetPropertyDouble(void *addonData, GUIHANDLE handle, const char *key);
71 static void Window_ClearProperties(void *addonData, GUIHANDLE handle);
72 static int Window_GetListSize(void *addonData, GUIHANDLE handle);
73 static void Window_ClearList(void *addonData, GUIHANDLE handle);
74 static GUIHANDLE Window_AddItem(void *addonData, GUIHANDLE handle, GUIHANDLE item, int itemPosition);
75 static GUIHANDLE Window_AddStringItem(void *addonData, GUIHANDLE handle, const char *itemName, int itemPosition);
76 static void Window_RemoveItem(void *addonData, GUIHANDLE handle, int itemPosition);
77 static GUIHANDLE Window_GetListItem(void *addonData, GUIHANDLE handle, int listPos);
78 static void Window_SetCurrentListPosition(void *addonData, GUIHANDLE handle, int listPos);
79 static int Window_GetCurrentListPosition(void *addonData, GUIHANDLE handle);
80 static GUIHANDLE Window_GetControl_Spin(void *addonData, GUIHANDLE handle, int controlId);
81 static GUIHANDLE Window_GetControl_Button(void *addonData, GUIHANDLE handle, int controlId);
82 static GUIHANDLE Window_GetControl_RadioButton(void *addonData, GUIHANDLE handle, int controlId);
83 static GUIHANDLE Window_GetControl_Edit(void *addonData, GUIHANDLE handle, int controlId);
84 static GUIHANDLE Window_GetControl_Progress(void *addonData, GUIHANDLE handle, int controlId);
85 static GUIHANDLE Window_GetControl_RenderAddon(void *addonData, GUIHANDLE handle, int controlId);
86 static void Window_SetControlLabel(void *addonData, GUIHANDLE handle, int controlId, const char *label);
87 static void Window_MarkDirtyRegion(void *addonData, GUIHANDLE handle);
88 static void Control_Spin_SetVisible(void *addonData, GUIHANDLE spinhandle, bool yesNo);
89 static void Control_Spin_SetText(void *addonData, GUIHANDLE spinhandle, const char *label);
90 static void Control_Spin_Clear(void *addonData, GUIHANDLE spinhandle);
91 static void Control_Spin_AddLabel(void *addonData, GUIHANDLE spinhandle, const char *label, int iValue);
92 static int Control_Spin_GetValue(void *addonData, GUIHANDLE spinhandle);
93 static void Control_Spin_SetValue(void *addonData, GUIHANDLE spinhandle, int iValue);
94 static void Control_RadioButton_SetVisible(void *addonData, GUIHANDLE handle, bool yesNo);
95 static void Control_RadioButton_SetText(void *addonData, GUIHANDLE handle, const char *label);
96 static void Control_RadioButton_SetSelected(void *addonData, GUIHANDLE handle, bool yesNo);
97 static bool Control_RadioButton_IsSelected(void *addonData, GUIHANDLE handle);
98 static void Control_Progress_SetPercentage(void *addonData, GUIHANDLE handle, float fPercent);
99 static float Control_Progress_GetPercentage(void *addonData, GUIHANDLE handle);
100 static void Control_Progress_SetInfo(void *addonData, GUIHANDLE handle, int iInfo);
101 static int Control_Progress_GetInfo(void *addonData, GUIHANDLE handle);
102 static const char * Control_Progress_GetDescription(void *addonData, GUIHANDLE handle);
103
104 static GUIHANDLE Window_GetControl_Slider(void *addonData, GUIHANDLE handle, int controlId);
105 static void Control_Slider_SetVisible(void *addonData, GUIHANDLE handle, bool yesNo);
106 static const char * Control_Slider_GetDescription(void *addonData, GUIHANDLE handle);
107 static void Control_Slider_SetIntRange(void *addonData, GUIHANDLE handle, int iStart, int iEnd);
108 static void Control_Slider_SetIntValue(void *addonData, GUIHANDLE handle, int iValue);
109 static int Control_Slider_GetIntValue(void *addonData, GUIHANDLE handle);
110 static void Control_Slider_SetIntInterval(void *addonData, GUIHANDLE handle, int iInterval);
111 static void Control_Slider_SetPercentage(void *addonData, GUIHANDLE handle, float fPercent);
112 static float Control_Slider_GetPercentage(void *addonData, GUIHANDLE handle);
113 static void Control_Slider_SetFloatRange(void *addonData, GUIHANDLE handle, float fStart, float fEnd);
114 static void Control_Slider_SetFloatValue(void *addonData, GUIHANDLE handle, float fValue);
115 static float Control_Slider_GetFloatValue(void *addonData, GUIHANDLE handle);
116 static void Control_Slider_SetFloatInterval(void *addonData, GUIHANDLE handle, float fInterval);
117
118 static GUIHANDLE Window_GetControl_SettingsSlider(void *addonData, GUIHANDLE handle, int controlId);
119 static void Control_SettingsSlider_SetVisible(void *addonData, GUIHANDLE handle, bool yesNo);
120 static void Control_SettingsSlider_SetText(void *addonData, GUIHANDLE handle, const char *label);
121 static const char * Control_SettingsSlider_GetDescription(void *addonData, GUIHANDLE handle);
122 static void Control_SettingsSlider_SetIntRange(void *addonData, GUIHANDLE handle, int iStart, int iEnd);
123 static void Control_SettingsSlider_SetIntValue(void *addonData, GUIHANDLE handle, int iValue);
124 static int Control_SettingsSlider_GetIntValue(void *addonData, GUIHANDLE handle);
125 static void Control_SettingsSlider_SetIntInterval(void *addonData, GUIHANDLE handle, int iInterval);
126 static void Control_SettingsSlider_SetPercentage(void *addonData, GUIHANDLE handle, float fPercent);
127 static float Control_SettingsSlider_GetPercentage(void *addonData, GUIHANDLE handle);
128 static void Control_SettingsSlider_SetFloatRange(void *addonData, GUIHANDLE handle, float fStart, float fEnd);
129 static void Control_SettingsSlider_SetFloatValue(void *addonData, GUIHANDLE handle, float fValue);
130 static float Control_SettingsSlider_GetFloatValue(void *addonData, GUIHANDLE handle);
131 static void Control_SettingsSlider_SetFloatInterval(void *addonData, GUIHANDLE handle, float fInterval);
132
133 static GUIHANDLE ListItem_Create(void *addonData, const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path);
134 static const char * ListItem_GetLabel(void *addonData, GUIHANDLE handle);
135 static void ListItem_SetLabel(void *addonData, GUIHANDLE handle, const char *label);
136 static const char * ListItem_GetLabel2(void *addonData, GUIHANDLE handle);
137 static void ListItem_SetLabel2(void *addonData, GUIHANDLE handle, const char *label);
138 static void ListItem_SetIconImage(void *addonData, GUIHANDLE handle, const char *image);
139 static void ListItem_SetThumbnailImage(void *addonData, GUIHANDLE handle, const char *image);
140 static void ListItem_SetInfo(void *addonData, GUIHANDLE handle, const char *info);
141 static void ListItem_SetProperty(void *addonData, GUIHANDLE handle, const char *key, const char *value);
142 static const char * ListItem_GetProperty(void *addonData, GUIHANDLE handle, const char *key);
143 static void ListItem_SetPath(void *addonData, GUIHANDLE handle, const char *path);
144 static void RenderAddon_SetCallbacks(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*createCB)(GUIHANDLE,int,int,int,int,void*), void (*renderCB)(GUIHANDLE), void (*stopCB)(GUIHANDLE), bool (*dirtyCB)(GUIHANDLE));
145 static void RenderAddon_Delete(void *addonData, GUIHANDLE handle);
146 static void RenderAddon_MarkDirty(void *addonData, GUIHANDLE handle);
147
148 static bool Dialog_Keyboard_ShowAndGetInput(char &aTextString, unsigned int iMaxStringSize, bool allowEmptyResult, unsigned int autoCloseMs);
149 static bool Dialog_Keyboard_ShowAndGetInputWithHead(char &aTextString, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, bool hiddenInput, unsigned int autoCloseMs);
150 static bool Dialog_Keyboard_ShowAndGetNewPassword(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs);
151 static bool Dialog_Keyboard_ShowAndGetNewPasswordWithHead(char &newPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, unsigned int autoCloseMs);
152 static bool Dialog_Keyboard_ShowAndVerifyNewPassword(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs);
153 static bool Dialog_Keyboard_ShowAndVerifyNewPasswordWithHead(char &strNewPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmpty, unsigned int autoCloseMs);
154 static int Dialog_Keyboard_ShowAndVerifyPassword(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries, unsigned int autoCloseMs);
155 static bool Dialog_Keyboard_ShowAndGetFilter(char &aTextString, unsigned int iMaxStringSize, bool searching, unsigned int autoCloseMs);
156 static bool Dialog_Keyboard_SendTextToActiveKeyboard(const char *aTextString, bool closeKeyboard);
157 static bool Dialog_Keyboard_isKeyboardActivated();
158
159 static bool Dialog_Numeric_ShowAndVerifyNewPassword(char &strNewPasswor, unsigned int iMaxStringSized);
160 static int Dialog_Numeric_ShowAndVerifyPassword(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries);
161 static bool Dialog_Numeric_ShowAndVerifyInput(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, bool bGetUserInput);
162 static bool Dialog_Numeric_ShowAndGetTime(tm &time, const char *strHeading);
163 static bool Dialog_Numeric_ShowAndGetDate(tm &date, const char *strHeading);
164 static bool Dialog_Numeric_ShowAndGetIPAddress(char &strIPAddress, unsigned int iMaxStringSize, const char *strHeading);
165 static bool Dialog_Numeric_ShowAndGetNumber(char &strInput, unsigned int iMaxStringSize, const char *strHeading, unsigned int iAutoCloseTimeoutMs);
166 static bool Dialog_Numeric_ShowAndGetSeconds(char &timeString, unsigned int iMaxStringSize, const char *strHeading);
167
168 static bool Dialog_FileBrowser_ShowAndGetFile(const char *directory, const char *mask, const char *heading, char &path, unsigned int iMaxStringSize, bool useThumbs, bool useFileDirectories, bool singleList);
169
170 static void Dialog_OK_ShowAndGetInputSingleText(const char *heading, const char *text);
171 static void Dialog_OK_ShowAndGetInputLineText(const char *heading, const char *line0, const char *line1, const char *line2);
172
173 static bool Dialog_YesNo_ShowAndGetInputSingleText(const char *heading, const char *text, bool& bCanceled, const char *noLabel, const char *yesLabel);
174 static bool Dialog_YesNo_ShowAndGetInputLineText(const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel, const char *yesLabel);
175 static bool Dialog_YesNo_ShowAndGetInputLineButtonText(const char *heading, const char *line0, const char *line1, const char *line2, bool &bCanceled, const char *noLabel, const char *yesLabel);
176
177 static void Dialog_TextViewer(const char *heading, const char *text);
178 static int Dialog_Select(const char *heading, const char *entries[], unsigned int size, int selected);
179
180private:
181 CB_GUILib *m_callbacks;
182 CAddon *m_addon;
183};
184
185class CGUIAddonWindow : public CGUIMediaWindow
186{
187friend class CAddonCallbacksGUI;
188
189public:
190 CGUIAddonWindow(int id, const std::string& strXML, CAddon* addon);
191 virtual ~CGUIAddonWindow(void);
192
193 virtual bool OnMessage(CGUIMessage& message);
194 virtual bool OnAction(const CAction &action);
195 virtual void AllocResources(bool forceLoad = false);
196 virtual void FreeResources(bool forceUnLoad = false);
197 virtual void Render();
198 void WaitForActionEvent(unsigned int timeout);
199 void PulseActionEvent();
200 void AddItem(CFileItemPtr fileItem, int itemPosition);
201 void RemoveItem(int itemPosition);
202 void ClearList();
203 CFileItemPtr GetListItem(int position);
204 int GetListSize();
205 int GetCurrentListPosition();
206 void SetCurrentListPosition(int item);
207 virtual bool OnClick(int iItem);
208
209protected:
210 virtual void Update();
211 virtual void GetContextButtons(int itemNumber, CContextButtons &buttons);
212 void SetupShares();
213
214 bool (*CBOnInit)(GUIHANDLE cbhdl);
215 bool (*CBOnFocus)(GUIHANDLE cbhdl, int controlId);
216 bool (*CBOnClick)(GUIHANDLE cbhdl, int controlId);
217 bool (*CBOnAction)(GUIHANDLE cbhdl, int);
218
219 GUIHANDLE m_clientHandle;
220 const int m_iWindowId;
221 int m_iOldWindowId;
222 bool m_bModal;
223 bool m_bIsDialog;
224
225private:
226 CEvent m_actionEvent;
227 CAddon *m_addon;
228 std::string m_mediaDir;
229};
230
231class CGUIAddonWindowDialog : public CGUIAddonWindow
232{
233public:
234 CGUIAddonWindowDialog(int id, const std::string& strXML, CAddon* addon);
235 virtual ~CGUIAddonWindowDialog(void);
236
237 void Show(bool show = true);
238 virtual bool OnMessage(CGUIMessage &message);
239 virtual bool IsDialogRunning() const { return m_bRunning; }
240 virtual bool IsDialog() const { return true;};
241 virtual bool IsModalDialog() const { return true; };
242 virtual bool IsMediaWindow() const { return false; };
243
244 void Show_Internal(bool show = true);
245
246private:
247 bool m_bRunning;
248};
249
250class CGUIAddonRenderingControl : public IRenderingCallback
251{
252friend class CAddonCallbacksGUI;
253public:
254 CGUIAddonRenderingControl(CGUIRenderingControl *pControl);
255 virtual ~CGUIAddonRenderingControl() {}
256 virtual bool Create(int x, int y, int w, int h, void *device);
257 virtual void Render();
258 virtual void Stop();
259 virtual bool IsDirty();
260 virtual void Delete();
261protected:
262 bool (*CBCreate) (GUIHANDLE cbhdl, int x, int y, int w, int h, void *device);
263 void (*CBRender)(GUIHANDLE cbhdl);
264 void (*CBStop)(GUIHANDLE cbhdl);
265 bool (*CBDirty)(GUIHANDLE cbhdl);
266
267 GUIHANDLE m_clientHandle;
268 CGUIRenderingControl *m_pControl;
269 int m_refCount;
270};
271
272}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonCallbacksPVR.cpp b/xbmc/addons/AddonCallbacksPVR.cpp
new file mode 100644
index 0000000..1d769e1
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksPVR.cpp
@@ -0,0 +1,324 @@
1/*
2 * Copyright (C) 2012-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Application.h"
22#include "AddonCallbacksPVR.h"
23#include "settings/AdvancedSettings.h"
24#include "utils/log.h"
25#include "utils/StringUtils.h"
26#include "dialogs/GUIDialogKaiToast.h"
27
28#include "epg/EpgContainer.h"
29#include "pvr/PVRManager.h"
30#include "pvr/channels/PVRChannelGroupsContainer.h"
31#include "pvr/channels/PVRChannelGroupInternal.h"
32#include "pvr/addons/PVRClient.h"
33#include "pvr/recordings/PVRRecordings.h"
34#include "pvr/timers/PVRTimers.h"
35#include "pvr/timers/PVRTimerInfoTag.h"
36
37using namespace PVR;
38using namespace EPG;
39
40namespace ADDON
41{
42
43CAddonCallbacksPVR::CAddonCallbacksPVR(CAddon* addon)
44{
45 m_addon = addon;
46 m_callbacks = new CB_PVRLib;
47
48 /* write XBMC PVR specific add-on function addresses to callback table */
49 m_callbacks->TransferEpgEntry = PVRTransferEpgEntry;
50 m_callbacks->TransferChannelEntry = PVRTransferChannelEntry;
51 m_callbacks->TransferTimerEntry = PVRTransferTimerEntry;
52 m_callbacks->TransferRecordingEntry = PVRTransferRecordingEntry;
53 m_callbacks->AddMenuHook = PVRAddMenuHook;
54 m_callbacks->Recording = PVRRecording;
55 m_callbacks->TriggerChannelUpdate = PVRTriggerChannelUpdate;
56 m_callbacks->TriggerChannelGroupsUpdate = PVRTriggerChannelGroupsUpdate;
57 m_callbacks->TriggerTimerUpdate = PVRTriggerTimerUpdate;
58 m_callbacks->TriggerRecordingUpdate = PVRTriggerRecordingUpdate;
59 m_callbacks->TriggerEpgUpdate = PVRTriggerEpgUpdate;
60 m_callbacks->FreeDemuxPacket = PVRFreeDemuxPacket;
61 m_callbacks->AllocateDemuxPacket = PVRAllocateDemuxPacket;
62 m_callbacks->TransferChannelGroup = PVRTransferChannelGroup;
63 m_callbacks->TransferChannelGroupMember = PVRTransferChannelGroupMember;
64}
65
66CAddonCallbacksPVR::~CAddonCallbacksPVR()
67{
68 /* delete the callback table */
69 delete m_callbacks;
70}
71
72CPVRClient *CAddonCallbacksPVR::GetPVRClient(void *addonData)
73{
74 CAddonCallbacks *addon = static_cast<CAddonCallbacks *>(addonData);
75 if (!addon || !addon->GetHelperPVR())
76 {
77 CLog::Log(LOGERROR, "PVR - %s - called with a null pointer", __FUNCTION__);
78 return NULL;
79 }
80
81 return dynamic_cast<CPVRClient *>(addon->GetHelperPVR()->m_addon);
82}
83
84void CAddonCallbacksPVR::PVRTransferChannelGroup(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group)
85{
86 if (!handle)
87 {
88 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
89 return;
90 }
91
92 CPVRChannelGroups *xbmcGroups = static_cast<CPVRChannelGroups *>(handle->dataAddress);
93 if (!group || !xbmcGroups)
94 {
95 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
96 return;
97 }
98
99 if (strlen(group->strGroupName) == 0)
100 {
101 CLog::Log(LOGERROR, "PVR - %s - empty group name", __FUNCTION__);
102 return;
103 }
104
105 /* transfer this entry to the groups container */
106 CPVRChannelGroup transferGroup(*group);
107 xbmcGroups->UpdateFromClient(transferGroup);
108}
109
110void CAddonCallbacksPVR::PVRTransferChannelGroupMember(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member)
111{
112 if (!handle)
113 {
114 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
115 return;
116 }
117
118 CPVRClient *client = GetPVRClient(addonData);
119 CPVRChannelGroup *group = static_cast<CPVRChannelGroup *>(handle->dataAddress);
120 if (!member || !client || !group)
121 {
122 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
123 return;
124 }
125
126 CPVRChannelPtr channel = g_PVRChannelGroups->GetByUniqueID(member->iChannelUniqueId, client->GetID());
127 if (!channel)
128 {
129 CLog::Log(LOGERROR, "PVR - %s - cannot find group '%s' or channel '%d'", __FUNCTION__, member->strGroupName, member->iChannelUniqueId);
130 }
131 else if (group->IsRadio() == channel->IsRadio())
132 {
133 /* transfer this entry to the group */
134 group->AddToGroup(channel, member->iChannelNumber);
135 }
136}
137
138void CAddonCallbacksPVR::PVRTransferEpgEntry(void *addonData, const ADDON_HANDLE handle, const EPG_TAG *epgentry)
139{
140 if (!handle)
141 {
142 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
143 return;
144 }
145
146 CEpg *xbmcEpg = static_cast<CEpg *>(handle->dataAddress);
147 if (!xbmcEpg)
148 {
149 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
150 return;
151 }
152
153 /* transfer this entry to the epg */
154 xbmcEpg->UpdateEntry(epgentry, handle->dataIdentifier == 1 /* update db */);
155}
156
157void CAddonCallbacksPVR::PVRTransferChannelEntry(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL *channel)
158{
159 if (!handle)
160 {
161 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
162 return;
163 }
164
165 CPVRClient *client = GetPVRClient(addonData);
166 CPVRChannelGroupInternal *xbmcChannels = static_cast<CPVRChannelGroupInternal *>(handle->dataAddress);
167 if (!channel || !client || !xbmcChannels)
168 {
169 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
170 return;
171 }
172
173 /* transfer this entry to the internal channels group */
174 CPVRChannelPtr transferChannel(new CPVRChannel(*channel, client->GetID()));
175 xbmcChannels->UpdateFromClient(transferChannel);
176}
177
178void CAddonCallbacksPVR::PVRTransferRecordingEntry(void *addonData, const ADDON_HANDLE handle, const PVR_RECORDING *recording)
179{
180 if (!handle)
181 {
182 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
183 return;
184 }
185
186 CPVRClient *client = GetPVRClient(addonData);
187 CPVRRecordings *xbmcRecordings = static_cast<CPVRRecordings *>(handle->dataAddress);
188 if (!recording || !client || !xbmcRecordings)
189 {
190 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
191 return;
192 }
193
194 /* transfer this entry to the recordings container */
195 CPVRRecordingPtr transferRecording(new CPVRRecording(*recording, client->GetID()));
196 xbmcRecordings->UpdateFromClient(transferRecording);
197}
198
199void CAddonCallbacksPVR::PVRTransferTimerEntry(void *addonData, const ADDON_HANDLE handle, const PVR_TIMER *timer)
200{
201 if (!handle)
202 {
203 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
204 return;
205 }
206
207 CPVRClient *client = GetPVRClient(addonData);
208 CPVRTimers *xbmcTimers = static_cast<CPVRTimers *>(handle->dataAddress);
209 if (!timer || !client || !xbmcTimers)
210 {
211 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
212 return;
213 }
214
215 CPVRChannelPtr channel = g_PVRChannelGroups->GetByUniqueID(timer->iClientChannelUid, client->GetID());
216 if (!channel)
217 {
218 CLog::Log(LOGERROR, "PVR - %s - cannot find channel %d on client %d", __FUNCTION__, timer->iClientChannelUid, client->GetID());
219 return;
220 }
221
222 /* transfer this entry to the timers container */
223 CPVRTimerInfoTag transferTimer(*timer, channel, client->GetID());
224 xbmcTimers->UpdateFromClient(transferTimer);
225}
226
227void CAddonCallbacksPVR::PVRAddMenuHook(void *addonData, PVR_MENUHOOK *hook)
228{
229 CPVRClient *client = GetPVRClient(addonData);
230 if (!hook || !client)
231 {
232 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
233 return;
234 }
235
236 PVR_MENUHOOKS *hooks = client->GetMenuHooks();
237 if (hooks)
238 {
239 PVR_MENUHOOK hookInt;
240 hookInt.iHookId = hook->iHookId;
241 hookInt.iLocalizedStringId = hook->iLocalizedStringId;
242 hookInt.category = hook->category;
243
244 /* add this new hook */
245 hooks->push_back(hookInt);
246 }
247}
248
249void CAddonCallbacksPVR::PVRRecording(void *addonData, const char *strName, const char *strFileName, bool bOnOff)
250{
251 CPVRClient *client = GetPVRClient(addonData);
252 if (!client || !strFileName)
253 {
254 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
255 return;
256 }
257
258 std::string strLine1;
259 if (bOnOff)
260 strLine1 = StringUtils::Format(g_localizeStrings.Get(19197).c_str(), client->Name().c_str());
261 else
262 strLine1 = StringUtils::Format(g_localizeStrings.Get(19198).c_str(), client->Name().c_str());
263
264 std::string strLine2;
265 if (strName)
266 strLine2 = strName;
267 else if (strFileName)
268 strLine2 = strFileName;
269
270 /* display a notification for 5 seconds */
271 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, strLine1, strLine2, 5000, false);
272
273 CLog::Log(LOGDEBUG, "PVR - %s - recording %s on client '%s'. name='%s' filename='%s'",
274 __FUNCTION__, bOnOff ? "started" : "finished", client->Name().c_str(), strName, strFileName);
275}
276
277void CAddonCallbacksPVR::PVRTriggerChannelUpdate(void *addonData)
278{
279 /* update the channels table in the next iteration of the pvrmanager's main loop */
280 g_PVRManager.TriggerChannelsUpdate();
281}
282
283void CAddonCallbacksPVR::PVRTriggerTimerUpdate(void *addonData)
284{
285 /* update the timers table in the next iteration of the pvrmanager's main loop */
286 g_PVRManager.TriggerTimersUpdate();
287}
288
289void CAddonCallbacksPVR::PVRTriggerRecordingUpdate(void *addonData)
290{
291 /* update the recordings table in the next iteration of the pvrmanager's main loop */
292 g_PVRManager.TriggerRecordingsUpdate();
293}
294
295void CAddonCallbacksPVR::PVRTriggerChannelGroupsUpdate(void *addonData)
296{
297 /* update all channel groups in the next iteration of the pvrmanager's main loop */
298 g_PVRManager.TriggerChannelGroupsUpdate();
299}
300
301void CAddonCallbacksPVR::PVRTriggerEpgUpdate(void *addonData, unsigned int iChannelUid)
302{
303 // get the client
304 CPVRClient *client = GetPVRClient(addonData);
305 if (!client)
306 {
307 CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__);
308 return;
309 }
310
311 g_EpgContainer.UpdateRequest(client->GetID(), iChannelUid);
312}
313
314void CAddonCallbacksPVR::PVRFreeDemuxPacket(void *addonData, DemuxPacket* pPacket)
315{
316 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
317}
318
319DemuxPacket* CAddonCallbacksPVR::PVRAllocateDemuxPacket(void *addonData, int iDataSize)
320{
321 return CDVDDemuxUtils::AllocateDemuxPacket(iDataSize);
322}
323
324}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonCallbacksPVR.h b/xbmc/addons/AddonCallbacksPVR.h
new file mode 100644
index 0000000..3fa48ec
--- /dev/null
+++ b/xbmc/addons/AddonCallbacksPVR.h
@@ -0,0 +1,166 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "AddonCallbacks.h"
23#include "include/xbmc_pvr_types.h"
24
25namespace PVR
26{
27 class CPVRClient;
28}
29
30namespace ADDON
31{
32
33/*!
34 * Callbacks for a PVR add-on to XBMC.
35 *
36 * Also translates the addon's C structures to XBMC's C++ structures.
37 */
38class CAddonCallbacksPVR
39{
40public:
41 CAddonCallbacksPVR(CAddon* addon);
42 ~CAddonCallbacksPVR(void);
43
44 /*!
45 * @return The callback table.
46 */
47 CB_PVRLib *GetCallbacks() { return m_callbacks; }
48
49 /*!
50 * @brief Transfer a channel group from the add-on to XBMC. The group will be created if it doesn't exist.
51 * @param addonData A pointer to the add-on.
52 * @param handle The handle parameter that XBMC used when requesting the channel groups list
53 * @param entry The entry to transfer to XBMC
54 */
55 static void PVRTransferChannelGroup(void* addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP* entry);
56
57 /*!
58 * @brief Transfer a channel group member entry from the add-on to XBMC. The channel will be added to the group if the group can be found.
59 * @param addonData A pointer to the add-on.
60 * @param handle The handle parameter that XBMC used when requesting the channel group members list
61 * @param entry The entry to transfer to XBMC
62 */
63 static void PVRTransferChannelGroupMember(void* addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER* entry);
64
65 /*!
66 * @brief Transfer an EPG tag from the add-on to XBMC
67 * @param addonData A pointer to the add-on.
68 * @param handle The handle parameter that XBMC used when requesting the EPG data
69 * @param entry The entry to transfer to XBMC
70 */
71 static void PVRTransferEpgEntry(void* addonData, const ADDON_HANDLE handle, const EPG_TAG* entry);
72
73 /*!
74 * @brief Transfer a channel entry from the add-on to XBMC
75 * @param addonData A pointer to the add-on.
76 * @param handle The handle parameter that XBMC used when requesting the channel list
77 * @param entry The entry to transfer to XBMC
78 */
79 static void PVRTransferChannelEntry(void* addonData, const ADDON_HANDLE handle, const PVR_CHANNEL* entry);
80
81 /*!
82 * @brief Transfer a timer entry from the add-on to XBMC
83 * @param addonData A pointer to the add-on.
84 * @param handle The handle parameter that XBMC used when requesting the timers list
85 * @param entry The entry to transfer to XBMC
86 */
87 static void PVRTransferTimerEntry(void* addonData, const ADDON_HANDLE handle, const PVR_TIMER* entry);
88
89 /*!
90 * @brief Transfer a recording entry from the add-on to XBMC
91 * @param addonData A pointer to the add-on.
92 * @param handle The handle parameter that XBMC used when requesting the recordings list
93 * @param entry The entry to transfer to XBMC
94 */
95 static void PVRTransferRecordingEntry(void* addonData, const ADDON_HANDLE handle, const PVR_RECORDING* entry);
96
97 /*!
98 * @brief Add or replace a menu hook for the context menu for this add-on
99 * @param addonData A pointer to the add-on.
100 * @param hook The hook to add.
101 */
102 static void PVRAddMenuHook(void* addonData, PVR_MENUHOOK* hook);
103
104 /*!
105 * @brief Display a notification in XBMC that a recording started or stopped on the server
106 * @param addonData A pointer to the add-on.
107 * @param strName The name of the recording to display
108 * @param strFileName The filename of the recording
109 * @param bOnOff True when recording started, false when it stopped
110 */
111 static void PVRRecording(void* addonData, const char* strName, const char* strFileName, bool bOnOff);
112
113 /*!
114 * @brief Request XBMC to update it's list of channels
115 * @param addonData A pointer to the add-on.
116 */
117 static void PVRTriggerChannelUpdate(void* addonData);
118
119 /*!
120 * @brief Request XBMC to update it's list of timers
121 * @param addonData A pointer to the add-on.
122 */
123 static void PVRTriggerTimerUpdate(void* addonData);
124
125 /*!
126 * @brief Request XBMC to update it's list of recordings
127 * @param addonData A pointer to the add-on.
128 */
129 static void PVRTriggerRecordingUpdate(void* addonData);
130
131 /*!
132 * @brief Request XBMC to update it's list of channel groups
133 * @param addonData A pointer to the add-on.
134 */
135 static void PVRTriggerChannelGroupsUpdate(void* addonData);
136
137 /*!
138 * @brief Schedule an EPG update for the given channel channel
139 * @param addonData A pointer to the add-on
140 * @param iChannelUid The unique id of the channel for this add-on
141 */
142 static void PVRTriggerEpgUpdate(void* addonData, unsigned int iChannelUid);
143
144 /*!
145 * @brief Free a packet that was allocated with AllocateDemuxPacket
146 * @param addonData A pointer to the add-on.
147 * @param pPacket The packet to free.
148 */
149 static void PVRFreeDemuxPacket(void* addonData, DemuxPacket* pPacket);
150
151 /*!
152 * @brief Allocate a demux packet. Free with FreeDemuxPacket
153 * @param addonData A pointer to the add-on.
154 * @param iDataSize The size of the data that will go into the packet
155 * @return The allocated packet.
156 */
157 static DemuxPacket* PVRAllocateDemuxPacket(void* addonData, int iDataSize = 0);
158
159private:
160 static PVR::CPVRClient* GetPVRClient(void* addonData);
161
162 CB_PVRLib *m_callbacks; /*!< callback addresses */
163 CAddon *m_addon; /*!< the addon */
164};
165
166}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonDatabase.cpp b/xbmc/addons/AddonDatabase.cpp
new file mode 100644
index 0000000..69b47ea
--- /dev/null
+++ b/xbmc/addons/AddonDatabase.cpp
@@ -0,0 +1,797 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "AddonDatabase.h"
22#include "addons/AddonManager.h"
23#include "utils/log.h"
24#include "utils/Variant.h"
25#include "utils/StringUtils.h"
26#include "XBDateTime.h"
27#include "dbwrappers/dataset.h"
28#include "addons/ContextItemAddon.h"
29
30using namespace ADDON;
31using namespace std;
32
33CAddonDatabase::CAddonDatabase()
34{
35}
36
37CAddonDatabase::~CAddonDatabase()
38{
39}
40
41bool CAddonDatabase::Open()
42{
43 return CDatabase::Open();
44}
45
46void CAddonDatabase::CreateTables()
47{
48 CLog::Log(LOGINFO, "create addon table");
49 m_pDS->exec("CREATE TABLE addon (id integer primary key, type text,"
50 "name text, summary text, description text, stars integer,"
51 "path text, addonID text, icon text, version text, "
52 "changelog text, fanart text, author text, disclaimer text,"
53 "minversion text)\n");
54
55 CLog::Log(LOGINFO, "create addonextra table");
56 m_pDS->exec("CREATE TABLE addonextra (id integer, key text, value text)\n");
57
58 CLog::Log(LOGINFO, "create dependencies table");
59 m_pDS->exec("CREATE TABLE dependencies (id integer, addon text, version text, optional boolean)\n");
60
61 CLog::Log(LOGINFO, "create repo table");
62 m_pDS->exec("CREATE TABLE repo (id integer primary key, addonID text,"
63 "checksum text, lastcheck text, version text)\n");
64
65 CLog::Log(LOGINFO, "create addonlinkrepo table");
66 m_pDS->exec("CREATE TABLE addonlinkrepo (idRepo integer, idAddon integer)\n");
67
68 CLog::Log(LOGINFO, "create disabled table");
69 m_pDS->exec("CREATE TABLE disabled (id integer primary key, addonID text)\n");
70
71 CLog::Log(LOGINFO, "create broken table");
72 m_pDS->exec("CREATE TABLE broken (id integer primary key, addonID text, reason text)\n");
73
74 CLog::Log(LOGINFO, "create blacklist table");
75 m_pDS->exec("CREATE TABLE blacklist (id integer primary key, addonID text, version text)\n");
76
77 CLog::Log(LOGINFO, "create package table");
78 m_pDS->exec("CREATE TABLE package (id integer primary key, addonID text, filename text, hash text)\n");
79}
80
81void CAddonDatabase::CreateAnalytics()
82{
83 CLog::Log(LOGINFO, "%s creating indicies", __FUNCTION__);
84 m_pDS->exec("CREATE INDEX idxAddon ON addon(addonID)");
85 m_pDS->exec("CREATE INDEX idxAddonExtra ON addonextra(id)");
86 m_pDS->exec("CREATE INDEX idxDependencies ON dependencies(id)");
87 m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_1 ON addonlinkrepo ( idAddon, idRepo )\n");
88 m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_2 ON addonlinkrepo ( idRepo, idAddon )\n");
89 m_pDS->exec("CREATE UNIQUE INDEX idxDisabled ON disabled(addonID)");
90 m_pDS->exec("CREATE UNIQUE INDEX idxBroken ON broken(addonID)");
91 m_pDS->exec("CREATE UNIQUE INDEX idxBlack ON blacklist(addonID)");
92 m_pDS->exec("CREATE UNIQUE INDEX idxPackage ON package(filename)");
93}
94
95void CAddonDatabase::UpdateTables(int version)
96{
97 if (version < 16)
98 {
99 m_pDS->exec("CREATE TABLE package (id integer primary key, addonID text, filename text, hash text)\n");
100 }
101 if (version < 17)
102 {
103 m_pDS->exec("DELETE FROM repo");
104 m_pDS->exec("ALTER TABLE repo ADD version text");
105 }
106}
107
108int CAddonDatabase::AddAddon(const AddonPtr& addon,
109 int idRepo)
110{
111 try
112 {
113 if (NULL == m_pDB.get()) return -1;
114 if (NULL == m_pDS.get()) return -1;
115
116 std::string sql = PrepareSQL("insert into addon (id, type, name, summary,"
117 "description, stars, path, icon, changelog, "
118 "fanart, addonID, version, author, disclaimer, minversion)"
119 " values(NULL, '%s', '%s', '%s', '%s', %i,"
120 "'%s', '%s', '%s', '%s', '%s','%s','%s','%s','%s')",
121 TranslateType(addon->Type(),false).c_str(),
122 addon->Name().c_str(), addon->Summary().c_str(),
123 addon->Description().c_str(),addon->Stars(),
124 addon->Path().c_str(), addon->Props().icon.c_str(),
125 addon->ChangeLog().c_str(),addon->FanArt().c_str(),
126 addon->ID().c_str(), addon->Version().asString().c_str(),
127 addon->Author().c_str(),addon->Disclaimer().c_str(),
128 addon->MinVersion().asString().c_str());
129 m_pDS->exec(sql.c_str());
130 int idAddon = (int)m_pDS->lastinsertid();
131
132 sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon);
133 m_pDS->exec(sql.c_str());
134
135 const InfoMap &info = addon->ExtraInfo();
136 for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i)
137 {
138 sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str());
139 m_pDS->exec(sql.c_str());
140 }
141 const ADDONDEPS &deps = addon->GetDeps();
142 for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i)
143 {
144 sql = PrepareSQL("insert into dependencies(id, addon, version, optional) values (%i, '%s', '%s', %i)", idAddon, i->first.c_str(), i->second.first.asString().c_str(), i->second.second ? 1 : 0);
145 m_pDS->exec(sql.c_str());
146 }
147 return idAddon;
148 }
149 catch (...)
150 {
151 CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str());
152 }
153 return -1;
154}
155
156AddonVersion CAddonDatabase::GetAddonVersion(const std::string &id)
157{
158 AddonVersion maxversion("0.0.0");
159 try
160 {
161 if (NULL == m_pDB.get()) return maxversion;
162 if (NULL == m_pDS2.get()) return maxversion;
163
164 // there may be multiple addons with this id (eg from different repositories) in the database,
165 // so we want to retrieve the latest version. Order by version won't work as the database
166 // won't know that 1.10 > 1.2, so grab them all and order outside
167 std::string sql = PrepareSQL("select version from addon where addonID='%s'",id.c_str());
168 m_pDS2->query(sql.c_str());
169
170 if (m_pDS2->eof())
171 return maxversion;
172
173 while (!m_pDS2->eof())
174 {
175 AddonVersion version(m_pDS2->fv(0).get_asString());
176 if (version > maxversion)
177 maxversion = version;
178 m_pDS2->next();
179 }
180 return maxversion;
181 }
182 catch (...)
183 {
184 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
185 }
186 return maxversion;
187}
188
189bool CAddonDatabase::GetAddon(const std::string& id, AddonPtr& addon)
190{
191 try
192 {
193 if (NULL == m_pDB.get()) return false;
194 if (NULL == m_pDS2.get()) return false;
195
196 // there may be multiple addons with this id (eg from different repositories) in the database,
197 // so we want to retrieve the latest version. Order by version won't work as the database
198 // won't know that 1.10 > 1.2, so grab them all and order outside
199 std::string sql = PrepareSQL("select id,version from addon where addonID='%s'",id.c_str());
200 m_pDS2->query(sql.c_str());
201
202 if (m_pDS2->eof())
203 return false;
204
205 AddonVersion maxversion("0.0.0");
206 int maxid = 0;
207 while (!m_pDS2->eof())
208 {
209 AddonVersion version(m_pDS2->fv(1).get_asString());
210 if (version > maxversion)
211 {
212 maxid = m_pDS2->fv(0).get_asInt();
213 maxversion = version;
214 }
215 m_pDS2->next();
216 }
217 return GetAddon(maxid,addon);
218 }
219 catch (...)
220 {
221 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
222 }
223 addon.reset();
224 return false;
225}
226
227bool CAddonDatabase::GetRepoForAddon(const std::string& addonID, std::string& repo)
228{
229 try
230 {
231 if (NULL == m_pDB.get()) return false;
232 if (NULL == m_pDS2.get()) return false;
233
234 std::string sql = PrepareSQL("select repo.addonID from repo join addonlinkrepo on repo.id=addonlinkrepo.idRepo join addon on addonlinkrepo.idAddon=addon.id where addon.addonID like '%s'", addonID.c_str());
235 m_pDS2->query(sql.c_str());
236 if (!m_pDS2->eof())
237 {
238 repo = m_pDS2->fv(0).get_asString();
239 m_pDS2->close();
240 return true;
241 }
242 }
243 catch (...)
244 {
245 CLog::Log(LOGERROR, "%s failed for addon %s", __FUNCTION__, addonID.c_str());
246 }
247 return false;
248}
249
250bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
251{
252 try
253 {
254 if (NULL == m_pDB.get()) return false;
255 if (NULL == m_pDS2.get()) return false;
256
257 std::string sql = "SELECT addon.*,"
258 " broken.reason,"
259 " addonextra.key, addonextra.value,"
260 " dependencies.addon, dependencies.version, dependencies.optional"
261 " FROM addon"
262 " LEFT JOIN broken"
263 " ON broken.addonID = addon.addonID"
264 " LEFT JOIN addonextra"
265 " ON addonextra.id = addon.id"
266 " LEFT JOIN dependencies"
267 " ON dependencies.id = addon.id";
268
269 sql += PrepareSQL(" WHERE addon.id=%i", id);
270
271 m_pDS2->query(sql.c_str());
272 if (!m_pDS2->eof())
273 {
274 const dbiplus::query_data &data = m_pDS2->get_result_set().records;
275 const dbiplus::sql_record* const record = data[0];
276 AddonProps props(record->at(addon_addonID).get_asString(),
277 TranslateType(record->at(addon_type).get_asString()),
278 record->at(addon_version).get_asString(),
279 record->at(addon_minversion).get_asString());
280 props.name = record->at(addon_name).get_asString();
281 props.summary = record->at(addon_summary).get_asString();
282 props.description = record->at(addon_description).get_asString();
283 props.changelog = record->at(addon_changelog).get_asString();
284 props.path = record->at(addon_path).get_asString();
285 props.icon = record->at(addon_icon).get_asString();
286 props.fanart = record->at(addon_fanart).get_asString();
287 props.author = record->at(addon_author).get_asString();
288 props.disclaimer = record->at(addon_disclaimer).get_asString();
289 props.broken = record->at(broken_reason).get_asString();
290
291 /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
292 extrainfo and dependencies are maps, so insert() will insert the first instance only */
293 for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
294 {
295 const dbiplus::sql_record* const record = *i;
296 if (!record->at(addonextra_key).get_asString().empty())
297 props.extrainfo.insert(make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
298 if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
299 props.dependencies.insert(make_pair(record->at(dependencies_addon).get_asString(), make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool())));
300 }
301
302 addon = CAddonMgr::AddonFromProps(props);
303 return NULL != addon.get();
304 }
305 }
306 catch (...)
307 {
308 CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
309 }
310 addon.reset();
311 return false;
312}
313
314bool CAddonDatabase::GetAddons(VECADDONS& addons)
315{
316 try
317 {
318 if (NULL == m_pDB.get()) return false;
319 if (NULL == m_pDS2.get()) return false;
320
321 std::string sql = PrepareSQL("select distinct addonID from addon");
322 m_pDS->query(sql.c_str());
323 while (!m_pDS->eof())
324 {
325 AddonPtr addon;
326 if (GetAddon(m_pDS->fv(0).get_asString(),addon))
327 addons.push_back(addon);
328 m_pDS->next();
329 }
330 m_pDS->close();
331 return true;
332 }
333 catch (...)
334 {
335 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
336 }
337 return false;
338}
339
340void CAddonDatabase::DeleteRepository(const std::string& id)
341{
342 try
343 {
344 if (NULL == m_pDB.get()) return;
345 if (NULL == m_pDS.get()) return;
346
347 std::string sql = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
348 m_pDS->query(sql.c_str());
349 if (!m_pDS->eof())
350 DeleteRepository(m_pDS->fv(0).get_asInt());
351 }
352 catch (...)
353 {
354 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
355 }
356}
357
358void CAddonDatabase::DeleteRepository(int idRepo)
359{
360 try
361 {
362 if (NULL == m_pDB.get()) return;
363 if (NULL == m_pDS.get()) return;
364
365 std::string sql = PrepareSQL("delete from repo where id=%i",idRepo);
366 m_pDS->exec(sql.c_str());
367 sql = PrepareSQL("delete from addon where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
368 m_pDS->exec(sql.c_str());
369 sql = PrepareSQL("delete from addonextra where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
370 m_pDS->exec(sql.c_str());
371 sql = PrepareSQL("delete from dependencies where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
372 m_pDS->exec(sql.c_str());
373 sql = PrepareSQL("delete from addonlinkrepo where idRepo=%i",idRepo);
374 m_pDS->exec(sql.c_str());
375
376 }
377 catch (...)
378 {
379 CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, idRepo);
380 }
381}
382
383int CAddonDatabase::AddRepository(const std::string& id, const VECADDONS& addons, const std::string& checksum, const AddonVersion& version)
384{
385 try
386 {
387 if (NULL == m_pDB.get()) return -1;
388 if (NULL == m_pDS.get()) return -1;
389
390 std::string sql;
391 int idRepo = GetRepoChecksum(id,sql);
392 if (idRepo > -1)
393 DeleteRepository(idRepo);
394
395 BeginTransaction();
396
397 CDateTime time = CDateTime::GetCurrentDateTime();
398 sql = PrepareSQL("insert into repo (id,addonID,checksum,lastcheck,version) values (NULL,'%s','%s','%s','%s')",
399 id.c_str(), checksum.c_str(), time.GetAsDBDateTime().c_str(), version.asString().c_str());
400 m_pDS->exec(sql.c_str());
401 idRepo = (int)m_pDS->lastinsertid();
402 for (unsigned int i=0;i<addons.size();++i)
403 AddAddon(addons[i],idRepo);
404
405 CommitTransaction();
406 return idRepo;
407 }
408 catch (...)
409 {
410 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
411 RollbackTransaction();
412 }
413 return -1;
414}
415
416int CAddonDatabase::GetRepoChecksum(const std::string& id, std::string& checksum)
417{
418 try
419 {
420 if (NULL == m_pDB.get()) return -1;
421 if (NULL == m_pDS.get()) return -1;
422
423 std::string strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
424 m_pDS->query(strSQL.c_str());
425 if (!m_pDS->eof())
426 {
427 checksum = m_pDS->fv("checksum").get_asString();
428 return m_pDS->fv("id").get_asInt();
429 }
430 }
431 catch (...)
432 {
433 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
434 }
435 checksum.clear();
436 return -1;
437}
438
439CDateTime CAddonDatabase::GetRepoTimestamp(const std::string& id)
440{
441 CDateTime date;
442 try
443 {
444 if (NULL == m_pDB.get()) return date;
445 if (NULL == m_pDS.get()) return date;
446
447 std::string strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
448 m_pDS->query(strSQL.c_str());
449 if (!m_pDS->eof())
450 {
451 date.SetFromDBDateTime(m_pDS->fv("lastcheck").get_asString());
452 return date;
453 }
454 }
455 catch (...)
456 {
457 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
458 }
459 return date;
460}
461
462
463AddonVersion CAddonDatabase::GetRepoVersion(const std::string& id)
464{
465 AddonVersion version("0.0.0");
466 try
467 {
468 if (NULL == m_pDB.get()) return version;
469 if (NULL == m_pDS2.get()) return version;
470
471 std::string strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
472 m_pDS->query(strSQL.c_str());
473 if (!m_pDS->eof())
474 {
475 return AddonVersion(m_pDS->fv("version").get_asString());
476 }
477 }
478 catch (...)
479 {
480 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
481 }
482 return version;
483}
484
485bool CAddonDatabase::SetRepoTimestamp(const std::string& id, const std::string& time, const ADDON::AddonVersion& version)
486{
487 try
488 {
489 if (NULL == m_pDB.get()) return false;
490 if (NULL == m_pDS.get()) return false;
491
492 std::string sql = PrepareSQL("UPDATE repo SET lastcheck='%s', version='%s' WHERE addonID='%s'",
493 time.c_str(), version.asString().c_str(), id.c_str());
494 m_pDS->exec(sql.c_str());
495
496 return true;
497 }
498 catch (...)
499 {
500 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
501 }
502 return false;
503}
504
505bool CAddonDatabase::GetRepository(int id, VECADDONS& addons)
506{
507 try
508 {
509 if (NULL == m_pDB.get()) return false;
510 if (NULL == m_pDS.get()) return false;
511
512 std::string strSQL = PrepareSQL("select * from addonlinkrepo where idRepo=%i",id);
513 m_pDS->query(strSQL.c_str());
514 while (!m_pDS->eof())
515 {
516 AddonPtr addon;
517 if (GetAddon(m_pDS->fv("idAddon").get_asInt(),addon))
518 addons.push_back(addon);
519 m_pDS->next();
520 }
521 return true;
522 }
523 catch (...)
524 {
525 CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, id);
526 }
527 return false;
528}
529
530bool CAddonDatabase::GetRepository(const std::string& id, VECADDONS& addons)
531{
532 try
533 {
534 if (NULL == m_pDB.get()) return false;
535 if (NULL == m_pDS.get()) return false;
536
537 std::string strSQL = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
538 m_pDS->query(strSQL.c_str());
539 if (!m_pDS->eof())
540 return GetRepository(m_pDS->fv(0).get_asInt(),addons);
541 }
542 catch (...)
543 {
544 CLog::Log(LOGERROR, "%s failed on repo %s", __FUNCTION__, id.c_str());
545 }
546 return false;
547}
548
549bool CAddonDatabase::Search(const std::string& search, VECADDONS& addons)
550{
551 try
552 {
553 if (NULL == m_pDB.get()) return false;
554 if (NULL == m_pDS.get()) return false;
555
556 std::string strSQL;
557 strSQL=PrepareSQL("SELECT addonID FROM addon WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%'", search.c_str(), search.c_str(), search.c_str());
558 CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
559
560 if (!m_pDS->query(strSQL.c_str())) return false;
561 if (m_pDS->num_rows() == 0) return false;
562
563 while (!m_pDS->eof())
564 {
565 AddonPtr addon;
566 GetAddon(m_pDS->fv(0).get_asString(),addon);
567 if (addon->Type() >= ADDON_UNKNOWN+1 && addon->Type() < ADDON_SCRAPER_LIBRARY)
568 addons.push_back(addon);
569 m_pDS->next();
570 }
571 m_pDS->close();
572 return true;
573 }
574 catch (...)
575 {
576 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
577 }
578 return false;
579}
580
581void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon,
582 CFileItemPtr& pItem)
583{
584 pItem->SetProperty("Addon.ID", addon->ID());
585 pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true));
586 pItem->SetProperty("Addon.intType", TranslateType(addon->Type()));
587 pItem->SetProperty("Addon.Name", addon->Name());
588 pItem->SetProperty("Addon.Version", addon->Version().asString());
589 pItem->SetProperty("Addon.Summary", addon->Summary());
590 pItem->SetProperty("Addon.Description", addon->Description());
591 pItem->SetProperty("Addon.Creator", addon->Author());
592 pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer());
593 pItem->SetProperty("Addon.Rating", addon->Stars());
594 std::string starrating = StringUtils::Format("rating%d.png", addon->Stars());
595 pItem->SetProperty("Addon.StarRating",starrating);
596 pItem->SetProperty("Addon.Path", addon->Path());
597 if (addon->Props().broken == "DEPSNOTMET")
598 pItem->SetProperty("Addon.Broken", g_localizeStrings.Get(24044));
599 else
600 pItem->SetProperty("Addon.Broken", addon->Props().broken);
601 std::map<std::string,std::string>::iterator it =
602 addon->Props().extrainfo.find("language");
603 if (it != addon->Props().extrainfo.end())
604 pItem->SetProperty("Addon.Language", it->second);
605}
606
607bool CAddonDatabase::DisableAddon(const std::string &addonID, bool disable /* = true */)
608{
609 try
610 {
611 if (NULL == m_pDB.get()) return false;
612 if (NULL == m_pDS.get()) return false;
613
614 if (disable)
615 {
616 if (!IsAddonDisabled(addonID)) // Enabled
617 {
618 std::string sql = PrepareSQL("insert into disabled(id, addonID) values(NULL, '%s')", addonID.c_str());
619 m_pDS->exec(sql);
620
621 // If the addon is a special, call the disabled handler
622 AddonPtr addon;
623 if ((CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false)
624 || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false)
625 || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_CONTEXT_ITEM, false)) && addon)
626 addon->OnDisabled();
627
628 return true;
629 }
630 return false; // already disabled or failed query
631 }
632 else
633 {
634 bool disabled = IsAddonDisabled(addonID); //we need to know if service addon is running
635 std::string sql = PrepareSQL("delete from disabled where addonID='%s'", addonID.c_str());
636 m_pDS->exec(sql);
637
638 if (disabled)
639 {
640 // If the addon is a special, call the enabled handler
641 AddonPtr addon;
642 if ((CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false)
643 || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false)
644 || CAddonMgr::Get().GetAddon(addonID, addon, ADDON_CONTEXT_ITEM, false)) && addon)
645 addon->OnEnabled();
646 }
647 }
648 return true;
649 }
650 catch (...)
651 {
652 CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addonID.c_str());
653 }
654 return false;
655}
656
657bool CAddonDatabase::BreakAddon(const std::string &addonID, const std::string& reason)
658{
659 if (reason.empty())
660 return ExecuteQuery(PrepareSQL("DELETE FROM broken WHERE addonID='%s'", addonID.c_str()));
661 else
662 return ExecuteQuery(PrepareSQL("REPLACE INTO broken(addonID, reason) VALUES('%s', '%s')",
663 addonID.c_str(), reason.c_str()));
664}
665
666bool CAddonDatabase::HasAddon(const std::string &addonID)
667{
668 std::string strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
669 std::string strHasAddon = GetSingleValue("addon", "id", strWhereClause);
670
671 return !strHasAddon.empty();
672}
673
674bool CAddonDatabase::IsAddonDisabled(const std::string &addonID)
675{
676 try
677 {
678 if (NULL == m_pDB.get()) return false;
679 if (NULL == m_pDS.get()) return false;
680
681 std::string sql = PrepareSQL("select id from disabled where addonID='%s'", addonID.c_str());
682 m_pDS->query(sql.c_str());
683 bool ret = !m_pDS->eof(); // in the disabled table -> disabled
684 m_pDS->close();
685 return ret;
686 }
687 catch (...)
688 {
689 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonID.c_str());
690 }
691 return false;
692}
693
694bool CAddonDatabase::IsSystemPVRAddonEnabled(const std::string &addonID)
695{
696 std::string strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
697 std::string strEnabled = GetSingleValue("pvrenabled", "id", strWhereClause);
698
699 return !strEnabled.empty();
700}
701
702std::string CAddonDatabase::IsAddonBroken(const std::string &addonID)
703{
704 return GetSingleValue(PrepareSQL("SELECT reason FROM broken WHERE addonID='%s'", addonID.c_str()));
705}
706
707bool CAddonDatabase::HasDisabledAddons()
708{
709 try
710 {
711 if (NULL == m_pDB.get()) return false;
712 if (NULL == m_pDS.get()) return false;
713
714 m_pDS->query("select count(id) from disabled");
715 bool ret = !m_pDS->eof() && m_pDS->fv(0).get_asInt() > 0; // have rows -> have disabled addons
716 m_pDS->close();
717 return ret;
718 }
719 catch (...)
720 {
721 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
722 }
723 return false;
724}
725
726bool CAddonDatabase::BlacklistAddon(const std::string& addonID,
727 const std::string& version)
728{
729 try
730 {
731 if (NULL == m_pDB.get()) return false;
732 if (NULL == m_pDS.get()) return false;
733
734 std::string sql = PrepareSQL("insert into blacklist(id, addonID, version) values(NULL, '%s', '%s')", addonID.c_str(),version.c_str());
735 m_pDS->exec(sql);
736
737 return true;
738 }
739 catch (...)
740 {
741 CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
742 }
743 return false;
744}
745
746bool CAddonDatabase::IsAddonBlacklisted(const std::string& addonID,
747 const std::string& version)
748{
749 std::string where = PrepareSQL("addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
750 return !GetSingleValue("blacklist","addonID",where).empty();
751}
752
753bool CAddonDatabase::RemoveAddonFromBlacklist(const std::string& addonID,
754 const std::string& version)
755{
756 try
757 {
758 if (NULL == m_pDB.get()) return false;
759 if (NULL == m_pDS.get()) return false;
760
761 std::string sql = PrepareSQL("delete from blacklist where addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
762 m_pDS->exec(sql);
763 return true;
764 }
765 catch (...)
766 {
767 CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
768 }
769 return false;
770}
771
772bool CAddonDatabase::AddPackage(const std::string& addonID,
773 const std::string& packageFileName,
774 const std::string& hash)
775{
776 std::string sql = PrepareSQL("insert into package(id, addonID, filename, hash)"
777 "values(NULL, '%s', '%s', '%s')",
778 addonID.c_str(), packageFileName.c_str(), hash.c_str());
779 return ExecuteQuery(sql);
780}
781
782bool CAddonDatabase::GetPackageHash(const std::string& addonID,
783 const std::string& packageFileName,
784 std::string& hash)
785{
786 std::string where = PrepareSQL("addonID='%s' and filename='%s'",
787 addonID.c_str(), packageFileName.c_str());
788 hash = GetSingleValue("package", "hash", where);
789 return !hash.empty();
790}
791
792bool CAddonDatabase::RemovePackage(const std::string& packageFileName)
793{
794 std::string sql = PrepareSQL("delete from package where filename='%s'", packageFileName.c_str());
795 return ExecuteQuery(sql);
796}
797
diff --git a/xbmc/addons/AddonDatabase.h b/xbmc/addons/AddonDatabase.h
new file mode 100644
index 0000000..b32f2a4
--- /dev/null
+++ b/xbmc/addons/AddonDatabase.h
@@ -0,0 +1,175 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "dbwrappers/Database.h"
23#include "addons/Addon.h"
24#include "FileItem.h"
25#include <string>
26
27class CAddonDatabase : public CDatabase
28{
29public:
30 CAddonDatabase();
31 virtual ~CAddonDatabase();
32 virtual bool Open();
33
34 int AddAddon(const ADDON::AddonPtr& item, int idRepo);
35 bool GetAddon(const std::string& addonID, ADDON::AddonPtr& addon);
36 bool GetAddons(ADDON::VECADDONS& addons);
37
38 /*! \brief grab the (largest) add-on version for an add-on */
39 ADDON::AddonVersion GetAddonVersion(const std::string &id);
40
41 /*! \brief Grab the repository from which a given addon came
42 \param addonID - the id of the addon in question
43 \param repo [out] - the id of the repository
44 \return true if a repo was found, false otherwise.
45 */
46 bool GetRepoForAddon(const std::string& addonID, std::string& repo);
47 int AddRepository(const std::string& id, const ADDON::VECADDONS& addons, const std::string& checksum, const ADDON::AddonVersion& version);
48 void DeleteRepository(const std::string& id);
49 void DeleteRepository(int id);
50 int GetRepoChecksum(const std::string& id, std::string& checksum);
51 bool GetRepository(const std::string& id, ADDON::VECADDONS& addons);
52 bool GetRepository(int id, ADDON::VECADDONS& addons);
53 bool SetRepoTimestamp(const std::string& id, const std::string& timestamp, const ADDON::AddonVersion& version);
54
55 /*! \brief Retrieve the time a repository was last checked
56 \param id id of the repo
57 \return last time the repo was checked, current time if not available
58 \sa SetRepoTimestamp */
59 CDateTime GetRepoTimestamp(const std::string& id);
60
61 ADDON::AddonVersion GetRepoVersion(const std::string& id);
62
63 bool Search(const std::string& search, ADDON::VECADDONS& items);
64 static void SetPropertiesFromAddon(const ADDON::AddonPtr& addon, CFileItemPtr& item);
65
66 /*! \brief Disable an addon.
67 Sets a flag that this addon has been disabled. If disabled, it is usually still available on disk.
68 \param addonID id of the addon to disable
69 \param disable whether to enable or disable. Defaults to true (disable)
70 \return true on success, false on failure
71 \sa IsAddonDisabled, HasDisabledAddons */
72 bool DisableAddon(const std::string &addonID, bool disable = true);
73
74 /*! \brief Checks if an addon is in the database.
75 \param addonID id of the addon to be checked
76 \return true if addon is in database, false if addon is not in database yet */
77 bool HasAddon(const std::string &addonID);
78
79 /*! \brief Check whether an addon has been disabled via DisableAddon.
80 \param addonID id of the addon to check
81 \return true if the addon is disabled, false otherwise
82 \sa DisableAddon, HasDisabledAddons */
83 bool IsAddonDisabled(const std::string &addonID);
84
85 /*! \brief Check whether we have disabled addons.
86 \return true if we have disabled addons, false otherwise
87 \sa DisableAddon, IsAddonDisabled */
88 bool HasDisabledAddons();
89
90 /*! @deprecated only here to allow clean upgrades from earlier pvr versions
91 */
92 bool IsSystemPVRAddonEnabled(const std::string &addonID);
93
94 /*! \brief Mark an addon as broken
95 Sets a flag that this addon has been marked as broken in the repository.
96 \param addonID id of the addon to mark as broken
97 \param reason why it is broken - if non empty we take it as broken. Defaults to empty
98 \return true on success, false on failure
99 \sa IsAddonBroken */
100 bool BreakAddon(const std::string &addonID, const std::string& reason="");
101
102 /*! \brief Check whether an addon has been marked as broken via BreakAddon.
103 \param addonID id of the addon to check
104 \return reason if the addon is broken, blank otherwise
105 \sa BreakAddon */
106 std::string IsAddonBroken(const std::string &addonID);
107
108 bool BlacklistAddon(const std::string& addonID, const std::string& version);
109 bool IsAddonBlacklisted(const std::string& addonID, const std::string& version);
110 bool RemoveAddonFromBlacklist(const std::string& addonID,
111 const std::string& version);
112
113 /*! \brief Store an addon's package filename and that file's hash for future verification
114 \param addonID id of the addon we're adding a package for
115 \param packageFileName filename of the package
116 \param hash MD5 checksum of the package
117 \return Whether or not the info successfully made it into the DB.
118 \sa GetPackageHash, RemovePackage
119 */
120 bool AddPackage(const std::string& addonID,
121 const std::string& packageFileName,
122 const std::string& hash);
123 /*! \brief Query the MD5 checksum of the given given addon's given package
124 \param addonID id of the addon we're who's package we're querying
125 \param packageFileName filename of the package
126 \param hash return the MD5 checksum of the package
127 \return Whether or not we found a hash for the given addon's given package
128 \sa AddPackage, RemovePackage
129 */
130 bool GetPackageHash(const std::string& addonID,
131 const std::string& packageFileName,
132 std::string& hash);
133 /*! \brief Remove a package's info from the database
134 \param packageFileName filename of the package
135 \return Whether or not we succeeded in removing the package
136 \sa AddPackage, GetPackageHash
137 */
138 bool RemovePackage(const std::string& packageFileName);
139protected:
140 virtual void CreateTables();
141 virtual void CreateAnalytics();
142 virtual void UpdateTables(int version);
143 virtual int GetMinSchemaVersion() const { return 15; }
144 virtual int GetSchemaVersion() const { return 17; }
145 const char *GetBaseDBName() const { return "Addons"; }
146
147 bool GetAddon(int id, ADDON::AddonPtr& addon);
148
149 /* keep in sync with the select in GetAddon */
150 enum _AddonFields
151 {
152 addon_id=0,
153 addon_type,
154 addon_name,
155 addon_summary,
156 addon_description,
157 addon_stars,
158 addon_path,
159 addon_addonID,
160 addon_icon,
161 addon_version,
162 addon_changelog,
163 addon_fanart,
164 addon_author,
165 addon_disclaimer,
166 addon_minversion,
167 broken_reason,
168 addonextra_key,
169 addonextra_value,
170 dependencies_addon,
171 dependencies_version,
172 dependencies_optional
173 } AddonFields;
174};
175
diff --git a/xbmc/addons/AddonDll.h b/xbmc/addons/AddonDll.h
new file mode 100644
index 0000000..d5e4e9e
--- /dev/null
+++ b/xbmc/addons/AddonDll.h
@@ -0,0 +1,572 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21#include <math.h>
22#include <string>
23
24#include "Addon.h"
25#include "DllAddon.h"
26#include "AddonManager.h"
27#include "AddonStatusHandler.h"
28#include "AddonCallbacks.h"
29#include "utils/URIUtils.h"
30#include "filesystem/File.h"
31#include "filesystem/SpecialProtocol.h"
32#include "filesystem/Directory.h"
33#include "utils/log.h"
34#include "interfaces/IAnnouncer.h"
35#include "interfaces/AnnouncementManager.h"
36#include "utils/XMLUtils.h"
37#include "Util.h"
38
39namespace ADDON
40{
41 template<class TheDll, typename TheStruct, typename TheProps>
42 class CAddonDll : public CAddon, public ANNOUNCEMENT::IAnnouncer
43 {
44 public:
45 CAddonDll(const AddonProps &props);
46 CAddonDll(const cp_extension_t *ext);
47 CAddonDll(const CAddonDll<TheDll, TheStruct, TheProps> &rhs);
48 virtual ~CAddonDll();
49 virtual AddonPtr Clone() const;
50 virtual ADDON_STATUS GetStatus();
51
52 // addon settings
53 virtual void SaveSettings();
54 virtual std::string GetSetting(const std::string& key);
55
56 ADDON_STATUS Create();
57 virtual void Stop();
58 virtual bool CheckAPIVersion(void) { return true; }
59 void Destroy();
60
61 bool DllLoaded(void) const;
62
63 void Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data);
64
65 protected:
66 void HandleException(std::exception &e, const char* context);
67 bool Initialized() { return m_initialized; }
68 virtual void BuildLibName(const cp_extension_t *ext = NULL) {}
69 virtual bool LoadSettings();
70 TheStruct* m_pStruct;
71 TheProps* m_pInfo;
72 CAddonCallbacks* m_pHelpers;
73 bool m_bIsChild;
74
75 private:
76 TheDll* m_pDll;
77 bool m_initialized;
78 bool LoadDll();
79 bool m_needsavedsettings;
80
81 virtual ADDON_STATUS TransferSettings();
82 TiXmlElement MakeSetting(DllSetting& setting) const;
83
84 static void AddOnStatusCallback(void *userData, const ADDON_STATUS status, const char* msg);
85 static bool AddOnGetSetting(void *userData, const char *settingName, void *settingValue);
86 static void AddOnOpenSettings(const char *url, bool bReload);
87 static void AddOnOpenOwnSettings(void *userData, bool bReload);
88 static const char* AddOnGetAddonDirectory(void *userData);
89 static const char* AddOnGetUserDirectory(void *userData);
90 };
91
92template<class TheDll, typename TheStruct, typename TheProps>
93CAddonDll<TheDll, TheStruct, TheProps>::CAddonDll(const cp_extension_t *ext)
94 : CAddon(ext),
95 m_bIsChild(false)
96{
97 // if library attribute isn't present, look for a system-dependent one
98 if (ext && m_strLibName.empty())
99 {
100#if defined(TARGET_ANDROID)
101 m_strLibName = CAddonMgr::Get().GetExtValue(ext->configuration, "@library_android");
102#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
103 m_strLibName = CAddonMgr::Get().GetExtValue(ext->configuration, "@library_linux");
104#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
105 m_strLibName = CAddonMgr::Get().GetExtValue(ext->configuration, "@library_windx");
106#elif defined(TARGET_DARWIN)
107 m_strLibName = CAddonMgr::Get().GetExtValue(ext->configuration, "@library_osx");
108#endif
109 }
110
111 m_pStruct = NULL;
112 m_initialized = false;
113 m_pDll = NULL;
114 m_pInfo = NULL;
115 m_pHelpers = NULL;
116 m_needsavedsettings = false;
117}
118
119template<class TheDll, typename TheStruct, typename TheProps>
120CAddonDll<TheDll, TheStruct, TheProps>::CAddonDll(const AddonProps &props)
121 : CAddon(props),
122 m_bIsChild(false)
123{
124 m_pStruct = NULL;
125 m_initialized = false;
126 m_pDll = NULL;
127 m_pInfo = NULL;
128 m_pHelpers = NULL;
129 m_needsavedsettings = false;
130}
131
132template<class TheDll, typename TheStruct, typename TheProps>
133CAddonDll<TheDll, TheStruct, TheProps>::CAddonDll(const CAddonDll<TheDll, TheStruct, TheProps> &rhs)
134 : CAddon(rhs),
135 m_bIsChild(true)
136{
137 m_pStruct = rhs.m_pStruct;
138 m_initialized = rhs.m_initialized;
139 m_pDll = rhs.m_pDll;
140 m_pInfo = rhs.m_pInfo;
141 m_pHelpers = rhs.m_pHelpers;
142 m_needsavedsettings = rhs.m_needsavedsettings;
143}
144
145template<class TheDll, typename TheStruct, typename TheProps>
146CAddonDll<TheDll, TheStruct, TheProps>::~CAddonDll()
147{
148 if (m_initialized)
149 Destroy();
150}
151
152template<class TheDll, typename TheStruct, typename TheProps>
153AddonPtr CAddonDll<TheDll, TheStruct, TheProps>::Clone() const
154{
155 return AddonPtr(new CAddonDll<TheDll, TheStruct, TheProps>(*this));
156}
157
158template<class TheDll, typename TheStruct, typename TheProps>
159bool CAddonDll<TheDll, TheStruct, TheProps>::LoadDll()
160{
161 std::string strFileName;
162 if (!m_bIsChild)
163 {
164 strFileName = LibPath();
165 }
166 else
167 { //FIXME hack to load same Dll twice
168 std::string extension = URIUtils::GetExtension(m_strLibName);
169 strFileName = "special://temp/" + m_strLibName;
170 URIUtils::RemoveExtension(strFileName);
171 strFileName += "-" + ID() + extension;
172
173 if (!XFILE::CFile::Exists(strFileName))
174 XFILE::CFile::Copy(LibPath(), strFileName);
175
176 CLog::Log(LOGNOTICE, "ADDON: Loaded virtual child addon %s", strFileName.c_str());
177 }
178
179 /* Check if lib being loaded exists, else check in XBMC binary location */
180#if defined(TARGET_ANDROID)
181 // Android libs MUST live in this path, else multi-arch will break.
182 // The usual soname requirements apply. no subdirs, and filename is ^lib.*\.so$
183 if (!XFILE::CFile::Exists(strFileName))
184 {
185 std::string tempbin = getenv("XBMC_ANDROID_LIBS");
186 strFileName = tempbin + "/" + m_strLibName;
187 }
188#endif
189 if (!XFILE::CFile::Exists(strFileName))
190 {
191 std::string temp = CSpecialProtocol::TranslatePath("special://xbmc/");
192 std::string tempbin = CSpecialProtocol::TranslatePath("special://xbmcbin/");
193 strFileName.erase(0, temp.size());
194 strFileName = tempbin + strFileName;
195 if (!XFILE::CFile::Exists(strFileName))
196 {
197 CLog::Log(LOGERROR, "ADDON: Could not locate %s", m_strLibName.c_str());
198 return false;
199 }
200 }
201
202 /* Load the Dll */
203 m_pDll = new TheDll;
204 m_pDll->SetFile(strFileName);
205 m_pDll->EnableDelayedUnload(false);
206 if (!m_pDll->Load())
207 {
208 delete m_pDll;
209 m_pDll = NULL;
210 new CAddonStatusHandler(ID(), ADDON_STATUS_UNKNOWN, "Can't load Dll", false);
211 return false;
212 }
213
214 m_pStruct = (TheStruct*)malloc(sizeof(TheStruct));
215 if (m_pStruct)
216 {
217 ZeroMemory(m_pStruct, sizeof(TheStruct));
218 m_pDll->GetAddon(m_pStruct);
219 return true;
220 }
221
222 return false;
223}
224
225template<class TheDll, typename TheStruct, typename TheProps>
226ADDON_STATUS CAddonDll<TheDll, TheStruct, TheProps>::Create()
227{
228 ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
229 CLog::Log(LOGDEBUG, "ADDON: Dll Initializing - %s", Name().c_str());
230 m_initialized = false;
231
232 if (!LoadDll() || !CheckAPIVersion())
233 return ADDON_STATUS_PERMANENT_FAILURE;
234
235 /* Allocate the helper function class to allow crosstalk over
236 helper libraries */
237 m_pHelpers = new CAddonCallbacks(this);
238
239 /* Call Create to make connections, initializing data or whatever is
240 needed to become the AddOn running */
241 try
242 {
243 status = m_pDll->Create(m_pHelpers->GetCallbacks(), m_pInfo);
244 if (status == ADDON_STATUS_OK)
245 {
246 m_initialized = true;
247 ANNOUNCEMENT::CAnnouncementManager::Get().AddAnnouncer(this);
248 }
249 else if ((status == ADDON_STATUS_NEED_SETTINGS) || (status == ADDON_STATUS_NEED_SAVEDSETTINGS))
250 {
251 m_needsavedsettings = (status == ADDON_STATUS_NEED_SAVEDSETTINGS);
252 if ((status = TransferSettings()) == ADDON_STATUS_OK)
253 m_initialized = true;
254 else
255 new CAddonStatusHandler(ID(), status, "", false);
256 }
257 else
258 { // Addon failed initialization
259 CLog::Log(LOGERROR, "ADDON: Dll %s - Client returned bad status (%i) from Create and is not usable", Name().c_str(), status);
260 new CAddonStatusHandler(ID(), status, "", false);
261 }
262 }
263 catch (std::exception &e)
264 {
265 HandleException(e, "m_pDll->Create");
266 }
267
268 if (!m_initialized)
269 SAFE_DELETE(m_pHelpers);
270
271 return status;
272}
273
274template<class TheDll, typename TheStruct, typename TheProps>
275void CAddonDll<TheDll, TheStruct, TheProps>::Stop()
276{
277 /* Inform dll to stop all activities */
278 try
279 {
280 if (m_needsavedsettings) // If the addon supports it we save some settings to settings.xml before stop
281 {
282 char str_id[64] = "";
283 char str_value[1024];
284 CAddon::LoadUserSettings();
285 for (unsigned int i=0; (strcmp(str_id,"###End") != 0); i++)
286 {
287 strcpy(str_id, "###GetSavedSettings");
288 sprintf (str_value, "%i", i);
289 ADDON_STATUS status = m_pDll->SetSetting((const char*)&str_id, (void*)&str_value);
290
291 if (status == ADDON_STATUS_UNKNOWN)
292 break;
293
294 if (strcmp(str_id,"###End") != 0) UpdateSetting(str_id, str_value);
295 }
296 CAddon::SaveSettings();
297 }
298 if (m_pDll)
299 {
300 m_pDll->Stop();
301 CLog::Log(LOGINFO, "ADDON: Dll Stopped - %s", Name().c_str());
302 }
303 }
304 catch (std::exception &e)
305 {
306 HandleException(e, "m_pDll->Stop");
307 }
308}
309
310template<class TheDll, typename TheStruct, typename TheProps>
311void CAddonDll<TheDll, TheStruct, TheProps>::Destroy()
312{
313 ANNOUNCEMENT::CAnnouncementManager::Get().RemoveAnnouncer(this);
314
315 /* Unload library file */
316 try
317 {
318 if (m_pDll)
319 {
320 m_pDll->Destroy();
321 m_pDll->Unload();
322 }
323 }
324 catch (std::exception &e)
325 {
326 HandleException(e, "m_pDll->Unload");
327 }
328 delete m_pHelpers;
329 m_pHelpers = NULL;
330 free(m_pStruct);
331 m_pStruct = NULL;
332 if (m_pDll)
333 {
334 delete m_pDll;
335 m_pDll = NULL;
336 CLog::Log(LOGINFO, "ADDON: Dll Destroyed - %s", Name().c_str());
337 }
338 m_initialized = false;
339}
340
341template<class TheDll, typename TheStruct, typename TheProps>
342bool CAddonDll<TheDll, TheStruct, TheProps>::DllLoaded(void) const
343{
344 return m_pDll != NULL;
345}
346
347template<class TheDll, typename TheStruct, typename TheProps>
348ADDON_STATUS CAddonDll<TheDll, TheStruct, TheProps>::GetStatus()
349{
350 try
351 {
352 return m_pDll->GetStatus();
353 }
354 catch (std::exception &e)
355 {
356 HandleException(e, "m_pDll->GetStatus()");
357 }
358 return ADDON_STATUS_UNKNOWN;
359}
360
361template<class TheDll, typename TheStruct, typename TheProps>
362bool CAddonDll<TheDll, TheStruct, TheProps>::LoadSettings()
363{
364 if (m_settingsLoaded)
365 return true;
366
367 if (!LoadDll())
368 return false;
369
370 ADDON_StructSetting** sSet;
371 std::vector<DllSetting> vSet;
372 unsigned entries = 0;
373 try
374 {
375 entries = m_pDll->GetSettings(&sSet);
376 DllUtils::StructToVec(entries, &sSet, &vSet);
377 m_pDll->FreeSettings();
378 }
379 catch (std::exception &e)
380 {
381 HandleException(e, "m_pDll->GetSettings()");
382 return false;
383 }
384
385 if (vSet.size())
386 {
387 // regenerate XML doc
388 m_addonXmlDoc.Clear();
389 TiXmlElement node("settings");
390 m_addonXmlDoc.InsertEndChild(node);
391
392 for (unsigned i=0; i < entries; i++)
393 {
394 DllSetting& setting = vSet[i];
395 m_addonXmlDoc.RootElement()->InsertEndChild(MakeSetting(setting));
396 }
397 CAddon::SettingsFromXML(m_addonXmlDoc, true);
398 }
399 else
400 return CAddon::LoadSettings();
401
402 m_settingsLoaded = true;
403 CAddon::LoadUserSettings();
404 return true;
405}
406
407template<class TheDll, typename TheStruct, typename TheProps>
408TiXmlElement CAddonDll<TheDll, TheStruct, TheProps>::MakeSetting(DllSetting& setting) const
409{
410 TiXmlElement node("setting");
411
412 switch (setting.type)
413 {
414 case DllSetting::CHECK:
415 {
416 node.SetAttribute("id", setting.id);
417 node.SetAttribute("type", "bool");
418 node.SetAttribute("label", setting.label);
419 break;
420 }
421 case DllSetting::SPIN:
422 {
423 node.SetAttribute("id", setting.id);
424 node.SetAttribute("type", "enum");
425 node.SetAttribute("label", setting.label);
426 std::string values;
427 for (unsigned int i = 0; i < setting.entry.size(); i++)
428 {
429 values.append(setting.entry[i]);
430 values.append("|");
431 }
432 node.SetAttribute("values", values.c_str());
433 break;
434 }
435 default:
436 break;
437 }
438
439 return node;
440}
441
442template<class TheDll, typename TheStruct, typename TheProps>
443void CAddonDll<TheDll, TheStruct, TheProps>::SaveSettings()
444{
445 // must save first, as TransferSettings() reloads saved settings!
446 CAddon::SaveSettings();
447 if (m_initialized)
448 TransferSettings();
449}
450
451template<class TheDll, typename TheStruct, typename TheProps>
452std::string CAddonDll<TheDll, TheStruct, TheProps>::GetSetting(const std::string& key)
453{
454 return CAddon::GetSetting(key);
455}
456
457template<class TheDll, typename TheStruct, typename TheProps>
458ADDON_STATUS CAddonDll<TheDll, TheStruct, TheProps>::TransferSettings()
459{
460 bool restart = false;
461 ADDON_STATUS reportStatus = ADDON_STATUS_OK;
462
463 CLog::Log(LOGDEBUG, "Calling TransferSettings for: %s", Name().c_str());
464
465 LoadSettings();
466
467 const TiXmlElement *category = m_addonXmlDoc.RootElement() ? m_addonXmlDoc.RootElement()->FirstChildElement("category") : NULL;
468 if (!category)
469 category = m_addonXmlDoc.RootElement(); // no categories
470
471 while (category)
472 {
473 const TiXmlElement *setting = category->FirstChildElement("setting");
474 while (setting)
475 {
476 ADDON_STATUS status = ADDON_STATUS_OK;
477 const char *id = setting->Attribute("id");
478 const std::string type = XMLUtils::GetAttribute(setting, "type");
479 const char *option = setting->Attribute("option");
480
481 if (id && !type.empty())
482 {
483 if (type == "sep" || type == "lsep")
484 {
485 /* Don't propagate separators */
486 }
487 else if (type == "text" || type == "ipaddress" ||
488 type == "video" || type == "audio" ||
489 type == "image" || type == "folder" ||
490 type == "executable" || type == "file" ||
491 type == "action" || type == "date" ||
492 type == "time" || type == "select" ||
493 type == "addon" || type == "labelenum" ||
494 type == "fileenum" )
495 {
496 status = m_pDll->SetSetting(id, (const char*) GetSetting(id).c_str());
497 }
498 else if (type == "enum" || type =="integer" ||
499 type == "labelenum" || type == "rangeofnum")
500 {
501 int tmp = atoi(GetSetting(id).c_str());
502 status = m_pDll->SetSetting(id, (int*) &tmp);
503 }
504 else if (type == "bool")
505 {
506 bool tmp = (GetSetting(id) == "true") ? true : false;
507 status = m_pDll->SetSetting(id, (bool*) &tmp);
508 }
509 else if (type == "rangeofnum" || type == "slider" ||
510 type == "number")
511 {
512 float tmpf = (float)atof(GetSetting(id).c_str());
513 int tmpi;
514
515 if (option && strcmpi(option,"int") == 0)
516 {
517 tmpi = (int)floor(tmpf);
518 status = m_pDll->SetSetting(id, (int*) &tmpi);
519 }
520 else
521 {
522 status = m_pDll->SetSetting(id, (float*) &tmpf);
523 }
524 }
525 else
526 {
527 /* Log unknowns as an error, but go ahead and transfer the string */
528 CLog::Log(LOGERROR, "Unknown setting type '%s' for %s", type.c_str(), Name().c_str());
529 status = m_pDll->SetSetting(id, (const char*) GetSetting(id).c_str());
530 }
531
532 if (status == ADDON_STATUS_NEED_RESTART)
533 restart = true;
534 else if (status != ADDON_STATUS_OK)
535 reportStatus = status;
536 }
537 setting = setting->NextSiblingElement("setting");
538 }
539 category = category->NextSiblingElement("category");
540 }
541
542 if (restart || reportStatus != ADDON_STATUS_OK)
543 {
544 new CAddonStatusHandler(ID(), restart ? ADDON_STATUS_NEED_RESTART : reportStatus, "", true);
545 }
546
547 return ADDON_STATUS_OK;
548}
549
550template<class TheDll, typename TheStruct, typename TheProps>
551void CAddonDll<TheDll, TheStruct, TheProps>::Announce(ANNOUNCEMENT::AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
552{
553 try
554 {
555 m_pDll->Announce(ANNOUNCEMENT::AnnouncementFlagToString(flag), sender, message, &data);
556 }
557 catch (std::exception &e)
558 {
559 HandleException(e, "m_pDll->Announce()");
560 }
561}
562
563template<class TheDll, typename TheStruct, typename TheProps>
564void CAddonDll<TheDll, TheStruct, TheProps>::HandleException(std::exception &e, const char* context)
565{
566 m_initialized = false;
567 m_pDll->Unload();
568 CLog::Log(LOGERROR, "ADDON: Dll %s, throws an exception '%s' during %s. Contact developer '%s' with bug reports", Name().c_str(), e.what(), context, Author().c_str());
569}
570
571}; /* namespace ADDON */
572
diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp
new file mode 100644
index 0000000..f4a241c
--- /dev/null
+++ b/xbmc/addons/AddonInstaller.cpp
@@ -0,0 +1,974 @@
1/*
2 * Copyright (C) 2011-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "AddonInstaller.h"
22#include "utils/log.h"
23#include "utils/FileUtils.h"
24#include "utils/URIUtils.h"
25#include "Util.h"
26#include "guilib/LocalizeStrings.h"
27#include "filesystem/Directory.h"
28#include "settings/AdvancedSettings.h"
29#include "settings/Settings.h"
30#include "ApplicationMessenger.h"
31#include "filesystem/FavouritesDirectory.h"
32#include "utils/JobManager.h"
33#include "dialogs/GUIDialogYesNo.h"
34#include "addons/AddonManager.h"
35#include "addons/Repository.h"
36#include "guilib/GUIWindowManager.h" // for callback
37#include "GUIUserMessages.h" // for callback
38#include "utils/StringUtils.h"
39#include "dialogs/GUIDialogKaiToast.h"
40#include "dialogs/GUIDialogOK.h"
41#include "dialogs/GUIDialogProgress.h"
42#include "URL.h"
43
44#include <functional>
45
46using namespace std;
47using namespace XFILE;
48using namespace ADDON;
49
50
51struct find_map : public binary_function<CAddonInstaller::JobMap::value_type, unsigned int, bool>
52{
53 bool operator() (CAddonInstaller::JobMap::value_type t, unsigned int id) const
54 {
55 return (t.second.jobID == id);
56 }
57};
58
59CAddonInstaller::CAddonInstaller()
60 : m_repoUpdateJob(0)
61{ }
62
63CAddonInstaller::~CAddonInstaller()
64{ }
65
66CAddonInstaller &CAddonInstaller::Get()
67{
68 static CAddonInstaller addonInstaller;
69 return addonInstaller;
70}
71
72void CAddonInstaller::OnJobComplete(unsigned int jobID, bool success, CJob* job)
73{
74 if (success)
75 CAddonMgr::Get().FindAddons();
76
77 CSingleLock lock(m_critSection);
78 if (strncmp(job->GetType(), "repoupdate", 10) == 0)
79 {
80 // repo job finished
81 m_repoUpdateDone.Set();
82 m_repoUpdateJob = 0;
83 lock.Leave();
84 }
85 else
86 {
87 // download job
88 JobMap::iterator i = find_if(m_downloadJobs.begin(), m_downloadJobs.end(), bind2nd(find_map(), jobID));
89 if (i != m_downloadJobs.end())
90 m_downloadJobs.erase(i);
91 lock.Leave();
92 PrunePackageCache();
93 }
94
95 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
96 g_windowManager.SendThreadMessage(msg);
97}
98
99void CAddonInstaller::OnJobProgress(unsigned int jobID, unsigned int progress, unsigned int total, const CJob *job)
100{
101 CSingleLock lock(m_critSection);
102 JobMap::iterator i = find_if(m_downloadJobs.begin(), m_downloadJobs.end(), bind2nd(find_map(), jobID));
103 if (i != m_downloadJobs.end())
104 {
105 // update job progress
106 i->second.progress = progress;
107 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM);
108 msg.SetStringParam(i->first);
109 lock.Leave();
110 g_windowManager.SendThreadMessage(msg);
111 }
112}
113
114bool CAddonInstaller::IsDownloading() const
115{
116 CSingleLock lock(m_critSection);
117 return !m_downloadJobs.empty();
118}
119
120void CAddonInstaller::GetInstallList(VECADDONS &addons) const
121{
122 CSingleLock lock(m_critSection);
123 vector<std::string> addonIDs;
124 for (JobMap::const_iterator i = m_downloadJobs.begin(); i != m_downloadJobs.end(); ++i)
125 {
126 if (i->second.jobID)
127 addonIDs.push_back(i->first);
128 }
129 lock.Leave();
130
131 CAddonDatabase database;
132 database.Open();
133 for (vector<std::string>::iterator it = addonIDs.begin(); it != addonIDs.end(); ++it)
134 {
135 AddonPtr addon;
136 if (database.GetAddon(*it, addon))
137 addons.push_back(addon);
138 }
139}
140
141bool CAddonInstaller::GetProgress(const std::string &addonID, unsigned int &percent) const
142{
143 CSingleLock lock(m_critSection);
144 JobMap::const_iterator i = m_downloadJobs.find(addonID);
145 if (i != m_downloadJobs.end())
146 {
147 percent = i->second.progress;
148 return true;
149 }
150 return false;
151}
152
153bool CAddonInstaller::Cancel(const std::string &addonID)
154{
155 CSingleLock lock(m_critSection);
156 JobMap::iterator i = m_downloadJobs.find(addonID);
157 if (i != m_downloadJobs.end())
158 {
159 CJobManager::GetInstance().CancelJob(i->second.jobID);
160 m_downloadJobs.erase(i);
161 return true;
162 }
163
164 return false;
165}
166
167bool CAddonInstaller::InstallModal(const std::string &addonID, ADDON::AddonPtr &addon, bool promptForInstall /* = true */)
168{
169 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
170 return false;
171
172 // we assume that addons that are enabled don't get to this routine (i.e. that GetAddon() has been called)
173 if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_UNKNOWN, false))
174 return false; // addon is installed but disabled, and the user has specifically activated something that needs
175 // the addon - should we enable it?
176
177 // check we have it available
178 CAddonDatabase database;
179 database.Open();
180 if (!database.GetAddon(addonID, addon))
181 return false;
182
183 // if specified ask the user if he wants it installed
184 if (promptForInstall &&
185 !CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(24076), g_localizeStrings.Get(24100),
186 addon->Name().c_str(), g_localizeStrings.Get(24101)))
187 return false;
188
189 if (!Install(addonID, true, "", false, true))
190 return false;
191
192 return CAddonMgr::Get().GetAddon(addonID, addon);
193}
194
195bool CAddonInstaller::Install(const std::string &addonID, bool force /* = false */, const std::string &referer /* = "" */, bool background /* = true */, bool modal /* = false */)
196{
197 AddonPtr addon;
198 bool addonInstalled = CAddonMgr::Get().GetAddon(addonID, addon, ADDON_UNKNOWN, false);
199 if (addonInstalled && !force)
200 return true;
201
202 if (referer.empty())
203 {
204 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
205 return false;
206 }
207
208 // check whether we have it available in a repository
209 std::string hash;
210 if (!CAddonInstallJob::GetAddonWithHash(addonID, addon, hash))
211 return false;
212
213 return DoInstall(addon, hash, addonInstalled, referer, background, modal);
214}
215
216bool CAddonInstaller::DoInstall(const AddonPtr &addon, const std::string &hash /* = "" */, bool update /* = false */, const std::string &referer /* = "" */, bool background /* = true */, bool modal /* = false */)
217{
218 // check whether we already have the addon installing
219 CSingleLock lock(m_critSection);
220 if (m_downloadJobs.find(addon->ID()) != m_downloadJobs.end())
221 return false;
222
223 CAddonInstallJob* installJob = new CAddonInstallJob(addon, hash, update, referer);
224 if (background)
225 {
226 unsigned int jobID = CJobManager::GetInstance().AddJob(installJob, this);
227 m_downloadJobs.insert(make_pair(addon->ID(), CDownloadJob(jobID)));
228 return true;
229 }
230
231 m_downloadJobs.insert(make_pair(addon->ID(), CDownloadJob(0)));
232 lock.Leave();
233
234 bool result = false;
235 if (modal)
236 result = installJob->DoModal();
237 else
238 result = installJob->DoWork();
239 delete installJob;
240
241 lock.Enter();
242 JobMap::iterator i = m_downloadJobs.find(addon->ID());
243 m_downloadJobs.erase(i);
244
245 return result;
246}
247
248bool CAddonInstaller::InstallFromZip(const std::string &path)
249{
250 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
251 return false;
252
253 // grab the descriptive XML document from the zip, and read it in
254 CFileItemList items;
255 // BUG: some zip files return a single item (root folder) that we think is stored, so we don't use the zip:// protocol
256 CURL pathToUrl(path);
257 CURL zipDir = URIUtils::CreateArchivePath("zip", pathToUrl, "");
258 if (!CDirectory::GetDirectory(zipDir, items) || items.Size() != 1 || !items[0]->m_bIsFolder)
259 {
260 CGUIDialogKaiToast::QueueNotification("", path, g_localizeStrings.Get(24045), TOAST_DISPLAY_TIME, false);
261 return false;
262 }
263
264 // TODO: possibly add support for github generated zips here?
265 std::string archive = URIUtils::AddFileToFolder(items[0]->GetPath(), "addon.xml");
266
267 CXBMCTinyXML xml;
268 AddonPtr addon;
269 if (xml.LoadFile(archive) && CAddonMgr::Get().LoadAddonDescriptionFromMemory(xml.RootElement(), addon))
270 {
271 // set the correct path
272 addon->Props().path = items[0]->GetPath();
273 addon->Props().icon = URIUtils::AddFileToFolder(items[0]->GetPath(), "icon.png");
274
275 // install the addon
276 return DoInstall(addon);
277 }
278
279 CGUIDialogKaiToast::QueueNotification("", path, g_localizeStrings.Get(24045), TOAST_DISPLAY_TIME, false);
280 return false;
281}
282
283void CAddonInstaller::InstallFromXBMCRepo(const set<std::string> &addonIDs)
284{
285 // first check we have the our repositories up to date (and wait until we do)
286 UpdateRepos(false, true);
287
288 // now install the addons
289 for (set<std::string>::const_iterator i = addonIDs.begin(); i != addonIDs.end(); ++i)
290 Install(*i);
291}
292
293bool CAddonInstaller::CheckDependencies(const AddonPtr &addon, CAddonDatabase *database /* = NULL */)
294{
295 std::vector<std::string> preDeps;
296 preDeps.push_back(addon->ID());
297 CAddonDatabase localDB;
298 if (!database)
299 database = &localDB;
300
301 return CheckDependencies(addon, preDeps, *database);
302}
303
304bool CAddonInstaller::CheckDependencies(const AddonPtr &addon,
305 std::vector<std::string>& preDeps, CAddonDatabase &database)
306{
307 if (addon == NULL)
308 return true; // a NULL addon has no dependencies
309
310 if (!database.Open())
311 return false;
312
313 ADDONDEPS deps = addon->GetDeps();
314 for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i)
315 {
316 const std::string &addonID = i->first;
317 const AddonVersion &version = i->second.first;
318 bool optional = i->second.second;
319 AddonPtr dep;
320 bool haveAddon = CAddonMgr::Get().GetAddon(addonID, dep);
321 if ((haveAddon && !dep->MeetsVersion(version)) || (!haveAddon && !optional))
322 {
323 // we have it but our version isn't good enough, or we don't have it and we need it
324 if (!database.GetAddon(addonID, dep) || !dep->MeetsVersion(version))
325 {
326 // we don't have it in a repo, or we have it but the version isn't good enough, so dep isn't satisfied.
327 CLog::Log(LOGDEBUG, "CAddonInstallJob[%s]: requires %s version %s which is not available", addon->ID().c_str(), addonID.c_str(), version.asString().c_str());
328 database.Close();
329 return false;
330 }
331 }
332
333 // at this point we have our dep, or the dep is optional (and we don't have it) so check that it's OK as well
334 // TODO: should we assume that installed deps are OK?
335 if (dep && std::find(preDeps.begin(), preDeps.end(), dep->ID()) == preDeps.end())
336 {
337 if (!CheckDependencies(dep, preDeps, database))
338 {
339 database.Close();
340 preDeps.push_back(dep->ID());
341 return false;
342 }
343 }
344 }
345 database.Close();
346
347 return true;
348}
349
350CDateTime CAddonInstaller::LastRepoUpdate() const
351{
352 CDateTime update;
353 CAddonDatabase database;
354 if (!database.Open())
355 return update;
356
357 VECADDONS addons;
358 CAddonMgr::Get().GetAddons(ADDON_REPOSITORY, addons);
359 for (unsigned int i = 0; i < addons.size(); i++)
360 {
361 CDateTime lastUpdate = database.GetRepoTimestamp(addons[i]->ID());
362 if (lastUpdate.IsValid() && lastUpdate > update)
363 update = lastUpdate;
364 }
365
366 return update;
367}
368
369void CAddonInstaller::UpdateRepos(bool force, bool wait)
370{
371 CSingleLock lock(m_critSection);
372 if (m_repoUpdateJob)
373 {
374 if (wait)
375 {
376 // wait for our job to complete
377 lock.Leave();
378 CLog::Log(LOGDEBUG, "%s - waiting for repository update job to finish...", __FUNCTION__);
379 m_repoUpdateDone.Wait();
380 }
381 return;
382 }
383
384 // don't run repo update jobs while on the login screen which runs under the master profile
385 if((g_windowManager.GetActiveWindow() & WINDOW_ID_MASK) == WINDOW_LOGIN_SCREEN)
386 return;
387
388 if (!force && m_repoUpdateWatch.IsRunning() && m_repoUpdateWatch.GetElapsedSeconds() < 600)
389 return;
390
391 CAddonDatabase database;
392 if (!database.Open())
393 return;
394
395 m_repoUpdateWatch.StartZero();
396
397 VECADDONS addons;
398 if (CAddonMgr::Get().GetAddons(ADDON_REPOSITORY, addons))
399 {
400 for (const auto& repo : addons)
401 {
402 CDateTime lastUpdate = database.GetRepoTimestamp(repo->ID());
403 if (force || !lastUpdate.IsValid() || lastUpdate + CDateTimeSpan(0, 24, 0, 0) < CDateTime::GetCurrentDateTime()
404 || repo->Version() != database.GetRepoVersion(repo->ID()))
405 {
406 CLog::Log(LOGDEBUG, "Checking repositories for updates (triggered by %s)", repo->Name().c_str());
407 m_repoUpdateJob = CJobManager::GetInstance().AddJob(new CRepositoryUpdateJob(addons), this);
408 if (wait)
409 {
410 // wait for our job to complete
411 lock.Leave();
412 CLog::Log(LOGDEBUG, "%s - waiting for this repository update job to finish...", __FUNCTION__);
413 m_repoUpdateDone.Wait();
414 }
415
416 return;
417 }
418 }
419 }
420}
421
422bool CAddonInstaller::HasJob(const std::string& ID) const
423{
424 CSingleLock lock(m_critSection);
425 return m_downloadJobs.find(ID) != m_downloadJobs.end();
426}
427
428void CAddonInstaller::PrunePackageCache()
429{
430 std::map<std::string,CFileItemList*> packs;
431 int64_t size = EnumeratePackageFolder(packs);
432 int64_t limit = (int64_t)g_advancedSettings.m_addonPackageFolderSize * 1024 * 1024;
433 if (size < limit)
434 return;
435
436 // Prune packages
437 // 1. Remove the largest packages, leaving at least 2 for each add-on
438 CFileItemList items;
439 CAddonDatabase db;
440 db.Open();
441 for (std::map<std::string,CFileItemList*>::const_iterator it = packs.begin(); it != packs.end(); ++it)
442 {
443 it->second->Sort(SortByLabel, SortOrderDescending);
444 for (int j = 2; j < it->second->Size(); j++)
445 items.Add(CFileItemPtr(new CFileItem(*it->second->Get(j))));
446 }
447
448 items.Sort(SortBySize, SortOrderDescending);
449 int i = 0;
450 while (size > limit && i < items.Size())
451 {
452 size -= items[i]->m_dwSize;
453 db.RemovePackage(items[i]->GetPath());
454 CFileUtils::DeleteItem(items[i++], true);
455 }
456
457 if (size > limit)
458 {
459 // 2. Remove the oldest packages (leaving least 1 for each add-on)
460 items.Clear();
461 for (std::map<std::string,CFileItemList*>::iterator it = packs.begin(); it != packs.end(); ++it)
462 {
463 if (it->second->Size() > 1)
464 items.Add(CFileItemPtr(new CFileItem(*it->second->Get(1))));
465 }
466
467 items.Sort(SortByDate, SortOrderAscending);
468 i = 0;
469 while (size > limit && i < items.Size())
470 {
471 size -= items[i]->m_dwSize;
472 db.RemovePackage(items[i]->GetPath());
473 CFileUtils::DeleteItem(items[i++],true);
474 }
475 }
476
477 // clean up our mess
478 for (std::map<std::string,CFileItemList*>::iterator it = packs.begin(); it != packs.end(); ++it)
479 delete it->second;
480}
481
482int64_t CAddonInstaller::EnumeratePackageFolder(std::map<std::string,CFileItemList*>& result)
483{
484 CFileItemList items;
485 CDirectory::GetDirectory("special://home/addons/packages/",items,".zip",DIR_FLAG_NO_FILE_DIRS);
486 int64_t size = 0;
487 for (int i = 0; i < items.Size(); i++)
488 {
489 if (items[i]->m_bIsFolder)
490 continue;
491
492 size += items[i]->m_dwSize;
493 std::string pack,dummy;
494 AddonVersion::SplitFileName(pack, dummy, items[i]->GetLabel());
495 if (result.find(pack) == result.end())
496 result[pack] = new CFileItemList;
497 result[pack]->Add(CFileItemPtr(new CFileItem(*items[i])));
498 }
499
500 return size;
501}
502
503CAddonInstallJob::CAddonInstallJob(const AddonPtr &addon, const std::string &hash /* = "" */, bool update /* = false */, const std::string &referer /* = "" */)
504 : m_addon(addon),
505 m_hash(hash),
506 m_update(update),
507 m_referer(referer)
508{ }
509
510AddonPtr CAddonInstallJob::GetRepoForAddon(const AddonPtr& addon)
511{
512 AddonPtr repoPtr;
513
514 CAddonDatabase database;
515 if (!database.Open())
516 return repoPtr;
517
518 std::string repo;
519 if (!database.GetRepoForAddon(addon->ID(), repo))
520 return repoPtr;
521
522 if (!CAddonMgr::Get().GetAddon(repo, repoPtr))
523 return repoPtr;
524
525 if (std::dynamic_pointer_cast<CRepository>(repoPtr) == NULL)
526 {
527 repoPtr.reset();
528 return repoPtr;
529 }
530
531 return repoPtr;
532}
533
534bool CAddonInstallJob::GetAddonWithHash(const std::string& addonID, ADDON::AddonPtr& addon, std::string& hash)
535{
536 CAddonDatabase database;
537 if (!database.Open())
538 return false;
539
540 if (!database.GetAddon(addonID, addon))
541 return false;
542
543 AddonPtr ptr = GetRepoForAddon(addon);
544 if (ptr == NULL)
545 return false;
546
547 RepositoryPtr repo = std::dynamic_pointer_cast<CRepository>(ptr);
548 if (repo == NULL)
549 return false;
550
551 hash = repo->GetAddonHash(addon);
552 return true;
553}
554
555bool CAddonInstallJob::DoWork()
556{
557 SetTitle(StringUtils::Format(g_localizeStrings.Get(24057).c_str(), m_addon->Name().c_str()));
558 SetProgress(0);
559
560 // check whether all the dependencies are available or not
561 SetText(g_localizeStrings.Get(24058));
562 if (!CAddonInstaller::Get().CheckDependencies(m_addon))
563 {
564 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: dependency check failed", m_addon->ID().c_str());
565 ReportInstallError(m_addon->ID(), m_addon->ID(), g_localizeStrings.Get(24044));
566 return false;
567 }
568
569 AddonPtr repoPtr = GetRepoForAddon(m_addon);
570 std::string installFrom;
571 if (!repoPtr || repoPtr->Props().libname.empty())
572 {
573 // Addons are installed by downloading the .zip package on the server to the local
574 // packages folder, then extracting from the local .zip package into the addons folder
575 // Both these functions are achieved by "copying" using the vfs.
576
577 std::string dest = "special://home/addons/packages/";
578 std::string package = URIUtils::AddFileToFolder("special://home/addons/packages/",
579 URIUtils::GetFileName(m_addon->Path()));
580 if (URIUtils::HasSlashAtEnd(m_addon->Path()))
581 { // passed in a folder - all we need do is copy it across
582 installFrom = m_addon->Path();
583 }
584 else
585 {
586 CAddonDatabase db;
587 if (!db.Open())
588 {
589 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to open database", m_addon->ID().c_str());
590 ReportInstallError(m_addon->ID(), m_addon->ID());
591 return false;
592 }
593
594 std::string md5;
595 // check that we don't already have a valid copy
596 if (!m_hash.empty() && CFile::Exists(package))
597 {
598 if (db.GetPackageHash(m_addon->ID(), package, md5) && m_hash != md5)
599 {
600 db.RemovePackage(package);
601 CFile::Delete(package);
602 }
603 }
604
605 // zip passed in - download + extract
606 if (!CFile::Exists(package))
607 {
608 std::string path(m_addon->Path());
609 if (!m_referer.empty() && URIUtils::IsInternetStream(path))
610 {
611 CURL url(path);
612 url.SetProtocolOptions(m_referer);
613 path = url.Get();
614 }
615
616 if (!DownloadPackage(path, dest))
617 {
618 CFile::Delete(package);
619
620 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to download %s", m_addon->ID().c_str(), package.c_str());
621 ReportInstallError(m_addon->ID(), URIUtils::GetFileName(package));
622 return false;
623 }
624 }
625
626 // at this point we have the package - check that it is valid
627 SetText(g_localizeStrings.Get(24077));
628 if (!m_hash.empty())
629 {
630 md5 = CUtil::GetFileMD5(package);
631 if (!StringUtils::EqualsNoCase(md5, m_hash))
632 {
633 CFile::Delete(package);
634
635 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: MD5 mismatch after download %s", m_addon->ID().c_str(), package.c_str());
636 ReportInstallError(m_addon->ID(), URIUtils::GetFileName(package));
637 return false;
638 }
639
640 db.AddPackage(m_addon->ID(), package, md5);
641 }
642
643 // check the archive as well - should have just a single folder in the root
644 CURL archive = URIUtils::CreateArchivePath("zip", CURL(package), "");
645
646 CFileItemList archivedFiles;
647 CDirectory::GetDirectory(archive, archivedFiles);
648
649 if (archivedFiles.Size() != 1 || !archivedFiles[0]->m_bIsFolder)
650 {
651 // invalid package
652 db.RemovePackage(package);
653 CFile::Delete(package);
654
655 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: invalid package %s", m_addon->ID().c_str(), package.c_str());
656 ReportInstallError(m_addon->ID(), URIUtils::GetFileName(package));
657 return false;
658 }
659
660 installFrom = archivedFiles[0]->GetPath();
661 }
662 repoPtr.reset();
663 }
664
665 // run any pre-install functions
666 bool reloadAddon = OnPreInstall();
667
668 // perform install
669 if (!Install(installFrom, repoPtr))
670 return false;
671
672 // run any post-install guff
673 OnPostInstall(reloadAddon);
674
675 // and we're done!
676 MarkFinished();
677 return true;
678}
679
680bool CAddonInstallJob::DownloadPackage(const std::string &path, const std::string &dest)
681{
682 if (ShouldCancel(0, 1))
683 return false;
684
685 SetText(g_localizeStrings.Get(24078));
686
687 // need to download/copy the package first
688 CFileItemList list;
689 list.Add(CFileItemPtr(new CFileItem(path, false)));
690 list[0]->Select(true);
691
692 return DoFileOperation(CFileOperationJob::ActionReplace, list, dest, true);
693}
694
695bool CAddonInstallJob::DoFileOperation(FileAction action, CFileItemList &items, const std::string &file, bool useSameJob /* = true */)
696{
697 bool result = false;
698 if (useSameJob)
699 {
700 SetFileOperation(action, items, file);
701
702 // temporarily disable auto-closing so not to close the current progress indicator
703 bool autoClose = GetAutoClose();
704 if (autoClose)
705 SetAutoClose(false);
706 // temporarily disable updating title or text
707 bool updateInformation = GetUpdateInformation();
708 if (updateInformation)
709 SetUpdateInformation(false);
710
711 result = CFileOperationJob::DoWork();
712
713 SetUpdateInformation(updateInformation);
714 SetAutoClose(autoClose);
715 }
716 else
717 {
718 CFileOperationJob job(action, items, file);
719
720 // pass our progress indicators to the temporary job and only allow it to
721 // show progress updates (no title or text changes)
722 job.SetProgressIndicators(GetProgressBar(), GetProgressDialog(), GetUpdateProgress(), false);
723
724 result = job.DoWork();
725 }
726
727 return result;
728}
729
730bool CAddonInstallJob::OnPreInstall()
731{
732 return m_addon->OnPreInstall();
733}
734
735bool CAddonInstallJob::DeleteAddon(const std::string &addonFolder)
736{
737 CFileItemList list;
738 list.Add(CFileItemPtr(new CFileItem(addonFolder, true)));
739 list[0]->Select(true);
740
741 return DoFileOperation(CFileOperationJob::ActionDelete, list, "", false);
742}
743
744bool CAddonInstallJob::Install(const std::string &installFrom, const AddonPtr& repo)
745{
746 SetText(g_localizeStrings.Get(24079));
747 ADDONDEPS deps = m_addon->GetDeps();
748
749 unsigned int totalSteps = static_cast<unsigned int>(deps.size());
750 if (ShouldCancel(0, totalSteps))
751 return false;
752
753 // The first thing we do is install dependencies
754 std::string referer = StringUtils::Format("Referer=%s-%s.zip",m_addon->ID().c_str(),m_addon->Version().asString().c_str());
755 for (ADDONDEPS::iterator it = deps.begin(); it != deps.end(); ++it)
756 {
757 if (it->first != "xbmc.metadata")
758 {
759 const std::string &addonID = it->first;
760 const AddonVersion &version = it->second.first;
761 bool optional = it->second.second;
762 AddonPtr dependency;
763 bool haveAddon = CAddonMgr::Get().GetAddon(addonID, dependency);
764 if ((haveAddon && !dependency->MeetsVersion(version)) || (!haveAddon && !optional))
765 {
766 // we have it but our version isn't good enough, or we don't have it and we need it
767 bool force = dependency != NULL;
768
769 // dependency is already queued up for install - ::Install will fail
770 // instead we wait until the Job has finished. note that we
771 // recall install on purpose in case prior installation failed
772 if (CAddonInstaller::Get().HasJob(addonID))
773 {
774 while (CAddonInstaller::Get().HasJob(addonID))
775 Sleep(50);
776 force = false;
777
778 if (!CAddonMgr::Get().IsAddonInstalled(addonID))
779 {
780 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to install dependency %s", m_addon->ID().c_str(), addonID.c_str());
781 ReportInstallError(m_addon->ID(), m_addon->ID(), g_localizeStrings.Get(24085));
782 return false;
783 }
784 }
785 // don't have the addon or the addon isn't new enough - grab it (no new job for these)
786 else if (IsModal())
787 {
788 AddonPtr addon;
789 std::string hash;
790 if (!CAddonInstallJob::GetAddonWithHash(addonID, addon, hash))
791 {
792 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to find dependency %s", m_addon->ID().c_str(), addonID.c_str());
793 ReportInstallError(m_addon->ID(), m_addon->ID(), g_localizeStrings.Get(24085));
794 return false;
795 }
796
797 CAddonInstallJob dependencyJob(addon, hash, force, referer);
798
799 // pass our progress indicators to the temporary job and don't allow it to
800 // show progress or information updates (no progress, title or text changes)
801 dependencyJob.SetProgressIndicators(GetProgressBar(), GetProgressDialog(), false, false);
802
803 if (!dependencyJob.DoModal())
804 {
805 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to install dependency %s", m_addon->ID().c_str(), addonID.c_str());
806 ReportInstallError(m_addon->ID(), m_addon->ID(), g_localizeStrings.Get(24085));
807 return false;
808 }
809 }
810 else if (!CAddonInstaller::Get().Install(addonID, force, referer, false))
811 {
812 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: failed to install dependency %s", m_addon->ID().c_str(), addonID.c_str());
813 ReportInstallError(m_addon->ID(), m_addon->ID(), g_localizeStrings.Get(24085));
814 return false;
815 }
816 }
817 }
818
819 if (ShouldCancel(std::distance(deps.begin(), it), totalSteps))
820 return false;
821 }
822
823 SetText(g_localizeStrings.Get(24086));
824 SetProgress(0);
825
826 // now that we have all our dependencies, we can install our add-on
827 if (repo != NULL)
828 {
829 CFileItemList dummy;
830 std::string s = StringUtils::Format("plugin://%s/?action=install&package=%s&version=%s", repo->ID().c_str(),
831 m_addon->ID().c_str(), m_addon->Version().asString().c_str());
832 if (!CDirectory::GetDirectory(s, dummy))
833 {
834 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: installation of repository failed", m_addon->ID().c_str());
835 ReportInstallError(m_addon->ID(), m_addon->ID());
836 return false;
837 }
838 }
839 else
840 {
841 std::string addonFolder = installFrom;
842 URIUtils::RemoveSlashAtEnd(addonFolder);
843 addonFolder = URIUtils::AddFileToFolder("special://home/addons/", URIUtils::GetFileName(addonFolder));
844
845 CFileItemList install;
846 install.Add(CFileItemPtr(new CFileItem(installFrom, true)));
847 install[0]->Select(true);
848
849 AddonPtr addon;
850 if (!DoFileOperation(CFileOperationJob::ActionReplace, install, "special://home/addons/", false) ||
851 !CAddonMgr::Get().LoadAddonDescription(addonFolder, addon))
852 {
853 // failed extraction or failed to load addon description
854 DeleteAddon(addonFolder);
855
856 std::string addonID = URIUtils::GetFileName(addonFolder);
857 CLog::Log(LOGERROR, "CAddonInstallJob[%s]: could not read addon description of %s", addonID.c_str(), addonFolder.c_str());
858 ReportInstallError(addonID, addonID);
859 return false;
860 }
861
862 // Update the addon manager so that it has the newly installed add-on.
863 CAddonMgr::Get().FindAddons();
864 }
865 SetProgress(100);
866
867 return true;
868}
869
870void CAddonInstallJob::OnPostInstall(bool reloadAddon)
871{
872 if (!IsModal() && CSettings::Get().GetBool("general.addonnotifications"))
873 CGUIDialogKaiToast::QueueNotification(m_addon->Icon(), m_addon->Name(),
874 g_localizeStrings.Get(m_update ? 24065 : 24064),
875 TOAST_DISPLAY_TIME, false, TOAST_DISPLAY_TIME);
876
877 m_addon->OnPostInstall(reloadAddon, m_update, IsModal());
878}
879
880void CAddonInstallJob::ReportInstallError(const std::string& addonID, const std::string& fileName, const std::string& message /* = "" */)
881{
882 AddonPtr addon;
883 CAddonDatabase database;
884 if (database.Open())
885 {
886 database.GetAddon(addonID, addon);
887 database.Close();
888 }
889
890 MarkFinished();
891
892 std::string msg = message;
893 if (addon != NULL)
894 {
895 AddonPtr addon2;
896 CAddonMgr::Get().GetAddon(addonID, addon2);
897 if (msg.empty())
898 msg = g_localizeStrings.Get(addon2 != NULL ? 113 : 114);
899
900 if (IsModal())
901 CGUIDialogOK::ShowAndGetInput(m_addon->Name(), msg);
902 else
903 CGUIDialogKaiToast::QueueNotification(addon->Icon(), addon->Name(), msg, TOAST_DISPLAY_TIME, false);
904 }
905 else
906 {
907 if (msg.empty())
908 msg = g_localizeStrings.Get(114);
909 if (IsModal())
910 CGUIDialogOK::ShowAndGetInput(fileName, msg);
911 else
912 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, fileName, msg, TOAST_DISPLAY_TIME, false);
913 }
914}
915
916std::string CAddonInstallJob::AddonID() const
917{
918 return m_addon ? m_addon->ID() : "";
919}
920
921CAddonUnInstallJob::CAddonUnInstallJob(const AddonPtr &addon)
922 : m_addon(addon)
923{ }
924
925bool CAddonUnInstallJob::DoWork()
926{
927 m_addon->OnPreUnInstall();
928
929 AddonPtr repoPtr = CAddonInstallJob::GetRepoForAddon(m_addon);
930 RepositoryPtr therepo = std::dynamic_pointer_cast<CRepository>(repoPtr);
931 if (therepo != NULL && !therepo->Props().libname.empty())
932 {
933 CFileItemList dummy;
934 std::string s = StringUtils::Format("plugin://%s/?action=uninstall&package=%s", therepo->ID().c_str(), m_addon->ID().c_str());
935 if (!CDirectory::GetDirectory(s, dummy))
936 return false;
937 }
938 else if (!DeleteAddon(m_addon->Path()))
939 return false;
940
941 OnPostUnInstall();
942
943 return true;
944}
945
946bool CAddonUnInstallJob::DeleteAddon(const std::string &addonFolder)
947{
948 CFileItemList list;
949 list.Add(CFileItemPtr(new CFileItem(addonFolder, true)));
950 list[0]->Select(true);
951
952 SetFileOperation(CFileOperationJob::ActionDelete, list, "");
953 return CFileOperationJob::DoWork();
954}
955
956void CAddonUnInstallJob::OnPostUnInstall()
957{
958 bool bSave = false;
959 CFileItemList items;
960 XFILE::CFavouritesDirectory::Load(items);
961 for (int i = 0; i < items.Size(); i++)
962 {
963 if (items[i]->GetPath().find(m_addon->ID()) != std::string::npos)
964 {
965 items.Remove(items[i].get());
966 bSave = true;
967 }
968 }
969
970 if (bSave)
971 CFavouritesDirectory::Save(items);
972
973 m_addon->OnPostUnInstall();
974}
diff --git a/xbmc/addons/AddonInstaller.h b/xbmc/addons/AddonInstaller.h
new file mode 100644
index 0000000..aca93d8
--- /dev/null
+++ b/xbmc/addons/AddonInstaller.h
@@ -0,0 +1,229 @@
1#pragma once
2/*
3 * Copyright (C) 2011-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "utils/FileOperationJob.h"
23#include "addons/Addon.h"
24#include "utils/Stopwatch.h"
25#include "threads/Event.h"
26
27class CAddonDatabase;
28
29enum {
30 AUTO_UPDATES_ON = 0,
31 AUTO_UPDATES_NOTIFY,
32 AUTO_UPDATES_NEVER,
33 AUTO_UPDATES_MAX
34};
35
36class CAddonInstaller : public IJobCallback
37{
38public:
39 static CAddonInstaller &Get();
40
41 bool IsDownloading() const;
42 void GetInstallList(ADDON::VECADDONS &addons) const;
43 bool GetProgress(const std::string &addonID, unsigned int &percent) const;
44 bool Cancel(const std::string &addonID);
45
46 /*! \brief Installs the addon while showing a modal progress dialog
47 \param addonID the addon ID of the item to install.
48 \param addon [out] the installed addon for later use.
49 \param promptForInstall Whether or not to prompt the user before installing the addon.
50 \return true on successful install, false otherwise.
51 \sa Install
52 */
53 bool InstallModal(const std::string &addonID, ADDON::AddonPtr &addon, bool promptForInstall = true);
54
55 /*! \brief Install an addon if it is available in a repository
56 \param addonID the addon ID of the item to install
57 \param force whether to force the install even if the addon is already installed (eg for updating). Defaults to false.
58 \param referer string to use for referer for http fetch. Set to previous version when updating, parent when fetching a dependency
59 \param background whether to install in the background or not. Defaults to true.
60 \param modal whether to show a modal dialog when not installing in background
61 \return true on successful install, false on failure.
62 \sa DoInstall
63 */
64 bool Install(const std::string &addonID, bool force = false, const std::string &referer="", bool background = true, bool modal = false);
65
66 /*! \brief Install an addon from the given zip path
67 \param path the zip file to install from
68 \return true if successful, false otherwise
69 \sa DoInstall
70 */
71 bool InstallFromZip(const std::string &path);
72
73 /*! \brief Install a set of addons from the official repository (if needed)
74 \param addonIDs a set of addon IDs to install
75 */
76 void InstallFromXBMCRepo(const std::set<std::string> &addonIDs);
77
78 /*! \brief Check whether dependencies of an addon exist or are installable.
79 Iterates through the addon's dependencies, checking they're installed or installable.
80 Each dependency must also satisfies CheckDependencies in turn.
81 \param addon the addon to check
82 \param database the database instance to update. Defaults to NULL.
83 \return true if dependencies are available, false otherwise.
84 */
85 bool CheckDependencies(const ADDON::AddonPtr &addon, CAddonDatabase *database = NULL);
86
87 /*! \brief Update all repositories (if needed)
88 Runs through all available repositories and queues an update of them if they
89 need it (according to the set timeouts) or if forced. Optionally busy wait
90 until the repository updates are complete.
91 \param force whether we should run an update regardless of the normal update cycle. Defaults to false.
92 \param wait whether we should busy wait for the updates to be performed. Defaults to false.
93 */
94
95 /*! \brief Check if an installation job for a given add-on is already queued up
96 * \param ID The ID of the add-on
97 * \return true if a job exists, false otherwise
98 */
99 bool HasJob(const std::string& ID) const;
100
101 /*! \brief Fetch the last repository update time.
102 \return the last time a repository was updated.
103 */
104 CDateTime LastRepoUpdate() const;
105 void UpdateRepos(bool force = false, bool wait = false);
106
107 void OnJobComplete(unsigned int jobID, bool success, CJob* job);
108 void OnJobProgress(unsigned int jobID, unsigned int progress, unsigned int total, const CJob *job);
109
110 class CDownloadJob
111 {
112 public:
113 CDownloadJob(unsigned int id)
114 {
115 jobID = id;
116 progress = 0;
117 }
118 unsigned int jobID;
119 unsigned int progress;
120 };
121
122 typedef std::map<std::string, CDownloadJob> JobMap;
123
124private:
125 // private construction, and no assignements; use the provided singleton methods
126 CAddonInstaller();
127 CAddonInstaller(const CAddonInstaller&);
128 CAddonInstaller const& operator=(CAddonInstaller const&);
129 virtual ~CAddonInstaller();
130
131 /*! \brief Install an addon from a repository or zip
132 \param addon the AddonPtr describing the addon
133 \param hash the hash to verify the install. Defaults to "".
134 \param update whether this is an update of an existing addon, or a new install. Defaults to false.
135 \param referer string to use for referer for http fetch. Defaults to "".
136 \param background whether to install in the background or not. Defaults to true.
137 \return true on successful install, false on failure.
138 */
139 bool DoInstall(const ADDON::AddonPtr &addon, const std::string &hash = "", bool update = false, const std::string &referer = "", bool background = true, bool modal = false);
140
141 /*! \brief Check whether dependencies of an addon exist or are installable.
142 Iterates through the addon's dependencies, checking they're installed or installable.
143 Each dependency must also satisfies CheckDependencies in turn.
144 \param addon the addon to check
145 \param preDeps previous dependencies encountered during recursion. aids in avoiding infinite recursion
146 \param database database instance to update
147 \return true if dependencies are available, false otherwise.
148 */
149 bool CheckDependencies(const ADDON::AddonPtr &addon, std::vector<std::string>& preDeps, CAddonDatabase &database);
150
151 void PrunePackageCache();
152 int64_t EnumeratePackageFolder(std::map<std::string,CFileItemList*>& result);
153
154 CCriticalSection m_critSection;
155 JobMap m_downloadJobs;
156 CStopWatch m_repoUpdateWatch; ///< repository updates are done based on this counter
157 unsigned int m_repoUpdateJob; ///< the job ID of the repository updates
158 CEvent m_repoUpdateDone; ///< event set when the repository updates are complete
159};
160
161class CAddonInstallJob : public CFileOperationJob
162{
163public:
164 CAddonInstallJob(const ADDON::AddonPtr &addon, const std::string &hash = "", bool update = false, const std::string &referer = "");
165
166 virtual bool DoWork();
167
168 /*! \brief return the id of the addon being installed
169 \return id of the installing addon
170 */
171 std::string AddonID() const;
172
173 /*! \brief Find which repository hosts an add-on
174 * \param addon The add-on to find the repository for
175 * \return The hosting repository
176 */
177 static ADDON::AddonPtr GetRepoForAddon(const ADDON::AddonPtr& addon);
178
179 /*! \brief Find the add-on and itshash for the given add-on ID
180 * \param addonID ID of the add-on to find
181 * \param addon Add-on with the given add-on ID
182 * \param hash Hash of the add-on
183 * \return True if the add-on and its hash were found, false otherwise.
184 */
185 static bool GetAddonWithHash(const std::string& addonID, ADDON::AddonPtr& addon, std::string& hash);
186
187private:
188 bool OnPreInstall();
189 void OnPostInstall(bool reloadAddon);
190 bool Install(const std::string &installFrom, const ADDON::AddonPtr& repo = ADDON::AddonPtr());
191 bool DownloadPackage(const std::string &path, const std::string &dest);
192
193 /*! \brief Delete an addon following install failure
194 \param addonFolder - the folder to delete
195 */
196 bool DeleteAddon(const std::string &addonFolder);
197
198 bool DoFileOperation(FileAction action, CFileItemList &items, const std::string &file, bool useSameJob = true);
199
200 /*! \brief Queue a notification for addon installation/update failure
201 \param addonID - addon id
202 \param fileName - filename which is shown in case the addon id is unknown
203 \param message - error message to be displayed
204 */
205 void ReportInstallError(const std::string& addonID, const std::string& fileName, const std::string& message = "");
206
207 ADDON::AddonPtr m_addon;
208 std::string m_hash;
209 bool m_update;
210 std::string m_referer;
211};
212
213class CAddonUnInstallJob : public CFileOperationJob
214{
215public:
216 CAddonUnInstallJob(const ADDON::AddonPtr &addon);
217
218 virtual bool DoWork();
219
220private:
221 /*! \brief Delete an addon following install failure
222 \param addonFolder - the folder to delete
223 */
224 bool DeleteAddon(const std::string &addonFolder);
225
226 void OnPostUnInstall();
227
228 ADDON::AddonPtr m_addon;
229};
diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp
new file mode 100644
index 0000000..9ab5c31
--- /dev/null
+++ b/xbmc/addons/AddonManager.cpp
@@ -0,0 +1,1030 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#include "AddonManager.h"
21#include "Addon.h"
22#include "AudioEncoder.h"
23#include "DllLibCPluff.h"
24#include "utils/StringUtils.h"
25#include "utils/JobManager.h"
26#include "threads/SingleLock.h"
27#include "FileItem.h"
28#include "LangInfo.h"
29#include "settings/AdvancedSettings.h"
30#include "settings/Settings.h"
31#include "utils/log.h"
32#include "utils/XBMCTinyXML.h"
33#ifdef HAS_VISUALISATION
34#include "Visualisation.h"
35#endif
36#ifdef HAS_SCREENSAVER
37#include "ScreenSaver.h"
38#endif
39#ifdef HAS_PVRCLIENTS
40#include "DllPVRClient.h"
41#include "pvr/addons/PVRClient.h"
42#endif
43//#ifdef HAS_SCRAPERS
44#include "Scraper.h"
45//#endif
46#include "PluginSource.h"
47#include "Repository.h"
48#include "Skin.h"
49#include "Service.h"
50#include "ContextItemAddon.h"
51#include "Util.h"
52#include "addons/Webinterface.h"
53
54using namespace std;
55using namespace XFILE;
56
57namespace ADDON
58{
59
60cp_log_severity_t clog_to_cp(int lvl);
61void cp_fatalErrorHandler(const char *msg);
62void cp_logger(cp_log_severity_t level, const char *msg, const char *apid, void *user_data);
63
64/**********************************************************
65 * CAddonMgr
66 *
67 */
68
69map<TYPE, IAddonMgrCallback*> CAddonMgr::m_managers;
70
71AddonPtr CAddonMgr::Factory(const cp_extension_t *props)
72{
73 if (!PlatformSupportsAddon(props->plugin))
74 return AddonPtr();
75
76 /* Check if user directories need to be created */
77 const cp_cfg_element_t *settings = GetExtElement(props->configuration, "settings");
78 if (settings)
79 CheckUserDirs(settings);
80
81 const TYPE type = TranslateType(props->ext_point_id);
82 switch (type)
83 {
84 case ADDON_PLUGIN:
85 case ADDON_SCRIPT:
86 return AddonPtr(new CPluginSource(props));
87 case ADDON_SCRIPT_LIBRARY:
88 case ADDON_SCRIPT_LYRICS:
89 case ADDON_SCRIPT_MODULE:
90 case ADDON_SUBTITLE_MODULE:
91 return AddonPtr(new CAddon(props));
92 case ADDON_WEB_INTERFACE:
93 return AddonPtr(new CWebinterface(props));
94 case ADDON_SCRIPT_WEATHER:
95 {
96 // Eden (API v2.0) broke old weather add-ons
97 AddonPtr result(new CAddon(props));
98 AddonVersion ver1 = result->GetDependencyVersion("xbmc.python");
99 AddonVersion ver2 = AddonVersion("2.0");
100 if (ver1 < ver2)
101 {
102 CLog::Log(LOGINFO,"%s: Weather add-ons for api < 2.0 unsupported (%s)",__FUNCTION__,result->ID().c_str());
103 return AddonPtr();
104 }
105 return result;
106 }
107 case ADDON_SERVICE:
108 return AddonPtr(new CService(props));
109 case ADDON_SCRAPER_ALBUMS:
110 case ADDON_SCRAPER_ARTISTS:
111 case ADDON_SCRAPER_MOVIES:
112 case ADDON_SCRAPER_MUSICVIDEOS:
113 case ADDON_SCRAPER_TVSHOWS:
114 case ADDON_SCRAPER_LIBRARY:
115 return AddonPtr(new CScraper(props));
116 case ADDON_VIZ:
117 case ADDON_SCREENSAVER:
118 case ADDON_PVRDLL:
119 case ADDON_AUDIOENCODER:
120 { // begin temporary platform handling for Dlls
121 // ideally platforms issues will be handled by C-Pluff
122 // this is not an attempt at a solution
123 std::string value;
124 if (type == ADDON_SCREENSAVER && 0 == strnicmp(props->plugin->identifier, "screensaver.xbmc.builtin.", 25))
125 { // built in screensaver
126 return AddonPtr(new CAddon(props));
127 }
128 if (type == ADDON_SCREENSAVER)
129 { // Python screensaver
130 std::string library = CAddonMgr::Get().GetExtValue(props->configuration, "@library");
131 if (URIUtils::HasExtension(library, ".py"))
132 return AddonPtr(new CScreenSaver(props));
133 }
134 if (type == ADDON_AUDIOENCODER && 0 == strncmp(props->plugin->identifier,
135 "audioencoder.xbmc.builtin.", 26))
136 { // built in audio encoder
137 return AddonPtr(new CAudioEncoder(props));
138 }
139 std::string tograb;
140#if defined(TARGET_ANDROID)
141 tograb = "@library_android";
142#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
143 tograb = "@library_linux";
144#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
145 tograb = "@library_windx";
146#elif defined(TARGET_DARWIN)
147 tograb = "@library_osx";
148#endif
149 value = GetExtValue(props->plugin->extensions->configuration, tograb.c_str());
150 if (value.empty())
151 break;
152 if (type == ADDON_VIZ)
153 {
154#if defined(HAS_VISUALISATION)
155 return AddonPtr(new CVisualisation(props));
156#endif
157 }
158 else if (type == ADDON_PVRDLL)
159 {
160#ifdef HAS_PVRCLIENTS
161 return AddonPtr(new PVR::CPVRClient(props));
162#endif
163 }
164 else if (type == ADDON_AUDIOENCODER)
165 return AddonPtr(new CAudioEncoder(props));
166 else
167 return AddonPtr(new CScreenSaver(props));
168 }
169 case ADDON_SKIN:
170 return AddonPtr(new CSkinInfo(props));
171 case ADDON_VIZ_LIBRARY:
172 return AddonPtr(new CAddonLibrary(props));
173 case ADDON_REPOSITORY:
174 return AddonPtr(new CRepository(props));
175 case ADDON_CONTEXT_ITEM:
176 return AddonPtr(new CContextItemAddon(props));
177 default:
178 break;
179 }
180 return AddonPtr();
181}
182
183bool CAddonMgr::CheckUserDirs(const cp_cfg_element_t *settings)
184{
185 if (!settings)
186 return false;
187
188 const cp_cfg_element_t *userdirs = GetExtElement((cp_cfg_element_t *)settings, "userdirs");
189 if (!userdirs)
190 return false;
191
192 ELEMENTS elements;
193 if (!GetExtElements((cp_cfg_element_t *)userdirs, "userdir", elements))
194 return false;
195
196 ELEMENTS::iterator itr = elements.begin();
197 while (itr != elements.end())
198 {
199 std::string path = GetExtValue(*itr++, "@path");
200 if (!CDirectory::Exists(path))
201 {
202 if (!CUtil::CreateDirectoryEx(path))
203 {
204 CLog::Log(LOGERROR, "CAddonMgr::CheckUserDirs: Unable to create directory %s.", path.c_str());
205 return false;
206 }
207 }
208 }
209
210 return true;
211}
212
213CAddonMgr::CAddonMgr()
214{
215 m_cpluff = NULL;
216}
217
218CAddonMgr::~CAddonMgr()
219{
220 DeInit();
221}
222
223CAddonMgr &CAddonMgr::Get()
224{
225 static CAddonMgr sAddonMgr;
226 return sAddonMgr;
227}
228
229IAddonMgrCallback* CAddonMgr::GetCallbackForType(TYPE type)
230{
231 if (m_managers.find(type) == m_managers.end())
232 return NULL;
233 else
234 return m_managers[type];
235}
236
237bool CAddonMgr::RegisterAddonMgrCallback(const TYPE type, IAddonMgrCallback* cb)
238{
239 if (cb == NULL)
240 return false;
241
242 m_managers.erase(type);
243 m_managers[type] = cb;
244
245 return true;
246}
247
248void CAddonMgr::UnregisterAddonMgrCallback(TYPE type)
249{
250 m_managers.erase(type);
251}
252
253bool CAddonMgr::Init()
254{
255 m_cpluff = new DllLibCPluff;
256 m_cpluff->Load();
257
258 m_database.Open();
259
260 if (!m_cpluff->IsLoaded())
261 {
262 CLog::Log(LOGERROR, "ADDONS: Fatal Error, could not load libcpluff");
263 return false;
264 }
265
266 m_cpluff->set_fatal_error_handler(cp_fatalErrorHandler);
267
268 cp_status_t status;
269 status = m_cpluff->init();
270 if (status != CP_OK)
271 {
272 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_init() returned status: %i", status);
273 return false;
274 }
275
276 //TODO could separate addons into different contexts
277 // would allow partial unloading of addon framework
278 m_cp_context = m_cpluff->create_context(&status);
279 assert(m_cp_context);
280 status = m_cpluff->register_pcollection(m_cp_context, CSpecialProtocol::TranslatePath("special://home/addons").c_str());
281 if (status != CP_OK)
282 {
283 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_pcollection() returned status: %i", status);
284 return false;
285 }
286
287 status = m_cpluff->register_pcollection(m_cp_context, CSpecialProtocol::TranslatePath("special://xbmc/addons").c_str());
288 if (status != CP_OK)
289 {
290 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_pcollection() returned status: %i", status);
291 return false;
292 }
293
294 status = m_cpluff->register_pcollection(m_cp_context, CSpecialProtocol::TranslatePath("special://xbmcbin/addons").c_str());
295 if (status != CP_OK)
296 {
297 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_pcollection() returned status: %i", status);
298 return false;
299 }
300
301 status = m_cpluff->register_logger(m_cp_context, cp_logger,
302 &CAddonMgr::Get(), clog_to_cp(g_advancedSettings.m_logLevel));
303 if (status != CP_OK)
304 {
305 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_logger() returned status: %i", status);
306 return false;
307 }
308
309 FindAddons();
310
311 VECADDONS repos;
312 if (GetAddons(ADDON_REPOSITORY, repos))
313 {
314 VECADDONS::iterator it = repos.begin();
315 for (;it != repos.end(); ++it)
316 CLog::Log(LOGNOTICE, "ADDONS: Using repository %s", (*it)->ID().c_str());
317 }
318
319 return true;
320}
321
322void CAddonMgr::DeInit()
323{
324 if (m_cpluff)
325 m_cpluff->destroy();
326 delete m_cpluff;
327 m_cpluff = NULL;
328 m_database.Close();
329 m_disabled.clear();
330}
331
332bool CAddonMgr::HasAddons(const TYPE &type, bool enabled /*= true*/)
333{
334 // TODO: This isn't particularly efficient as we create an addon type for each addon using the Factory, just so
335 // we can check addon dependencies in the addon constructor.
336 VECADDONS addons;
337 return GetAddons(type, addons, enabled);
338}
339
340bool CAddonMgr::GetAllAddons(VECADDONS &addons, bool enabled /*= true*/, bool allowRepos /* = false */)
341{
342 for (int i = ADDON_UNKNOWN+1; i < ADDON_MAX; ++i)
343 {
344 if (!allowRepos && ADDON_REPOSITORY == (TYPE)i)
345 continue;
346 VECADDONS temp;
347 if (CAddonMgr::Get().GetAddons((TYPE)i, temp, enabled))
348 addons.insert(addons.end(), temp.begin(), temp.end());
349 }
350 return !addons.empty();
351}
352
353void CAddonMgr::AddToUpdateableAddons(AddonPtr &pAddon)
354{
355 CSingleLock lock(m_critSection);
356 m_updateableAddons.push_back(pAddon);
357}
358
359void CAddonMgr::RemoveFromUpdateableAddons(AddonPtr &pAddon)
360{
361 CSingleLock lock(m_critSection);
362 VECADDONS::iterator it = std::find(m_updateableAddons.begin(), m_updateableAddons.end(), pAddon);
363
364 if(it != m_updateableAddons.end())
365 {
366 m_updateableAddons.erase(it);
367 }
368}
369
370struct AddonIdFinder
371{
372 AddonIdFinder(const std::string& id)
373 : m_id(id)
374 {}
375
376 bool operator()(const AddonPtr& addon)
377 {
378 return m_id == addon->ID();
379 }
380 private:
381 std::string m_id;
382};
383
384bool CAddonMgr::ReloadSettings(const std::string &id)
385{
386 CSingleLock lock(m_critSection);
387 VECADDONS::iterator it = std::find_if(m_updateableAddons.begin(), m_updateableAddons.end(), AddonIdFinder(id));
388
389 if( it != m_updateableAddons.end())
390 {
391 return (*it)->ReloadSettings();
392 }
393 return false;
394}
395
396bool CAddonMgr::GetAllOutdatedAddons(VECADDONS &addons, bool getLocalVersion /*= false*/)
397{
398 CSingleLock lock(m_critSection);
399 for (int i = ADDON_UNKNOWN+1; i < ADDON_MAX; ++i)
400 {
401 VECADDONS temp;
402 if (CAddonMgr::Get().GetAddons((TYPE)i, temp, true))
403 {
404 AddonPtr repoAddon;
405 for (unsigned int j = 0; j < temp.size(); j++)
406 {
407 // Ignore duplicates due to add-ons with multiple extension points
408 bool found = false;
409 for (VECADDONS::const_iterator addonIt = addons.begin(); addonIt != addons.end(); ++addonIt)
410 {
411 if ((*addonIt)->ID() == temp[j]->ID())
412 found = true;
413 }
414
415 if (found || !m_database.GetAddon(temp[j]->ID(), repoAddon))
416 continue;
417
418 if (temp[j]->Version() < repoAddon->Version() &&
419 !m_database.IsAddonBlacklisted(temp[j]->ID(),
420 repoAddon->Version().asString().c_str()))
421 {
422 if (getLocalVersion)
423 repoAddon->Props().version = temp[j]->Version();
424 addons.push_back(repoAddon);
425 }
426 }
427 }
428 }
429 return !addons.empty();
430}
431
432bool CAddonMgr::HasOutdatedAddons()
433{
434 VECADDONS dummy;
435 return GetAllOutdatedAddons(dummy);
436}
437
438bool CAddonMgr::GetAddons(const TYPE &type, VECADDONS &addons, bool enabled /* = true */)
439{
440 CSingleLock lock(m_critSection);
441 addons.clear();
442 if (!m_cp_context)
443 return false;
444 cp_status_t status;
445 int num;
446 std::string ext_point(TranslateType(type));
447 cp_extension_t **exts = m_cpluff->get_extensions_info(m_cp_context, ext_point.c_str(), &status, &num);
448 for(int i=0; i <num; i++)
449 {
450 const cp_extension_t *props = exts[i];
451 if (IsAddonDisabled(props->plugin->identifier) != enabled)
452 {
453 AddonPtr addon(Factory(props));
454 if (addon)
455 {
456 if (enabled)
457 {
458 // if the addon has a running instance, grab that
459 AddonPtr runningAddon = addon->GetRunningInstance();
460 if (runningAddon)
461 addon = runningAddon;
462 }
463 addons.push_back(addon);
464 }
465 }
466 }
467 m_cpluff->release_info(m_cp_context, exts);
468 return addons.size() > 0;
469}
470
471bool CAddonMgr::GetAddon(const std::string &str, AddonPtr &addon, const TYPE &type/*=ADDON_UNKNOWN*/, bool enabledOnly /*= true*/)
472{
473 CSingleLock lock(m_critSection);
474
475 cp_status_t status;
476 cp_plugin_info_t *cpaddon = m_cpluff->get_plugin_info(m_cp_context, str.c_str(), &status);
477 if (status == CP_OK && cpaddon)
478 {
479 addon = GetAddonFromDescriptor(cpaddon, type==ADDON_UNKNOWN?"":TranslateType(type));
480 m_cpluff->release_info(m_cp_context, cpaddon);
481
482 if (addon)
483 {
484 if (enabledOnly && IsAddonDisabled(addon->ID()))
485 return false;
486
487 // if the addon has a running instance, grab that
488 AddonPtr runningAddon = addon->GetRunningInstance();
489 if (runningAddon)
490 addon = runningAddon;
491 }
492 return NULL != addon.get();
493 }
494 if (cpaddon)
495 m_cpluff->release_info(m_cp_context, cpaddon);
496
497 return false;
498}
499
500//TODO handle all 'default' cases here, not just scrapers & vizs
501bool CAddonMgr::GetDefault(const TYPE &type, AddonPtr &addon)
502{
503 std::string setting;
504 switch (type)
505 {
506 case ADDON_VIZ:
507 setting = CSettings::Get().GetString("musicplayer.visualisation");
508 break;
509 case ADDON_SCREENSAVER:
510 setting = CSettings::Get().GetString("screensaver.mode");
511 break;
512 case ADDON_SCRAPER_ALBUMS:
513 setting = CSettings::Get().GetString("musiclibrary.albumsscraper");
514 break;
515 case ADDON_SCRAPER_ARTISTS:
516 setting = CSettings::Get().GetString("musiclibrary.artistsscraper");
517 break;
518 case ADDON_SCRAPER_MOVIES:
519 setting = CSettings::Get().GetString("scrapers.moviesdefault");
520 break;
521 case ADDON_SCRAPER_MUSICVIDEOS:
522 setting = CSettings::Get().GetString("scrapers.musicvideosdefault");
523 break;
524 case ADDON_SCRAPER_TVSHOWS:
525 setting = CSettings::Get().GetString("scrapers.tvshowsdefault");
526 break;
527 case ADDON_WEB_INTERFACE:
528 setting = CSettings::Get().GetString("services.webskin");
529 break;
530 default:
531 return false;
532 }
533 return GetAddon(setting, addon, type);
534}
535
536bool CAddonMgr::SetDefault(const TYPE &type, const std::string &addonID)
537{
538 switch (type)
539 {
540 case ADDON_VIZ:
541 CSettings::Get().SetString("musicplayer.visualisation",addonID);
542 break;
543 case ADDON_SCREENSAVER:
544 CSettings::Get().SetString("screensaver.mode",addonID);
545 break;
546 case ADDON_SCRAPER_ALBUMS:
547 CSettings::Get().SetString("musiclibrary.albumsscraper",addonID);
548 break;
549 case ADDON_SCRAPER_ARTISTS:
550 CSettings::Get().SetString("musiclibrary.artistsscraper",addonID);
551 break;
552 case ADDON_SCRAPER_MOVIES:
553 CSettings::Get().SetString("scrapers.moviesdefault",addonID);
554 break;
555 case ADDON_SCRAPER_MUSICVIDEOS:
556 CSettings::Get().SetString("scrapers.musicvideosdefault",addonID);
557 break;
558 case ADDON_SCRAPER_TVSHOWS:
559 CSettings::Get().SetString("scrapers.tvshowsdefault",addonID);
560 break;
561 default:
562 return false;
563 }
564
565 return true;
566}
567
568std::string CAddonMgr::GetString(const std::string &id, const int number)
569{
570 AddonPtr addon;
571 if (GetAddon(id, addon))
572 return addon->GetString(number);
573
574 return "";
575}
576
577void CAddonMgr::FindAddons()
578{
579 {
580 CSingleLock lock(m_critSection);
581 if (m_cpluff && m_cp_context)
582 {
583 m_cpluff->scan_plugins(m_cp_context, CP_SP_UPGRADE);
584 SetChanged();
585 }
586 }
587 NotifyObservers(ObservableMessageAddons);
588}
589
590void CAddonMgr::RemoveAddon(const std::string& ID)
591{
592 if (m_cpluff && m_cp_context)
593 {
594 m_cpluff->uninstall_plugin(m_cp_context,ID.c_str());
595 SetChanged();
596 NotifyObservers(ObservableMessageAddons);
597 }
598}
599
600bool CAddonMgr::DisableAddon(const std::string& ID, bool disable)
601{
602 CSingleLock lock(m_critSection);
603 if (m_database.DisableAddon(ID, disable))
604 {
605 m_disabled[ID] = disable;
606 return true;
607 }
608
609 return false;
610}
611
612bool CAddonMgr::IsAddonDisabled(const std::string& ID)
613{
614 CSingleLock lock(m_critSection);
615 std::map<std::string, bool>::const_iterator it = m_disabled.find(ID);
616 if (it != m_disabled.end())
617 return it->second;
618
619 bool ret = m_database.IsAddonDisabled(ID);
620 m_disabled.insert(pair<std::string, bool>(ID, ret));
621
622 return ret;
623}
624
625bool CAddonMgr::CanAddonBeDisabled(const std::string& ID)
626{
627 if (ID.empty())
628 return false;
629
630 CSingleLock lock(m_critSection);
631 AddonPtr localAddon;
632 // can't disable an addon that isn't installed
633 if (!IsAddonInstalled(ID, localAddon))
634 return false;
635
636 // can't disable an addon that is in use
637 if (localAddon->IsInUse())
638 return false;
639
640 // installed PVR addons can always be disabled
641 if (localAddon->Type() == ADDON_PVRDLL)
642 return true;
643
644 std::string systemAddonsPath = CSpecialProtocol::TranslatePath("special://xbmc/addons");
645 // can't disable system addons
646 if (StringUtils::StartsWith(localAddon->Path(), systemAddonsPath))
647 return false;
648
649 return true;
650}
651
652bool CAddonMgr::IsAddonInstalled(const std::string& ID)
653{
654 AddonPtr tmp;
655 return IsAddonInstalled(ID, tmp);
656}
657
658bool CAddonMgr::IsAddonInstalled(const std::string& ID, AddonPtr& addon)
659{
660 return GetAddon(ID, addon, ADDON_UNKNOWN, false);
661}
662
663bool CAddonMgr::CanAddonBeInstalled(const std::string& ID)
664{
665 if (ID.empty())
666 return false;
667
668 CSingleLock lock(m_critSection);
669 // can't install already installed addon
670 if (IsAddonInstalled(ID))
671 return false;
672
673 // can't install broken addons
674 if (!m_database.IsAddonBroken(ID).empty())
675 return false;
676
677 return true;
678}
679
680bool CAddonMgr::CanAddonBeInstalled(const AddonPtr& addon)
681{
682 if (addon == NULL)
683 return false;
684
685 CSingleLock lock(m_critSection);
686 // can't install already installed addon
687 if (IsAddonInstalled(addon->ID()))
688 return false;
689
690 // can't install broken addons
691 if (!addon->Props().broken.empty())
692 return false;
693
694 return true;
695}
696
697std::string CAddonMgr::GetTranslatedString(const cp_cfg_element_t *root, const char *tag)
698{
699 if (!root)
700 return "";
701
702 const cp_cfg_element_t *eng = NULL;
703 for (unsigned int i = 0; i < root->num_children; i++)
704 {
705 const cp_cfg_element_t &child = root->children[i];
706 if (strcmp(tag, child.name) == 0)
707 { // see if we have a "lang" attribute
708 const char *lang = m_cpluff->lookup_cfg_value((cp_cfg_element_t*)&child, "@lang");
709 if (lang && 0 == strcmp(lang,g_langInfo.GetLanguageLocale().c_str()))
710 return child.value ? child.value : "";
711 if (!lang || 0 == strcmp(lang, "en"))
712 eng = &child;
713 }
714 }
715 return (eng && eng->value) ? eng->value : "";
716}
717
718AddonPtr CAddonMgr::AddonFromProps(AddonProps& addonProps)
719{
720 switch (addonProps.type)
721 {
722 case ADDON_PLUGIN:
723 case ADDON_SCRIPT:
724 return AddonPtr(new CPluginSource(addonProps));
725 case ADDON_SCRIPT_LIBRARY:
726 case ADDON_SCRIPT_LYRICS:
727 case ADDON_SCRIPT_WEATHER:
728 case ADDON_SCRIPT_MODULE:
729 case ADDON_SUBTITLE_MODULE:
730 return AddonPtr(new CAddon(addonProps));
731 case ADDON_WEB_INTERFACE:
732 return AddonPtr(new CWebinterface(addonProps));
733 case ADDON_SERVICE:
734 return AddonPtr(new CService(addonProps));
735 case ADDON_SCRAPER_ALBUMS:
736 case ADDON_SCRAPER_ARTISTS:
737 case ADDON_SCRAPER_MOVIES:
738 case ADDON_SCRAPER_MUSICVIDEOS:
739 case ADDON_SCRAPER_TVSHOWS:
740 case ADDON_SCRAPER_LIBRARY:
741 return AddonPtr(new CScraper(addonProps));
742 case ADDON_SKIN:
743 return AddonPtr(new CSkinInfo(addonProps));
744#if defined(HAS_VISUALISATION)
745 case ADDON_VIZ:
746 return AddonPtr(new CVisualisation(addonProps));
747#endif
748 case ADDON_SCREENSAVER:
749 return AddonPtr(new CScreenSaver(addonProps));
750 case ADDON_VIZ_LIBRARY:
751 return AddonPtr(new CAddonLibrary(addonProps));
752 case ADDON_PVRDLL:
753 return AddonPtr(new PVR::CPVRClient(addonProps));
754 case ADDON_AUDIOENCODER:
755 return AddonPtr(new CAudioEncoder(addonProps));
756 case ADDON_REPOSITORY:
757 return AddonPtr(new CRepository(addonProps));
758 case ADDON_CONTEXT_ITEM:
759 return AddonPtr(new CContextItemAddon(addonProps));
760 default:
761 break;
762 }
763 return AddonPtr();
764}
765
766/*
767 * libcpluff interaction
768 */
769
770bool CAddonMgr::PlatformSupportsAddon(const cp_plugin_info_t *plugin) const
771{
772 if (!plugin || !plugin->num_extensions)
773 return false;
774 const cp_extension_t *metadata = GetExtension(plugin, "xbmc.addon.metadata"); //<! backword compatibilty
775 if (!metadata)
776 metadata = CAddonMgr::Get().GetExtension(plugin, "kodi.addon.metadata");
777 if (!metadata)
778 return false;
779
780 vector<std::string> platforms;
781 if (CAddonMgr::Get().GetExtList(metadata->configuration, "platform", platforms))
782 {
783 for (vector<std::string>::const_iterator platform = platforms.begin(); platform != platforms.end(); ++platform)
784 {
785 if (*platform == "all")
786 return true;
787#if defined(TARGET_ANDROID)
788 if (*platform == "android")
789#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
790 if (*platform == "linux")
791#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
792 if (*platform == "windx")
793#elif defined(TARGET_DARWIN_OSX)
794// Remove this after Frodo and add an architecture filter
795// in addition to platform.
796#if defined(__x86_64__)
797 if (*platform == "osx64" || *platform == "osx")
798#else
799 if (*platform == "osx32" || *platform == "osx")
800#endif
801#elif defined(TARGET_DARWIN_IOS)
802 if (*platform == "ios")
803#endif
804 return true;
805 }
806 return false; // no <platform> works for us
807 }
808 return true; // assume no <platform> is equivalent to <platform>all</platform>
809}
810
811const cp_cfg_element_t *CAddonMgr::GetExtElement(cp_cfg_element_t *base, const char *path)
812{
813 const cp_cfg_element_t *element = NULL;
814 if (base)
815 element = m_cpluff->lookup_cfg_element(base, path);
816 return element;
817}
818
819bool CAddonMgr::GetExtElements(cp_cfg_element_t *base, const char *path, ELEMENTS &elements)
820{
821 if (!base || !path)
822 return false;
823
824 for (unsigned int i = 0; i < base->num_children; i++)
825 {
826 std::string temp = base->children[i].name;
827 if (!temp.compare(path))
828 elements.push_back(&base->children[i]);
829 }
830
831 return !elements.empty();
832}
833
834const cp_extension_t *CAddonMgr::GetExtension(const cp_plugin_info_t *props, const char *extension) const
835{
836 if (!props)
837 return NULL;
838 for (unsigned int i = 0; i < props->num_extensions; ++i)
839 {
840 if (0 == strcmp(props->extensions[i].ext_point_id, extension))
841 return &props->extensions[i];
842 }
843 return NULL;
844}
845
846std::string CAddonMgr::GetExtValue(cp_cfg_element_t *base, const char *path)
847{
848 const char *value = "";
849 if (base && (value = m_cpluff->lookup_cfg_value(base, path)))
850 return value;
851 else
852 return "";
853}
854
855bool CAddonMgr::GetExtList(cp_cfg_element_t *base, const char *path, vector<std::string> &result) const
856{
857 result.clear();
858 if (!base || !path)
859 return false;
860 const char *all = m_cpluff->lookup_cfg_value(base, path);
861 if (!all || *all == 0)
862 return false;
863 StringUtils::Tokenize(all, result, ' ');
864 return true;
865}
866
867AddonPtr CAddonMgr::GetAddonFromDescriptor(const cp_plugin_info_t *info,
868 const std::string& type)
869{
870 if (!info)
871 return AddonPtr();
872
873 if (!info->extensions && type.empty())
874 { // no extensions, so we need only the dep information
875 return AddonPtr(new CAddon(info));
876 }
877
878 // grab a relevant extension point, ignoring our kodi.addon.metadata extension point
879 for (unsigned int i = 0; i < info->num_extensions; ++i)
880 {
881 if (0 != strcmp("xbmc.addon.metadata" , info->extensions[i].ext_point_id) && //<! backword compatibilty
882 0 != strcmp("kodi.addon.metadata" , info->extensions[i].ext_point_id) &&
883 (type.empty() || 0 == strcmp(type.c_str(), info->extensions[i].ext_point_id)))
884 { // note that Factory takes care of whether or not we have platform support
885 return Factory(&info->extensions[i]);
886 }
887 }
888 return AddonPtr();
889}
890
891// FIXME: This function may not be required
892bool CAddonMgr::LoadAddonDescription(const std::string &path, AddonPtr &addon)
893{
894 cp_status_t status;
895 cp_plugin_info_t *info = m_cpluff->load_plugin_descriptor(m_cp_context, CSpecialProtocol::TranslatePath(path).c_str(), &status);
896 if (info)
897 {
898 addon = GetAddonFromDescriptor(info);
899 m_cpluff->release_info(m_cp_context, info);
900 return NULL != addon.get();
901 }
902 return false;
903}
904
905bool CAddonMgr::AddonsFromRepoXML(const TiXmlElement *root, VECADDONS &addons)
906{
907 // create a context for these addons
908 cp_status_t status;
909 cp_context_t *context = m_cpluff->create_context(&status);
910 if (!root || !context)
911 return false;
912
913 // each addon XML should have a UTF-8 declaration
914 TiXmlDeclaration decl("1.0", "UTF-8", "");
915 const TiXmlElement *element = root->FirstChildElement("addon");
916 while (element)
917 {
918 // dump the XML back to text
919 std::string xml;
920 xml << decl;
921 xml << *element;
922 cp_status_t status;
923 cp_plugin_info_t *info = m_cpluff->load_plugin_descriptor_from_memory(context, xml.c_str(), xml.size(), &status);
924 if (info)
925 {
926 AddonPtr addon = GetAddonFromDescriptor(info);
927 if (addon.get())
928 addons.push_back(addon);
929 m_cpluff->release_info(context, info);
930 }
931 element = element->NextSiblingElement("addon");
932 }
933 m_cpluff->destroy_context(context);
934 return true;
935}
936
937bool CAddonMgr::LoadAddonDescriptionFromMemory(const TiXmlElement *root, AddonPtr &addon)
938{
939 // create a context for these addons
940 cp_status_t status;
941 cp_context_t *context = m_cpluff->create_context(&status);
942 if (!root || !context)
943 return false;
944
945 // dump the XML back to text
946 std::string xml;
947 xml << TiXmlDeclaration("1.0", "UTF-8", "");
948 xml << *root;
949 cp_plugin_info_t *info = m_cpluff->load_plugin_descriptor_from_memory(context, xml.c_str(), xml.size(), &status);
950 if (info)
951 {
952 addon = GetAddonFromDescriptor(info);
953 m_cpluff->release_info(context, info);
954 }
955 m_cpluff->destroy_context(context);
956 return addon != NULL;
957}
958
959bool CAddonMgr::StartServices(const bool beforelogin)
960{
961 CLog::Log(LOGDEBUG, "ADDON: Starting service addons.");
962
963 VECADDONS services;
964 if (!GetAddons(ADDON_SERVICE, services))
965 return false;
966
967 bool ret = true;
968 for (IVECADDONS it = services.begin(); it != services.end(); ++it)
969 {
970 std::shared_ptr<CService> service = std::dynamic_pointer_cast<CService>(*it);
971 if (service)
972 {
973 if ( (beforelogin && service->GetStartOption() == CService::STARTUP)
974 || (!beforelogin && service->GetStartOption() == CService::LOGIN) )
975 ret &= service->Start();
976 }
977 }
978
979 return ret;
980}
981
982void CAddonMgr::StopServices(const bool onlylogin)
983{
984 CLog::Log(LOGDEBUG, "ADDON: Stopping service addons.");
985
986 VECADDONS services;
987 if (!GetAddons(ADDON_SERVICE, services))
988 return;
989
990 for (IVECADDONS it = services.begin(); it != services.end(); ++it)
991 {
992 std::shared_ptr<CService> service = std::dynamic_pointer_cast<CService>(*it);
993 if (service)
994 {
995 if ( (onlylogin && service->GetStartOption() == CService::LOGIN)
996 || (!onlylogin) )
997 service->Stop();
998 }
999 }
1000}
1001
1002int cp_to_clog(cp_log_severity_t lvl)
1003{
1004 if (lvl >= CP_LOG_ERROR)
1005 return LOGINFO;
1006 return LOGDEBUG;
1007}
1008
1009cp_log_severity_t clog_to_cp(int lvl)
1010{
1011 if (lvl >= LOG_LEVEL_DEBUG)
1012 return CP_LOG_INFO;
1013 return CP_LOG_ERROR;
1014}
1015
1016void cp_fatalErrorHandler(const char *msg)
1017{
1018 CLog::Log(LOGERROR, "ADDONS: CPluffFatalError(%s)", msg);
1019}
1020
1021void cp_logger(cp_log_severity_t level, const char *msg, const char *apid, void *user_data)
1022{
1023 if(!apid)
1024 CLog::Log(cp_to_clog(level), "ADDON: cpluff: '%s'", msg);
1025 else
1026 CLog::Log(cp_to_clog(level), "ADDON: cpluff: '%s' reports '%s'", apid, msg);
1027}
1028
1029} /* namespace ADDON */
1030
diff --git a/xbmc/addons/AddonManager.h b/xbmc/addons/AddonManager.h
new file mode 100644
index 0000000..8bc058d
--- /dev/null
+++ b/xbmc/addons/AddonManager.h
@@ -0,0 +1,253 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21#include "Addon.h"
22#include "threads/CriticalSection.h"
23#include "utils/Observer.h"
24#include <string>
25#include <vector>
26#include <map>
27#include <deque>
28#include "AddonDatabase.h"
29
30class DllLibCPluff;
31extern "C"
32{
33#include "lib/cpluff/libcpluff/cpluff.h"
34}
35
36namespace ADDON
37{
38 typedef std::map<TYPE, VECADDONS> MAPADDONS;
39 typedef std::map<TYPE, VECADDONS>::iterator IMAPADDONS;
40 typedef std::vector<cp_cfg_element_t*> ELEMENTS;
41
42 const std::string ADDON_METAFILE = "description.xml";
43 const std::string ADDON_VIS_EXT = "*.vis";
44 const std::string ADDON_PYTHON_EXT = "*.py";
45 const std::string ADDON_SCRAPER_EXT = "*.xml";
46 const std::string ADDON_SCREENSAVER_EXT = "*.xbs";
47 const std::string ADDON_PVRDLL_EXT = "*.pvr";
48 const std::string ADDON_DSP_AUDIO_EXT = "*.adsp";
49 const std::string ADDON_VERSION_RE = "(?<Major>\\d*)\\.?(?<Minor>\\d*)?\\.?(?<Build>\\d*)?\\.?(?<Revision>\\d*)?";
50
51 /**
52 * Class - IAddonMgrCallback
53 * This callback should be inherited by any class which manages
54 * specific addon types. Could be mostly used for Dll addon types to handle
55 * cleanup before restart/removal
56 */
57 class IAddonMgrCallback
58 {
59 public:
60 virtual ~IAddonMgrCallback() {};
61 virtual bool RequestRestart(AddonPtr addon, bool datachanged)=0;
62 virtual bool RequestRemoval(AddonPtr addon)=0;
63 };
64
65 /**
66 * Class - CAddonMgr
67 * Holds references to all addons, enabled or
68 * otherwise. Services the generic callbacks available
69 * to all addon variants.
70 */
71 class CAddonMgr : public Observable
72 {
73 public:
74 static CAddonMgr &Get();
75 bool ReInit() { DeInit(); return Init(); }
76 bool Init();
77 void DeInit();
78
79 IAddonMgrCallback* GetCallbackForType(TYPE type);
80 bool RegisterAddonMgrCallback(TYPE type, IAddonMgrCallback* cb);
81 void UnregisterAddonMgrCallback(TYPE type);
82
83 /* Addon access */
84 bool GetDefault(const TYPE &type, AddonPtr &addon);
85 bool SetDefault(const TYPE &type, const std::string &addonID);
86 /*! \brief Retrieve a specific addon (of a specific type)
87 \param id the id of the addon to retrieve.
88 \param addon [out] the retrieved addon pointer - only use if the function returns true.
89 \param type type of addon to retrieve - defaults to any type.
90 \param enabledOnly whether we only want enabled addons - set to false to allow both enabled and disabled addons - defaults to true.
91 \return true if an addon matching the id of the given type is available and is enabled (if enabledOnly is true).
92 */
93 bool GetAddon(const std::string &id, AddonPtr &addon, const TYPE &type = ADDON_UNKNOWN, bool enabledOnly = true);
94 bool HasAddons(const TYPE &type, bool enabled = true);
95 bool GetAddons(const TYPE &type, VECADDONS &addons, bool enabled = true);
96 bool GetAllAddons(VECADDONS &addons, bool enabled = true, bool allowRepos = false);
97 void AddToUpdateableAddons(AddonPtr &pAddon);
98 void RemoveFromUpdateableAddons(AddonPtr &pAddon);
99 bool ReloadSettings(const std::string &id);
100 /*! \brief Get all addons with available updates
101 \param addons List to fill with all outdated addons
102 \param getLocalVersion Whether to get the local addon version or the addon verion from the repository
103 \return True if there are outdated addons otherwise false
104 */
105 bool GetAllOutdatedAddons(VECADDONS &addons, bool getLocalVersion = false);
106 /*! \brief Checks if there is any addon with available updates
107 \return True if there are outdated addons otherwise false
108 */
109 bool HasOutdatedAddons();
110 std::string GetString(const std::string &id, const int number);
111
112 std::string GetTranslatedString(const cp_cfg_element_t *root, const char *tag);
113 static AddonPtr AddonFromProps(AddonProps& props);
114 void FindAddons();
115 void RemoveAddon(const std::string& ID);
116
117 /* \brief Disable an addon
118 Triggers the database routine and saves the current addon state to cache.
119 \param ID id of the addon
120 \param disable whether to enable or disable. Defaults to true (disable)
121 \sa IsAddonDisabled,
122 */
123 bool DisableAddon(const std::string& ID, bool disable = true);
124
125 /* \brief Check whether an addon has been disabled via DisableAddon.
126 In case the disabled cache does not know about the current state the database routine will be used.
127 \param ID id of the addon
128 \sa DisableAddon
129 */
130 bool IsAddonDisabled(const std::string& ID);
131
132 /* \brief Checks whether an addon can be disabled via DisableAddon.
133 \param ID id of the addon
134 \sa DisableAddon
135 */
136 bool CanAddonBeDisabled(const std::string& ID);
137
138 /* \brief Checks whether an addon is installed.
139 \param ID id of the addon
140 */
141 bool IsAddonInstalled(const std::string& ID);
142
143 /* \brief Checks whether an addon is installed.
144 \param ID id of the addon
145 \param addon Installed addon
146 */
147 bool IsAddonInstalled(const std::string& ID, AddonPtr& addon);
148
149 /* \brief Checks whether an addon can be installed. Broken addons can't be installed.
150 \param ID id of the addon
151 */
152 bool CanAddonBeInstalled(const std::string& ID);
153
154 /* \brief Checks whether an addon can be installed. Broken addons can't be installed.
155 \param addon addon to be checked
156 */
157 bool CanAddonBeInstalled(const AddonPtr& addon);
158
159 /* libcpluff */
160 std::string GetExtValue(cp_cfg_element_t *base, const char *path);
161
162 /*! \brief Retrieve a vector of repeated elements from a given configuration element
163 \param base the base configuration element.
164 \param path the path to the configuration element from the base element.
165 \param result [out] returned list of elements.
166 \return true if the configuration element is present and the list of elements is non-empty
167 */
168 bool GetExtElements(cp_cfg_element_t *base, const char *path, ELEMENTS &result);
169
170 /*! \brief Retrieve a list of strings from a given configuration element
171 Assumes the configuration element or attribute contains a whitespace separated list of values (eg xs:list schema).
172 \param base the base configuration element.
173 \param path the path to the configuration element or attribute from the base element.
174 \param result [out] returned list of strings.
175 \return true if the configuration element is present and the list of strings is non-empty
176 */
177 bool GetExtList(cp_cfg_element_t *base, const char *path, std::vector<std::string> &result) const;
178
179 const cp_extension_t *GetExtension(const cp_plugin_info_t *props, const char *extension) const;
180
181 /*! \brief Load the addon in the given path
182 This loads the addon using c-pluff which parses the addon descriptor file.
183 \param path folder that contains the addon.
184 \param addon [out] returned addon.
185 \return true if addon is set, false otherwise.
186 */
187 bool LoadAddonDescription(const std::string &path, AddonPtr &addon);
188
189 /*! \brief Load the addon in the given in-memory xml
190 This loads the addon using c-pluff which parses the addon descriptor file.
191 \param root Root element of an XML document.
192 \param addon [out] returned addon.
193 \return true if addon is set, false otherwise.
194 */
195 bool LoadAddonDescriptionFromMemory(const TiXmlElement *root, AddonPtr &addon);
196
197 /*! \brief Parse a repository XML file for addons and load their descriptors
198 A repository XML is essentially a concatenated list of addon descriptors.
199 \param root Root element of an XML document.
200 \param addons [out] returned list of addons.
201 \return true if the repository XML file is parsed, false otherwise.
202 */
203 bool AddonsFromRepoXML(const TiXmlElement *root, VECADDONS &addons);
204
205 /*! \brief Start all services addons.
206 \return True is all addons are started, false otherwise
207 */
208 bool StartServices(const bool beforelogin);
209 /*! \brief Stop all services addons.
210 */
211 void StopServices(const bool onlylogin);
212
213 private:
214 void LoadAddons(const std::string &path,
215 std::map<std::string, AddonPtr>& unresolved);
216
217 /* libcpluff */
218 const cp_cfg_element_t *GetExtElement(cp_cfg_element_t *base, const char *path);
219 cp_context_t *m_cp_context;
220 DllLibCPluff *m_cpluff;
221 VECADDONS m_updateableAddons;
222
223 /*! \brief Fetch a (single) addon from a plugin descriptor.
224 Assumes that there is a single (non-trivial) extension point per addon.
225 \param info the plugin descriptor
226 \param type the extension point we want
227 \return an AddonPtr based on the descriptor. May be NULL if no suitable extension point is found.
228 */
229 AddonPtr GetAddonFromDescriptor(const cp_plugin_info_t *info,
230 const std::string& type="");
231
232 /*! \brief Check whether this addon is supported on the current platform
233 \param info the plugin descriptor
234 \return true if the addon is supported, false otherwise.
235 */
236 bool PlatformSupportsAddon(const cp_plugin_info_t *info) const;
237
238 AddonPtr Factory(const cp_extension_t *props);
239 bool CheckUserDirs(const cp_cfg_element_t *element);
240
241 // private construction, and no assignements; use the provided singleton methods
242 CAddonMgr();
243 CAddonMgr(const CAddonMgr&);
244 CAddonMgr const& operator=(CAddonMgr const&);
245 virtual ~CAddonMgr();
246
247 std::map<std::string, bool> m_disabled;
248 static std::map<TYPE, IAddonMgrCallback*> m_managers;
249 CCriticalSection m_critSection;
250 CAddonDatabase m_database;
251 };
252
253}; /* namespace ADDON */
diff --git a/xbmc/addons/AddonStatusHandler.cpp b/xbmc/addons/AddonStatusHandler.cpp
new file mode 100644
index 0000000..7bb874a
--- /dev/null
+++ b/xbmc/addons/AddonStatusHandler.cpp
@@ -0,0 +1,175 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#include "AddonStatusHandler.h"
21#include "AddonManager.h"
22#include "threads/SingleLock.h"
23#include "ApplicationMessenger.h"
24#include "guilib/GUIWindowManager.h"
25#include "GUIDialogAddonSettings.h"
26#include "dialogs/GUIDialogYesNo.h"
27#include "dialogs/GUIDialogOK.h"
28#include "dialogs/GUIDialogKaiToast.h"
29#include "settings/Settings.h"
30#include "utils/log.h"
31#include "utils/StringUtils.h"
32
33namespace ADDON
34{
35
36/**********************************************************
37 * CAddonStatusHandler - AddOn Status Report Class
38 *
39 * Used to informate the user about occurred errors and
40 * changes inside Add-on's, and ask him what to do.
41 *
42 */
43
44CCriticalSection CAddonStatusHandler::m_critSection;
45
46CAddonStatusHandler::CAddonStatusHandler(const std::string &addonID, ADDON_STATUS status, std::string message, bool sameThread)
47 : CThread(("AddonStatus " + addonID).c_str())
48{
49 if (!CAddonMgr::Get().GetAddon(addonID, m_addon))
50 return;
51
52 CLog::Log(LOGINFO, "Called Add-on status handler for '%u' of clientName:%s, clientID:%s (same Thread=%s)", status, m_addon->Name().c_str(), m_addon->ID().c_str(), sameThread ? "yes" : "no");
53
54 m_status = status;
55 m_message = message;
56
57 if (sameThread)
58 {
59 Process();
60 }
61 else
62 {
63 Create(true, THREAD_MINSTACKSIZE);
64 }
65}
66
67CAddonStatusHandler::~CAddonStatusHandler()
68{
69 StopThread();
70}
71
72void CAddonStatusHandler::OnStartup()
73{
74 SetPriority(GetMinPriority());
75}
76
77void CAddonStatusHandler::OnExit()
78{
79}
80
81void CAddonStatusHandler::Process()
82{
83 CSingleLock lock(m_critSection);
84
85 std::string heading = StringUtils::Format("%s: %s", TranslateType(m_addon->Type(), true).c_str(), m_addon->Name().c_str());
86
87 /* AddOn lost connection to his backend (for ones that use Network) */
88 if (m_status == ADDON_STATUS_LOST_CONNECTION)
89 {
90 if (m_addon->Type() == ADDON_PVRDLL)
91 {
92 if (!CSettings::Get().GetBool("pvrmanager.hideconnectionlostwarning"))
93 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, m_addon->Name().c_str(), g_localizeStrings.Get(36030)); // connection lost
94 // TODO handle disconnects after the add-on's been initialised
95 }
96 else
97 {
98 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
99 if (!pDialog) return;
100
101 pDialog->SetHeading(heading);
102 pDialog->SetLine(1, 24070);
103 pDialog->SetLine(2, 24073);
104
105 //send message and wait for user input
106 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_YES_NO, g_windowManager.GetActiveWindow()};
107 CApplicationMessenger::Get().SendMessage(tMsg, true);
108
109 if (pDialog->IsConfirmed())
110 CAddonMgr::Get().GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, false);
111 }
112 }
113 /* Request to restart the AddOn and data structures need updated */
114 else if (m_status == ADDON_STATUS_NEED_RESTART)
115 {
116 CGUIDialogOK* pDialog = (CGUIDialogOK*)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
117 if (!pDialog) return;
118
119 pDialog->SetHeading(heading);
120 pDialog->SetLine(1, 24074);
121
122 //send message and wait for user input
123 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_OK, g_windowManager.GetActiveWindow()};
124 CApplicationMessenger::Get().SendMessage(tMsg, true);
125
126 CAddonMgr::Get().GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, true);
127 }
128 /* Some required settings are missing/invalid */
129 else if ((m_status == ADDON_STATUS_NEED_SETTINGS) || (m_status == ADDON_STATUS_NEED_SAVEDSETTINGS))
130 {
131 CGUIDialogYesNo* pDialogYesNo = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
132 if (!pDialogYesNo) return;
133
134 pDialogYesNo->SetHeading(heading);
135 pDialogYesNo->SetLine(1, 24070);
136 pDialogYesNo->SetLine(2, 24072);
137 pDialogYesNo->SetLine(3, m_message);
138
139 //send message and wait for user input
140 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_YES_NO, g_windowManager.GetActiveWindow()};
141 CApplicationMessenger::Get().SendMessage(tMsg, true);
142
143 if (!pDialogYesNo->IsConfirmed()) return;
144
145 if (!m_addon->HasSettings())
146 return;
147
148 if (CGUIDialogAddonSettings::ShowAndGetInput(m_addon))
149 {
150 //todo doesn't dialogaddonsettings save these automatically? should do
151 m_addon->SaveSettings();
152 CAddonMgr::Get().GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, true);
153 }
154 }
155 /* A unknown event has occurred */
156 else if (m_status == ADDON_STATUS_UNKNOWN)
157 {
158 //CAddonMgr::Get().DisableAddon(m_addon->ID());
159 CGUIDialogOK* pDialog = (CGUIDialogOK*)g_windowManager.GetWindow(WINDOW_DIALOG_OK);
160 if (!pDialog) return;
161
162 pDialog->SetHeading(heading);
163 pDialog->SetLine(1, 24070);
164 pDialog->SetLine(2, 24071);
165 pDialog->SetLine(3, m_message);
166
167 //send message and wait for user input
168 ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_OK, g_windowManager.GetActiveWindow()};
169 CApplicationMessenger::Get().SendMessage(tMsg, true);
170 }
171}
172
173
174} /*namespace ADDON*/
175
diff --git a/xbmc/addons/AddonStatusHandler.h b/xbmc/addons/AddonStatusHandler.h
new file mode 100644
index 0000000..c9b65bd
--- /dev/null
+++ b/xbmc/addons/AddonStatusHandler.h
@@ -0,0 +1,56 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "threads/Thread.h"
23#include "IAddon.h"
24#include "include/xbmc_addon_types.h"
25#include "threads/CriticalSection.h"
26#include <string>
27
28namespace ADDON
29{
30 /**
31 * Class - CAddonStatusHandler
32 * Used to informate the user about occurred errors and
33 * changes inside Add-on's, and ask him what to do.
34 * It can executed in the same thread as the calling
35 * function or in a seperate thread.
36 */
37 class CAddonStatusHandler : private CThread
38 {
39 public:
40 CAddonStatusHandler(const std::string &addonID, ADDON_STATUS status, std::string message, bool sameThread = true);
41 ~CAddonStatusHandler();
42
43 /* Thread handling */
44 virtual void Process();
45 virtual void OnStartup();
46 virtual void OnExit();
47
48 private:
49 static CCriticalSection m_critSection;
50 AddonPtr m_addon;
51 ADDON_STATUS m_status;
52 std::string m_message;
53 };
54
55
56}
diff --git a/xbmc/addons/AddonVersion.cpp b/xbmc/addons/AddonVersion.cpp
new file mode 100644
index 0000000..9d5a112
--- /dev/null
+++ b/xbmc/addons/AddonVersion.cpp
@@ -0,0 +1,138 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25
26#include "AddonVersion.h"
27#include "utils/StringUtils.h"
28
29namespace ADDON
30{
31 AddonVersion::AddonVersion(const std::string& version)
32 : mEpoch(0), mUpstream(version.empty() ? "0.0.0" : version)
33 {
34 size_t pos = mUpstream.find(':');
35 if (pos != std::string::npos)
36 {
37 mEpoch = strtol(mUpstream.c_str(), NULL, 10);
38 mUpstream.erase(0, pos+1);
39 }
40
41 pos = mUpstream.find('-');
42 if (pos != std::string::npos)
43 {
44 mRevision = mUpstream.substr(pos+1);
45 mUpstream.erase(pos);
46 }
47 }
48
49 /**Compare two components of a Debian-style version. Return -1, 0, or 1
50 * if a is less than, equal to, or greater than b, respectively.
51 */
52 int AddonVersion::CompareComponent(const char *a, const char *b)
53 {
54 while (*a && *b)
55 {
56 while (*a && *b && !isdigit(*a) && !isdigit(*b))
57 {
58 if (*a != *b)
59 {
60 if (*a == '~') return -1;
61 if (*b == '~') return 1;
62 return *a < *b ? -1 : 1;
63 }
64 a++;
65 b++;
66 }
67 if (*a && *b && (!isdigit(*a) || !isdigit(*b)))
68 {
69 if (*a == '~') return -1;
70 if (*b == '~') return 1;
71 return isdigit(*a) ? -1 : 1;
72 }
73
74 char *next_a, *next_b;
75 long int num_a = strtol(a, &next_a, 10);
76 long int num_b = strtol(b, &next_b, 10);
77 if (num_a != num_b)
78 return num_a < num_b ? -1 : 1;
79
80 a = next_a;
81 b = next_b;
82 }
83 if (!*a && !*b)
84 return 0;
85 if (*a)
86 return *a == '~' ? -1 : 1;
87 else
88 return *b == '~' ? 1 : -1;
89 }
90
91 bool AddonVersion::operator<(const AddonVersion& other) const
92 {
93 if (mEpoch != other.mEpoch)
94 return mEpoch < other.mEpoch;
95
96 int result = CompareComponent(mUpstream.c_str(), other.mUpstream.c_str());
97 if (result)
98 return (result < 0);
99
100 return (CompareComponent(mRevision.c_str(), other.mRevision.c_str()) < 0);
101 }
102
103 bool AddonVersion::operator==(const AddonVersion& other) const
104 {
105 return mEpoch == other.mEpoch
106 && CompareComponent(mUpstream.c_str(), other.mUpstream.c_str()) == 0
107 && CompareComponent(mRevision.c_str(), other.mRevision.c_str()) == 0;
108 }
109
110 bool AddonVersion::empty() const
111 {
112 return mEpoch == 0 && mUpstream == "0.0.0" && mRevision.empty();
113 }
114
115 std::string AddonVersion::asString() const
116 {
117 std::string out;
118 if (mEpoch)
119 out = StringUtils::Format("%i:", mEpoch);
120 out += mUpstream;
121 if (!mRevision.empty())
122 out += "-" + mRevision;
123 return out;
124 }
125
126 bool AddonVersion::SplitFileName(std::string& ID, std::string& version,
127 const std::string& filename)
128 {
129 size_t dpos = filename.rfind("-");
130 if (dpos == std::string::npos)
131 return false;
132 ID = filename.substr(0, dpos);
133 version = filename.substr(dpos + 1);
134 version = version.substr(0, version.size() - 4);
135
136 return true;
137 }
138}
diff --git a/xbmc/addons/AddonVersion.h b/xbmc/addons/AddonVersion.h
new file mode 100644
index 0000000..3c23370
--- /dev/null
+++ b/xbmc/addons/AddonVersion.h
@@ -0,0 +1,72 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <string>
22#include <boost/operators.hpp>
23
24namespace ADDON
25{
26 /* \brief Addon versioning using the debian versioning scheme
27
28 AddonVersion uses debian versioning, which means in the each section of the period
29 separated version string, numbers are compared numerically rather than lexicographically,
30 thus any preceding zeros are ignored.
31
32 i.e. 1.00 is considered the same as 1.0, and 1.01 is considered the same as 1.1.
33
34 Further, 1.0 < 1.0.0
35
36 See here for more info: http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
37 */
38 class AddonVersion : public boost::totally_ordered<AddonVersion> {
39 public:
40 AddonVersion(const AddonVersion& other) { *this = other; }
41 explicit AddonVersion(const std::string& version);
42 virtual ~AddonVersion() {};
43
44 int Epoch() const { return mEpoch; }
45 const std::string &Upstream() const { return mUpstream; }
46 const std::string &Revision() const { return mRevision; }
47
48 AddonVersion& operator=(const AddonVersion& other);
49 bool operator<(const AddonVersion& other) const;
50 bool operator==(const AddonVersion& other) const;
51 std::string asString() const;
52 bool empty() const;
53
54 static bool SplitFileName(std::string& ID, std::string& version,
55 const std::string& filename);
56
57 protected:
58 int mEpoch;
59 std::string mUpstream;
60 std::string mRevision;
61
62 static int CompareComponent(const char *a, const char *b);
63 };
64
65 inline AddonVersion& AddonVersion::operator=(const AddonVersion& other)
66 {
67 mEpoch = other.mEpoch;
68 mUpstream = other.mUpstream;
69 mRevision = other.mRevision;
70 return *this;
71 }
72}
diff --git a/xbmc/addons/AudioEncoder.cpp b/xbmc/addons/AudioEncoder.cpp
new file mode 100644
index 0000000..2737bba
--- /dev/null
+++ b/xbmc/addons/AudioEncoder.cpp
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) 2013 Arne Morten Kvarving
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, see
16 * <http://www.gnu.org/licenses/>.
17 *
18 */
19#include "AudioEncoder.h"
20
21namespace ADDON
22{
23
24CAudioEncoder::CAudioEncoder(const cp_extension_t* ext)
25 : AudioEncoderDll(ext),
26 extension(CAddonMgr::Get().GetExtValue(ext->configuration, "@extension")),
27 m_context(NULL)
28{
29}
30
31AddonPtr CAudioEncoder::Clone() const
32{
33 // Copy constructor is generated by compiler and calls parent copy constructor
34 return AddonPtr(new CAudioEncoder(*this));
35}
36
37bool CAudioEncoder::Init(audioenc_callbacks &callbacks)
38{
39 if (!Initialized())
40 return false;
41
42 // create encoder instance
43 m_context = m_pStruct->Create(&callbacks);
44 if (!m_context)
45 return false;
46
47 return m_pStruct->Start(m_context,
48 m_iInChannels,
49 m_iInSampleRate,
50 m_iInBitsPerSample,
51 m_strTitle.c_str(),
52 m_strArtist.c_str(),
53 m_strAlbumArtist.c_str(),
54 m_strAlbum.c_str(),
55 m_strYear.c_str(),
56 m_strTrack.c_str(),
57 m_strGenre.c_str(),
58 m_strComment.c_str(),
59 m_iTrackLength);
60}
61
62int CAudioEncoder::Encode(int nNumBytesRead, uint8_t* pbtStream)
63{
64 if (!Initialized() || !m_context)
65 return 0;
66
67 return m_pStruct->Encode(m_context, nNumBytesRead, pbtStream);
68}
69
70bool CAudioEncoder::Close()
71{
72 if (!Initialized() || !m_context)
73 return false;
74
75 if (!m_pStruct->Finish(m_context))
76 return false;
77
78 m_pStruct->Free(m_context);
79 m_context = NULL;
80
81 return true;
82}
83
84void CAudioEncoder::Destroy()
85{
86 AudioEncoderDll::Destroy();
87}
88
89} /*namespace ADDON*/
90
diff --git a/xbmc/addons/AudioEncoder.h b/xbmc/addons/AudioEncoder.h
new file mode 100644
index 0000000..3900333
--- /dev/null
+++ b/xbmc/addons/AudioEncoder.h
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2013 Arne Morten Kvarving
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, see
16 * <http://www.gnu.org/licenses/>.
17 *
18 */
19#pragma once
20
21#include "AddonDll.h"
22#include "include/xbmc_audioenc_types.h"
23#include "cdrip/IEncoder.h"
24
25typedef DllAddon<AudioEncoder, AUDIOENC_PROPS> DllAudioEncoder;
26namespace ADDON
27{
28 typedef CAddonDll<DllAudioEncoder,
29 AudioEncoder, AUDIOENC_PROPS> AudioEncoderDll;
30
31 class CAudioEncoder : public AudioEncoderDll, public IEncoder
32 {
33 public:
34 CAudioEncoder(const AddonProps &props) : AudioEncoderDll(props) {};
35 CAudioEncoder(const cp_extension_t *ext);
36 virtual ~CAudioEncoder() {}
37 virtual AddonPtr Clone() const;
38
39 // Things that MUST be supplied by the child classes
40 bool Init(audioenc_callbacks &callbacks);
41 int Encode(int nNumBytesRead, uint8_t* pbtStream);
42 bool Close();
43 void Destroy();
44
45 const std::string extension;
46
47 private:
48 void *m_context; ///< audio encoder context
49 };
50
51} /*namespace ADDON*/
diff --git a/xbmc/addons/ContextItemAddon.cpp b/xbmc/addons/ContextItemAddon.cpp
new file mode 100644
index 0000000..4222936
--- /dev/null
+++ b/xbmc/addons/ContextItemAddon.cpp
@@ -0,0 +1,108 @@
1/*
2 * Copyright (C) 2013-2015 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "ContextItemAddon.h"
22#include "AddonManager.h"
23#include "ContextMenuManager.h"
24#include "dialogs/GUIDialogContextMenu.h"
25#include "GUIInfoManager.h"
26#include "interfaces/info/InfoBool.h"
27#include "utils/log.h"
28#include "utils/StringUtils.h"
29#include "video/dialogs/GUIDialogVideoInfo.h"
30#include <boost/lexical_cast.hpp>
31
32using namespace std;
33
34namespace ADDON
35{
36
37CContextItemAddon::CContextItemAddon(const AddonProps &props)
38 : CAddon(props)
39{ }
40
41CContextItemAddon::~CContextItemAddon()
42{ }
43
44CContextItemAddon::CContextItemAddon(const cp_extension_t *ext)
45 : CAddon(ext)
46{
47 ELEMENTS items;
48 if (CAddonMgr::Get().GetExtElements(ext->configuration, "item", items))
49 {
50 cp_cfg_element_t *item = items[0];
51
52 m_label = CAddonMgr::Get().GetExtValue(item, "label");
53 if (StringUtils::IsNaturalNumber(m_label))
54 {
55 m_label = GetString(boost::lexical_cast<int>(m_label.c_str()));
56 ClearStrings();
57 }
58
59 m_parent = CAddonMgr::Get().GetExtValue(item, "parent");
60
61 string visible = CAddonMgr::Get().GetExtValue(item, "visible");
62 if (visible.empty())
63 visible = "false";
64
65 m_visCondition = g_infoManager.Register(visible, 0);
66 }
67}
68
69bool CContextItemAddon::OnPreInstall()
70{
71 return CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this()));
72}
73
74void CContextItemAddon::OnPostInstall(bool restart, bool update)
75{
76 if (restart)
77 {
78 // need to grab the local addon so we have the correct library path to run
79 AddonPtr localAddon;
80 if (CAddonMgr::Get().GetAddon(ID(), localAddon, ADDON_CONTEXT_ITEM))
81 {
82 ContextItemAddonPtr contextItem = std::dynamic_pointer_cast<CContextItemAddon>(localAddon);
83 if (contextItem)
84 CContextMenuManager::Get().Register(contextItem);
85 }
86 }
87}
88
89void CContextItemAddon::OnPreUnInstall()
90{
91 CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this()));
92}
93
94void CContextItemAddon::OnDisabled()
95{
96 CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this()));
97}
98void CContextItemAddon::OnEnabled()
99{
100 CContextMenuManager::Get().Register(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this()));
101}
102
103bool CContextItemAddon::IsVisible(const CFileItemPtr& item) const
104{
105 return item && m_visCondition->Get(item.get());
106}
107
108}
diff --git a/xbmc/addons/ContextItemAddon.h b/xbmc/addons/ContextItemAddon.h
new file mode 100644
index 0000000..628fdcd
--- /dev/null
+++ b/xbmc/addons/ContextItemAddon.h
@@ -0,0 +1,72 @@
1#pragma once
2/*
3 * Copyright (C) 2013-2015 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <list>
23#include <memory>
24#include "Addon.h"
25
26class CFileItem;
27typedef std::shared_ptr<CFileItem> CFileItemPtr;
28
29namespace INFO
30{
31 class InfoBool;
32 typedef std::shared_ptr<InfoBool> InfoPtr;
33}
34
35namespace ADDON
36{
37 class CContextItemAddon : public CAddon
38 {
39 public:
40 CContextItemAddon(const cp_extension_t *ext);
41 CContextItemAddon(const AddonProps &props);
42 virtual ~CContextItemAddon();
43
44 const std::string& GetLabel() const { return m_label; }
45
46 /*!
47 * \brief Get the parent category of this context item.
48 *
49 * \details Returns empty string if at root level or
50 * CONTEXT_MENU_GROUP_MANAGE when it should be in the 'manage' submenu.
51 */
52 const std::string& GetParent() const { return m_parent; }
53
54 /*!
55 * \brief Returns true if this contex menu should be visible for given item.
56 */
57 bool IsVisible(const CFileItemPtr& item) const;
58
59 virtual bool OnPreInstall();
60 virtual void OnPostInstall(bool restart, bool update);
61 virtual void OnPreUnInstall();
62 virtual void OnDisabled();
63 virtual void OnEnabled();
64
65 private:
66 std::string m_label;
67 std::string m_parent;
68 INFO::InfoPtr m_visCondition;
69 };
70
71 typedef std::shared_ptr<CContextItemAddon> ContextItemAddonPtr;
72}
diff --git a/xbmc/addons/DllAddon.h b/xbmc/addons/DllAddon.h
new file mode 100644
index 0000000..3ea4e8d
--- /dev/null
+++ b/xbmc/addons/DllAddon.h
@@ -0,0 +1,70 @@
1#pragma once
2/*
3* Copyright (C) 2005-2013 Team XBMC
4* http://xbmc.org
5*
6* This Program is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2, or (at your option)
9* any later version.
10*
11* This Program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with XBMC; see the file COPYING. If not, see
18* <http://www.gnu.org/licenses/>.
19*
20*/
21
22#include "DynamicDll.h"
23#include "addons/include/xbmc_addon_cpp_dll.h"
24
25template <typename TheStruct, typename Props>
26class DllAddonInterface
27{
28public:
29 virtual ~DllAddonInterface() {}
30 virtual void GetAddon(TheStruct* pAddon) =0;
31 virtual ADDON_STATUS Create(void *cb, Props *info) =0;
32 virtual void Stop() =0;
33 virtual void Destroy() =0;
34 virtual ADDON_STATUS GetStatus() =0;
35 virtual bool HasSettings() =0;
36 virtual unsigned int GetSettings(ADDON_StructSetting*** sSet)=0;
37 virtual void FreeSettings()=0;
38 virtual ADDON_STATUS SetSetting(const char *settingName, const void *settingValue) =0;
39 virtual void Announce(const char *flag, const char *sender, const char *message, const void *data) =0;
40};
41
42template <typename TheStruct, typename Props>
43class DllAddon : public DllDynamic, public DllAddonInterface<TheStruct, Props>
44{
45public:
46 DECLARE_DLL_WRAPPER_TEMPLATE(DllAddon)
47 DEFINE_METHOD2(ADDON_STATUS, Create, (void* p1, Props* p2))
48 DEFINE_METHOD0(void, Stop)
49 DEFINE_METHOD0(void, Destroy)
50 DEFINE_METHOD0(ADDON_STATUS, GetStatus)
51 DEFINE_METHOD0(bool, HasSettings)
52 DEFINE_METHOD1(unsigned int, GetSettings, (ADDON_StructSetting ***p1))
53 DEFINE_METHOD0(void, FreeSettings)
54 DEFINE_METHOD2(ADDON_STATUS, SetSetting, (const char *p1, const void *p2))
55 DEFINE_METHOD1(void, GetAddon, (TheStruct* p1))
56 DEFINE_METHOD4(void, Announce, (const char *p1, const char *p2, const char *p3, const void *p4))
57 BEGIN_METHOD_RESOLVE()
58 RESOLVE_METHOD_RENAME(get_addon,GetAddon)
59 RESOLVE_METHOD_RENAME(ADDON_Create, Create)
60 RESOLVE_METHOD_RENAME(ADDON_Stop, Stop)
61 RESOLVE_METHOD_RENAME(ADDON_Destroy, Destroy)
62 RESOLVE_METHOD_RENAME(ADDON_GetStatus, GetStatus)
63 RESOLVE_METHOD_RENAME(ADDON_HasSettings, HasSettings)
64 RESOLVE_METHOD_RENAME(ADDON_SetSetting, SetSetting)
65 RESOLVE_METHOD_RENAME(ADDON_GetSettings, GetSettings)
66 RESOLVE_METHOD_RENAME(ADDON_FreeSettings, FreeSettings)
67 RESOLVE_METHOD_RENAME(ADDON_Announce, Announce)
68 END_METHOD_RESOLVE()
69};
70
diff --git a/xbmc/addons/DllLibCPluff.h b/xbmc/addons/DllLibCPluff.h
new file mode 100644
index 0000000..6e3f03c
--- /dev/null
+++ b/xbmc/addons/DllLibCPluff.h
@@ -0,0 +1,116 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DynamicDll.h"
23
24extern "C" {
25#include "lib/cpluff/libcpluff/cpluff.h"
26}
27
28class DllLibCPluffInterface
29{
30public:
31 virtual ~DllLibCPluffInterface() {}
32 virtual const char *get_version(void) =0;
33 virtual void set_fatal_error_handler(cp_fatal_error_func_t error_handler) =0;
34 virtual cp_status_t init(void) =0;
35 virtual void destroy(void) =0;
36 virtual cp_context_t * create_context(cp_status_t *status) =0;
37 virtual void destroy_context(cp_context_t *ctx) =0;
38 virtual cp_status_t register_pcollection(cp_context_t *ctx, const char *dir) =0;
39 virtual void unregister_pcollection(cp_context_t *ctx, const char *dir) =0;
40 virtual void unregister_pcollections(cp_context_t *ctx) =0;
41 virtual cp_status_t register_logger(cp_context_t *ctx, cp_logger_func_t logger, void *user_data, cp_log_severity_t min_severity) =0;
42 virtual void unregister_logger(cp_context_t *ctx, cp_logger_func_t logger) =0;
43 virtual cp_status_t scan_plugins(cp_context_t *ctx, int flags) =0;
44 virtual cp_plugin_info_t * get_plugin_info(cp_context_t *ctx, const char *id, cp_status_t *status) =0;
45 virtual cp_plugin_info_t ** get_plugins_info(cp_context_t *ctx, cp_status_t *status, int *num) =0;
46 virtual cp_extension_t ** get_extensions_info(cp_context_t *ctx, const char *extpt_id, cp_status_t *status, int *num) =0;
47 virtual void release_info(cp_context_t *ctx, void *info) =0;
48 virtual cp_cfg_element_t * lookup_cfg_element(cp_cfg_element_t *base, const char *path) =0;
49 virtual char * lookup_cfg_value(cp_cfg_element_t *base, const char *path) =0;
50 virtual cp_status_t define_symbol(cp_context_t *ctx, const char *name, void *ptr) =0;
51 virtual void *resolve_symbol(cp_context_t *ctx, const char *id, const char *name, cp_status_t *status) =0;
52 virtual void release_symbol(cp_context_t *ctx, const void *ptr) =0;
53 virtual cp_plugin_info_t *load_plugin_descriptor(cp_context_t *ctx, const char *path, cp_status_t *status) =0;
54 virtual cp_plugin_info_t *load_plugin_descriptor_from_memory(cp_context_t *ctx, const char *buffer, unsigned int buffer_len, cp_status_t *status) =0;
55 virtual cp_status_t uninstall_plugin(cp_context_t *ctx, const char *id)=0;
56};
57
58class DllLibCPluff : public DllDynamic, DllLibCPluffInterface
59{
60 DECLARE_DLL_WRAPPER(DllLibCPluff, DLL_PATH_CPLUFF)
61 DEFINE_METHOD0(const char*, get_version)
62 DEFINE_METHOD1(void, set_fatal_error_handler, (cp_fatal_error_func_t p1))
63 DEFINE_METHOD0(cp_status_t, init)
64 DEFINE_METHOD0(void, destroy)
65 DEFINE_METHOD1(cp_context_t*, create_context, (cp_status_t *p1))
66 DEFINE_METHOD1(void, destroy_context, (cp_context_t *p1))
67
68 DEFINE_METHOD2(cp_status_t, register_pcollection, (cp_context_t *p1, const char *p2))
69 DEFINE_METHOD2(void, unregister_pcollection, (cp_context_t *p1, const char *p2))
70 DEFINE_METHOD1(void, unregister_pcollections, (cp_context_t *p1))
71
72 DEFINE_METHOD4(cp_status_t, register_logger, (cp_context_t *p1, cp_logger_func_t p2, void *p3, cp_log_severity_t p4))
73 DEFINE_METHOD2(void, unregister_logger, (cp_context_t *p1, cp_logger_func_t p2))
74 DEFINE_METHOD2(cp_status_t, scan_plugins, (cp_context_t *p1, int p2))
75 DEFINE_METHOD3(cp_plugin_info_t*, get_plugin_info, (cp_context_t *p1, const char *p2, cp_status_t *p3))
76 DEFINE_METHOD3(cp_plugin_info_t**, get_plugins_info, (cp_context_t *p1, cp_status_t *p2, int *p3))
77 DEFINE_METHOD4(cp_extension_t**, get_extensions_info, (cp_context_t *p1, const char *p2, cp_status_t *p3, int *p4))
78 DEFINE_METHOD2(void, release_info, (cp_context_t *p1, void *p2))
79
80 DEFINE_METHOD2(cp_cfg_element_t*, lookup_cfg_element, (cp_cfg_element_t *p1, const char *p2))
81 DEFINE_METHOD2(char*, lookup_cfg_value, (cp_cfg_element_t *p1, const char *p2))
82
83 DEFINE_METHOD3(cp_status_t, define_symbol, (cp_context_t *p1, const char *p2, void *p3))
84 DEFINE_METHOD4(void*, resolve_symbol, (cp_context_t *p1, const char *p2, const char *p3, cp_status_t *p4))
85 DEFINE_METHOD2(void, release_symbol, (cp_context_t *p1, const void *p2))
86 DEFINE_METHOD3(cp_plugin_info_t*, load_plugin_descriptor, (cp_context_t *p1, const char *p2, cp_status_t *p3))
87 DEFINE_METHOD4(cp_plugin_info_t*, load_plugin_descriptor_from_memory, (cp_context_t *p1, const char *p2, unsigned int p3, cp_status_t *p4))
88 DEFINE_METHOD2(cp_status_t, uninstall_plugin, (cp_context_t *p1, const char *p2))
89
90 BEGIN_METHOD_RESOLVE()
91 RESOLVE_METHOD_RENAME(cp_get_version, get_version)
92 RESOLVE_METHOD_RENAME(cp_set_fatal_error_handler, set_fatal_error_handler)
93 RESOLVE_METHOD_RENAME(cp_init, init)
94 RESOLVE_METHOD_RENAME(cp_destroy, destroy)
95 RESOLVE_METHOD_RENAME(cp_create_context, create_context)
96 RESOLVE_METHOD_RENAME(cp_destroy_context, destroy_context)
97 RESOLVE_METHOD_RENAME(cp_register_pcollection, register_pcollection)
98 RESOLVE_METHOD_RENAME(cp_unregister_pcollection, unregister_pcollection)
99 RESOLVE_METHOD_RENAME(cp_unregister_pcollections, unregister_pcollections)
100 RESOLVE_METHOD_RENAME(cp_register_logger, register_logger)
101 RESOLVE_METHOD_RENAME(cp_unregister_logger, unregister_logger)
102 RESOLVE_METHOD_RENAME(cp_scan_plugins, scan_plugins)
103 RESOLVE_METHOD_RENAME(cp_get_plugin_info, get_plugin_info)
104 RESOLVE_METHOD_RENAME(cp_get_plugins_info, get_plugins_info)
105 RESOLVE_METHOD_RENAME(cp_get_extensions_info, get_extensions_info)
106 RESOLVE_METHOD_RENAME(cp_release_info, release_info)
107 RESOLVE_METHOD_RENAME(cp_lookup_cfg_element, lookup_cfg_element)
108 RESOLVE_METHOD_RENAME(cp_lookup_cfg_value, lookup_cfg_value)
109 RESOLVE_METHOD_RENAME(cp_define_symbol, define_symbol)
110 RESOLVE_METHOD_RENAME(cp_resolve_symbol, resolve_symbol)
111 RESOLVE_METHOD_RENAME(cp_release_symbol, release_symbol)
112 RESOLVE_METHOD_RENAME(cp_load_plugin_descriptor, load_plugin_descriptor)
113 RESOLVE_METHOD_RENAME(cp_load_plugin_descriptor_from_memory, load_plugin_descriptor_from_memory)
114 RESOLVE_METHOD_RENAME(cp_uninstall_plugin, uninstall_plugin)
115 END_METHOD_RESOLVE()
116};
diff --git a/xbmc/addons/DllPVRClient.h b/xbmc/addons/DllPVRClient.h
new file mode 100644
index 0000000..7948858
--- /dev/null
+++ b/xbmc/addons/DllPVRClient.h
@@ -0,0 +1,29 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DllAddon.h"
23#include "include/xbmc_pvr_types.h"
24
25class DllPVRClient : public DllAddon<PVRClient, PVR_PROPERTIES>
26{
27 // this is populated via Macro calls in DllAddon.h
28};
29
diff --git a/xbmc/addons/GUIDialogAddonInfo.cpp b/xbmc/addons/GUIDialogAddonInfo.cpp
new file mode 100644
index 0000000..fe3484f
--- /dev/null
+++ b/xbmc/addons/GUIDialogAddonInfo.cpp
@@ -0,0 +1,458 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "GUIDialogAddonInfo.h"
22#include "dialogs/GUIDialogYesNo.h"
23#include "dialogs/GUIDialogOK.h"
24#include "addons/AddonManager.h"
25#include "AddonDatabase.h"
26#include "FileItem.h"
27#include "filesystem/Directory.h"
28#include "filesystem/SpecialProtocol.h"
29#include "GUIDialogAddonSettings.h"
30#include "dialogs/GUIDialogContextMenu.h"
31#include "dialogs/GUIDialogTextViewer.h"
32#include "GUIUserMessages.h"
33#include "guilib/GUIWindowManager.h"
34#include "input/Key.h"
35#include "utils/JobManager.h"
36#include "utils/FileOperationJob.h"
37#include "utils/StringUtils.h"
38#include "utils/URIUtils.h"
39#include "utils/log.h"
40#include "addons/AddonInstaller.h"
41#include "pvr/PVRManager.h"
42#include "Util.h"
43#include "interfaces/Builtins.h"
44
45#define CONTROL_BTN_INSTALL 6
46#define CONTROL_BTN_ENABLE 7
47#define CONTROL_BTN_UPDATE 8
48#define CONTROL_BTN_SETTINGS 9
49#define CONTROL_BTN_CHANGELOG 10
50#define CONTROL_BTN_ROLLBACK 11
51#define CONTROL_BTN_SELECT 12
52
53using namespace std;
54using namespace ADDON;
55using namespace XFILE;
56
57CGUIDialogAddonInfo::CGUIDialogAddonInfo(void)
58 : CGUIDialog(WINDOW_DIALOG_ADDON_INFO, "DialogAddonInfo.xml"), m_jobid(0)
59{
60 m_item = CFileItemPtr(new CFileItem);
61 m_loadType = KEEP_IN_MEMORY;
62}
63
64CGUIDialogAddonInfo::~CGUIDialogAddonInfo(void)
65{
66}
67
68bool CGUIDialogAddonInfo::OnMessage(CGUIMessage& message)
69{
70 switch ( message.GetMessage() )
71 {
72 case GUI_MSG_WINDOW_DEINIT:
73 {
74 if (m_jobid)
75 CJobManager::GetInstance().CancelJob(m_jobid);
76 }
77 break;
78
79 case GUI_MSG_CLICKED:
80 {
81 int iControl = message.GetSenderId();
82 if (iControl == CONTROL_BTN_UPDATE)
83 {
84 OnUpdate();
85 return true;
86 }
87 if (iControl == CONTROL_BTN_INSTALL)
88 {
89 if (!m_localAddon)
90 {
91 OnInstall();
92 return true;
93 }
94 else
95 {
96 OnUninstall();
97 return true;
98 }
99 }
100 else if (iControl == CONTROL_BTN_SELECT)
101 {
102 OnLaunch();
103 return true;
104 }
105 else if (iControl == CONTROL_BTN_ENABLE)
106 {
107 OnEnable(!m_item->GetProperty("Addon.Enabled").asBoolean());
108 return true;
109 }
110 else if (iControl == CONTROL_BTN_SETTINGS)
111 {
112 OnSettings();
113 return true;
114 }
115 else if (iControl == CONTROL_BTN_CHANGELOG)
116 {
117 OnChangeLog();
118 return true;
119 }
120 else if (iControl == CONTROL_BTN_ROLLBACK)
121 {
122 OnRollback();
123 return true;
124 }
125 }
126 break;
127default:
128 break;
129 }
130
131 return CGUIDialog::OnMessage(message);
132}
133
134bool CGUIDialogAddonInfo::OnAction(const CAction &action)
135{
136 if (action.GetID() == ACTION_SHOW_INFO)
137 {
138 Close();
139 return true;
140 }
141 return CGUIDialog::OnAction(action);
142}
143
144void CGUIDialogAddonInfo::OnInitWindow()
145{
146 UpdateControls();
147 CGUIDialog::OnInitWindow();
148 m_changelog = false;
149}
150
151void CGUIDialogAddonInfo::UpdateControls()
152{
153 bool isInstalled = NULL != m_localAddon.get();
154 bool isEnabled = isInstalled && m_item->GetProperty("Addon.Enabled").asBoolean();
155 bool isUpdatable = isInstalled && m_item->GetProperty("Addon.UpdateAvail").asBoolean();
156 bool isExecutable = isInstalled && (m_localAddon->Type() == ADDON_PLUGIN || m_localAddon->Type() == ADDON_SCRIPT);
157 if (isInstalled)
158 GrabRollbackVersions();
159
160 bool canDisable = isInstalled && CAddonMgr::Get().CanAddonBeDisabled(m_localAddon->ID());
161 bool canInstall = !isInstalled && m_item->GetProperty("Addon.Broken").empty();
162 bool isRepo = (isInstalled && m_localAddon->Type() == ADDON_REPOSITORY) || (m_addon && m_addon->Type() == ADDON_REPOSITORY);
163
164 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_INSTALL, canDisable || canInstall);
165 SET_CONTROL_LABEL(CONTROL_BTN_INSTALL, isInstalled ? 24037 : 24038);
166
167 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_ENABLE, canDisable);
168 SET_CONTROL_LABEL(CONTROL_BTN_ENABLE, isEnabled ? 24021 : 24022);
169
170 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_UPDATE, isUpdatable);
171 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_SETTINGS, isInstalled && m_localAddon->HasSettings());
172 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_SELECT, isExecutable);
173 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_CHANGELOG, !isRepo);
174 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_ROLLBACK, m_rollbackVersions.size() > 1);
175}
176
177void CGUIDialogAddonInfo::OnUpdate()
178{
179 std::string referer = StringUtils::Format("Referer=%s-%s.zip",m_localAddon->ID().c_str(),m_localAddon->Version().asString().c_str());
180 CAddonInstaller::Get().Install(m_addon->ID(), true, referer); // force install
181 Close();
182}
183
184void CGUIDialogAddonInfo::OnInstall()
185{
186 CAddonInstaller::Get().Install(m_addon->ID());
187 Close();
188}
189
190void CGUIDialogAddonInfo::OnLaunch()
191{
192 if (!m_localAddon)
193 return;
194
195 CBuiltins::Execute("RunAddon(" + m_localAddon->ID() + ")");
196 Close();
197}
198
199bool CGUIDialogAddonInfo::PromptIfDependency(int heading, int line2)
200{
201 if (!m_localAddon)
202 return false;
203
204 VECADDONS addons;
205 vector<string> deps;
206 CAddonMgr::Get().GetAllAddons(addons);
207 for (VECADDONS::const_iterator it = addons.begin();
208 it != addons.end();++it)
209 {
210 ADDONDEPS::const_iterator i = (*it)->GetDeps().find(m_localAddon->ID());
211 if (i != (*it)->GetDeps().end() && !i->second.second) // non-optional dependency
212 deps.push_back((*it)->Name());
213 }
214
215 if (!deps.empty())
216 {
217 string line0 = StringUtils::Format(g_localizeStrings.Get(24046).c_str(), m_localAddon->Name().c_str());
218 string line1 = StringUtils::Join(deps, ", ");
219 CGUIDialogOK::ShowAndGetInput(heading, line0, line1, line2);
220 return true;
221 }
222 return false;
223}
224
225void CGUIDialogAddonInfo::OnUninstall()
226{
227 if (!m_localAddon.get())
228 return;
229
230 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
231 return;
232
233 // ensure the addon is not a dependency of other installed addons
234 if (PromptIfDependency(24037, 24047))
235 return;
236
237 // prompt user to be sure
238 if (!CGUIDialogYesNo::ShowAndGetInput(24037, 750, 0, 0))
239 return;
240
241 // ensure the addon isn't disabled in our database
242 CAddonMgr::Get().DisableAddon(m_localAddon->ID(), false);
243
244 CJobManager::GetInstance().AddJob(new CAddonUnInstallJob(m_localAddon),
245 &CAddonInstaller::Get());
246 CAddonMgr::Get().RemoveAddon(m_localAddon->ID());
247 Close();
248}
249
250void CGUIDialogAddonInfo::OnEnable(bool enable)
251{
252 if (!m_localAddon.get())
253 return;
254
255 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
256 return;
257
258 if (!enable && PromptIfDependency(24075, 24091))
259 return;
260
261 CAddonMgr::Get().DisableAddon(m_localAddon->ID(), !enable);
262 SetItem(m_item);
263 UpdateControls();
264 g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE);
265}
266
267void CGUIDialogAddonInfo::OnSettings()
268{
269 CGUIDialogAddonSettings::ShowAndGetInput(m_localAddon);
270}
271
272void CGUIDialogAddonInfo::OnChangeLog()
273{
274 CGUIDialogTextViewer* pDlgInfo = (CGUIDialogTextViewer*)g_windowManager.GetWindow(WINDOW_DIALOG_TEXT_VIEWER);
275 std::string name;
276 if (m_addon)
277 name = m_addon->Name();
278 else if (m_localAddon)
279 name = m_localAddon->Name();
280 pDlgInfo->SetHeading(g_localizeStrings.Get(24054)+" - "+name);
281 if (m_item->GetProperty("Addon.Changelog").empty())
282 {
283 pDlgInfo->SetText(g_localizeStrings.Get(13413));
284 CFileItemList items;
285 if (m_localAddon &&
286 !m_item->GetProperty("Addon.UpdateAvail").asBoolean())
287 {
288 items.Add(CFileItemPtr(new CFileItem(m_localAddon->ChangeLog(),false)));
289 }
290 else
291 items.Add(CFileItemPtr(new CFileItem(m_addon->ChangeLog(),false)));
292 items[0]->Select(true);
293 m_jobid = CJobManager::GetInstance().AddJob(
294 new CFileOperationJob(CFileOperationJob::ActionCopy,items,
295 "special://temp/"),this);
296 }
297 else
298 pDlgInfo->SetText(m_item->GetProperty("Addon.Changelog").asString());
299
300 m_changelog = true;
301 pDlgInfo->DoModal();
302 m_changelog = false;
303}
304
305void CGUIDialogAddonInfo::OnRollback()
306{
307 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
308 return;
309
310 CGUIDialogContextMenu* dlg = (CGUIDialogContextMenu*)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU);
311 CAddonDatabase database;
312 database.Open();
313
314 CContextButtons buttons;
315 for (unsigned int i=0;i<m_rollbackVersions.size();++i)
316 {
317 std::string label(m_rollbackVersions[i]);
318 if (m_rollbackVersions[i] == m_localAddon->Version().asString())
319 label += " "+g_localizeStrings.Get(24094);
320 if (database.IsAddonBlacklisted(m_localAddon->ID(),label))
321 label += " "+g_localizeStrings.Get(24095);
322
323 buttons.Add(i,label);
324 }
325 int choice;
326 if ((choice=dlg->ShowAndGetChoice(buttons)) > -1)
327 {
328 // blacklist everything newer
329 for (unsigned int j=choice+1;j<m_rollbackVersions.size();++j)
330 database.BlacklistAddon(m_localAddon->ID(),m_rollbackVersions[j]);
331 std::string path = "special://home/addons/packages/";
332 path += m_localAddon->ID()+"-"+m_rollbackVersions[choice]+".zip";
333 // needed as cpluff won't downgrade
334 if (!m_localAddon->IsType(ADDON_SERVICE))
335 //we will handle this for service addons in CAddonInstallJob::OnPostInstall
336 CAddonMgr::Get().RemoveAddon(m_localAddon->ID());
337 CAddonInstaller::Get().InstallFromZip(path);
338 database.RemoveAddonFromBlacklist(m_localAddon->ID(),m_rollbackVersions[choice]);
339 Close();
340 }
341}
342
343bool CGUIDialogAddonInfo::ShowForItem(const CFileItemPtr& item)
344{
345 CGUIDialogAddonInfo* dialog = (CGUIDialogAddonInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_INFO);
346 if (!dialog)
347 return false;
348 if (!dialog->SetItem(item))
349 return false;
350
351 dialog->DoModal();
352 return true;
353}
354
355bool CGUIDialogAddonInfo::SetItem(const CFileItemPtr& item)
356{
357 *m_item = *item;
358 m_rollbackVersions.clear();
359
360 // grab the local addon, if it's available
361 m_localAddon.reset();
362 m_addon.reset();
363 if (CAddonMgr::Get().GetAddon(item->GetProperty("Addon.ID").asString(), m_localAddon)) // sets m_localAddon if installed regardless of enabled state
364 m_item->SetProperty("Addon.Enabled", "true");
365 else
366 m_item->SetProperty("Addon.Enabled", "false");
367 m_item->SetProperty("Addon.Installed", m_localAddon ? "true" : "false");
368
369 CAddonDatabase database;
370 database.Open();
371 database.GetAddon(item->GetProperty("Addon.ID").asString(),m_addon);
372
373 if (TranslateType(item->GetProperty("Addon.intType").asString()) == ADDON_REPOSITORY)
374 {
375 CAddonDatabase database;
376 database.Open();
377 VECADDONS addons;
378 if (m_addon)
379 database.GetRepository(m_addon->ID(), addons);
380 else if (m_localAddon) // sanity
381 database.GetRepository(m_localAddon->ID(), addons);
382 int tot=0;
383 for (int i = ADDON_UNKNOWN+1;i<ADDON_MAX;++i)
384 {
385 int num=0;
386 for (unsigned int j=0;j<addons.size();++j)
387 {
388 if (addons[j]->Type() == (TYPE)i)
389 ++num;
390 }
391 m_item->SetProperty("Repo." + TranslateType((TYPE)i), num);
392 tot += num;
393 }
394 m_item->SetProperty("Repo.Addons", tot);
395 }
396 return true;
397}
398
399void CGUIDialogAddonInfo::OnJobComplete(unsigned int jobID, bool success,
400 CJob* job)
401{
402 if (!m_changelog)
403 return;
404
405 CGUIDialogTextViewer* pDlgInfo = (CGUIDialogTextViewer*)g_windowManager.GetWindow(WINDOW_DIALOG_TEXT_VIEWER);
406
407 m_jobid = 0;
408 if (!success)
409 {
410 pDlgInfo->SetText(g_localizeStrings.Get(195));
411 }
412 else
413 {
414 CFile file;
415 XFILE::auto_buffer buf;
416 if (file.LoadFile("special://temp/" +
417 URIUtils::GetFileName(((CFileOperationJob*)job)->GetItems()[0]->GetPath()), buf) > 0)
418 {
419 std::string str(buf.get(), buf.length());
420 m_item->SetProperty("Addon.Changelog", str);
421 pDlgInfo->SetText(str);
422 }
423 }
424 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, WINDOW_DIALOG_TEXT_VIEWER, 0, GUI_MSG_UPDATE);
425 g_windowManager.SendThreadMessage(msg);
426}
427
428void CGUIDialogAddonInfo::GrabRollbackVersions()
429{
430 CFileItemList items;
431 XFILE::CDirectory::GetDirectory("special://home/addons/packages/",items,".zip",DIR_FLAG_NO_FILE_DIRS);
432 items.Sort(SortByLabel, SortOrderAscending);
433 CAddonDatabase db;
434 db.Open();
435 for (int i=0;i<items.Size();++i)
436 {
437 if (items[i]->m_bIsFolder)
438 continue;
439 std::string ID, version;
440 AddonVersion::SplitFileName(ID,version,items[i]->GetLabel());
441 if (ID == m_localAddon->ID())
442 {
443 std::string hash, path(items[i]->GetPath());
444 if (db.GetPackageHash(m_localAddon->ID(), path, hash))
445 {
446 std::string md5 = CUtil::GetFileMD5(path);
447 if (md5 == hash)
448 m_rollbackVersions.push_back(version);
449 else /* The package has been corrupted */
450 {
451 CLog::Log(LOGWARNING, "%s: Removing corrupt addon package %s.", __FUNCTION__, path.c_str());
452 CFile::Delete(path);
453 db.RemovePackage(path);
454 }
455 }
456 }
457 }
458}
diff --git a/xbmc/addons/GUIDialogAddonInfo.h b/xbmc/addons/GUIDialogAddonInfo.h
new file mode 100644
index 0000000..53b7a27
--- /dev/null
+++ b/xbmc/addons/GUIDialogAddonInfo.h
@@ -0,0 +1,80 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "guilib/GUIDialog.h"
24#include "addons/IAddon.h"
25#include "utils/Job.h"
26
27class CGUIDialogAddonInfo :
28 public CGUIDialog,
29 public IJobCallback
30{
31public:
32 CGUIDialogAddonInfo(void);
33 virtual ~CGUIDialogAddonInfo(void);
34 virtual bool OnMessage(CGUIMessage& message);
35 virtual bool OnAction(const CAction &action);
36
37 virtual CFileItemPtr GetCurrentListItem(int offset = 0) { return m_item; }
38 virtual bool HasListItems() const { return true; }
39
40 static bool ShowForItem(const CFileItemPtr& item);
41
42 // job callback
43 void OnJobComplete(unsigned int jobID, bool success, CJob* job);
44protected:
45 void OnInitWindow();
46
47 /*! \brief Set the item to display addon info on.
48 \param item to display
49 \return true if we can display information, false otherwise
50 */
51 bool SetItem(const CFileItemPtr &item);
52 void UpdateControls();
53
54 void OnUpdate();
55 void OnInstall();
56 void OnUninstall();
57 void OnEnable(bool enable);
58 void OnSettings();
59 void OnChangeLog();
60 void OnRollback();
61 void OnLaunch();
62
63 /*! \brief check if the add-on is a dependency of others, and if so prompt the user.
64 \param heading the label for the heading of the prompt dialog
65 \param line2 the action that could not be completed.
66 \return true if prompted, false otherwise.
67 */
68 bool PromptIfDependency(int heading, int line2);
69
70 CFileItemPtr m_item;
71 ADDON::AddonPtr m_addon;
72 ADDON::AddonPtr m_localAddon;
73 unsigned int m_jobid;
74 bool m_changelog;
75
76 // rollback data
77 void GrabRollbackVersions();
78 std::vector<std::string> m_rollbackVersions;
79};
80
diff --git a/xbmc/addons/GUIDialogAddonSettings.cpp b/xbmc/addons/GUIDialogAddonSettings.cpp
new file mode 100644
index 0000000..ef1c3c2
--- /dev/null
+++ b/xbmc/addons/GUIDialogAddonSettings.cpp
@@ -0,0 +1,1200 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "GUIDialogAddonSettings.h"
22#include "filesystem/PluginDirectory.h"
23#include "addons/IAddon.h"
24#include "addons/AddonManager.h"
25#include "dialogs/GUIDialogNumeric.h"
26#include "dialogs/GUIDialogFileBrowser.h"
27#include "dialogs/GUIDialogOK.h"
28#include "guilib/GUIControlGroupList.h"
29#include "guilib/GUISettingsSliderControl.h"
30#include "utils/URIUtils.h"
31#include "utils/StringUtils.h"
32#include "storage/MediaManager.h"
33#include "guilib/GUILabelControl.h"
34#include "guilib/GUIRadioButtonControl.h"
35#include "guilib/GUISpinControlEx.h"
36#include "guilib/GUIImage.h"
37#include "input/Key.h"
38#include "filesystem/Directory.h"
39#include "video/VideoInfoScanner.h"
40#include "addons/Scraper.h"
41#include "guilib/GUIWindowManager.h"
42#include "ApplicationMessenger.h"
43#include "guilib/GUIKeyboardFactory.h"
44#include "FileItem.h"
45#include "settings/AdvancedSettings.h"
46#include "settings/MediaSourceSettings.h"
47#include "GUIInfoManager.h"
48#include "GUIUserMessages.h"
49#include "dialogs/GUIDialogSelect.h"
50#include "GUIWindowAddonBrowser.h"
51#include "utils/log.h"
52#include "Util.h"
53#include "URL.h"
54#include "utils/XMLUtils.h"
55
56using namespace std;
57using namespace ADDON;
58using XFILE::CDirectory;
59
60#define CONTROL_SETTINGS_AREA 2
61#define CONTROL_DEFAULT_BUTTON 3
62#define CONTROL_DEFAULT_RADIOBUTTON 4
63#define CONTROL_DEFAULT_SPIN 5
64#define CONTROL_DEFAULT_SEPARATOR 6
65#define CONTROL_DEFAULT_LABEL_SEPARATOR 7
66#define CONTROL_DEFAULT_SLIDER 8
67#define CONTROL_SECTION_AREA 9
68#define CONTROL_DEFAULT_SECTION_BUTTON 13
69
70#define ID_BUTTON_OK 10
71#define ID_BUTTON_CANCEL 11
72#define ID_BUTTON_DEFAULT 12
73#define CONTROL_HEADING_LABEL 20
74
75#define CONTROL_START_SECTION 100
76#define CONTROL_START_SETTING 200
77
78CGUIDialogAddonSettings::CGUIDialogAddonSettings()
79 : CGUIDialogBoxBase(WINDOW_DIALOG_ADDON_SETTINGS, "DialogAddonSettings.xml")
80{
81 m_currentSection = 0;
82 m_totalSections = 1;
83 m_saveToDisk = false;
84}
85
86CGUIDialogAddonSettings::~CGUIDialogAddonSettings(void)
87{
88}
89
90bool CGUIDialogAddonSettings::OnMessage(CGUIMessage& message)
91{
92 switch (message.GetMessage())
93 {
94 case GUI_MSG_WINDOW_DEINIT:
95 {
96 FreeSections();
97 }
98 break;
99 case GUI_MSG_CLICKED:
100 {
101 int iControl = message.GetSenderId();
102 bool bCloseDialog = false;
103
104 if (iControl == ID_BUTTON_DEFAULT)
105 SetDefaultSettings();
106 else if (iControl != ID_BUTTON_OK)
107 bCloseDialog = ShowVirtualKeyboard(iControl);
108
109 if (iControl == ID_BUTTON_OK || iControl == ID_BUTTON_CANCEL || bCloseDialog)
110 {
111 if (iControl == ID_BUTTON_OK || bCloseDialog)
112 {
113 m_bConfirmed = true;
114 SaveSettings();
115 }
116 Close();
117 return true;
118 }
119 }
120 break;
121 case GUI_MSG_FOCUSED:
122 {
123 CGUIDialogBoxBase::OnMessage(message);
124 int focusedControl = GetFocusedControlID();
125 if (focusedControl >= CONTROL_START_SECTION && focusedControl < (int)(CONTROL_START_SECTION + m_totalSections) &&
126 focusedControl - CONTROL_START_SECTION != (int)m_currentSection)
127 { // changing section
128 UpdateFromControls();
129 m_currentSection = focusedControl - CONTROL_START_SECTION;
130 CreateControls();
131 }
132 return true;
133 }
134 case GUI_MSG_SETTING_UPDATED:
135 {
136 std::string id = message.GetStringParam(0);
137 std::string value = message.GetStringParam(1);
138 m_settings[id] = value;
139 if (GetFocusedControl())
140 {
141 int iControl = GetFocusedControl()->GetID();
142 CreateControls();
143 CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl);
144 OnMessage(msg);
145 }
146 return true;
147 }
148 }
149 return CGUIDialogBoxBase::OnMessage(message);
150}
151
152bool CGUIDialogAddonSettings::OnAction(const CAction& action)
153{
154 if (action.GetID() == ACTION_DELETE_ITEM)
155 {
156 CGUIControl* pControl = GetFocusedControl();
157 if (pControl)
158 {
159 int iControl = pControl->GetID();
160 int controlId = CONTROL_START_SETTING;
161 const TiXmlElement* setting = GetFirstSetting();
162 UpdateFromControls();
163 while (setting)
164 {
165 if (controlId == iControl)
166 {
167 const char* id = setting->Attribute("id");
168 const char* value = setting->Attribute("default");
169 if (id && value)
170 m_settings[id] = value;
171 CreateControls();
172 CGUIMessage msg(GUI_MSG_SETFOCUS,GetID(),iControl);
173 OnMessage(msg);
174 return true;
175 }
176 setting = setting->NextSiblingElement("setting");
177 controlId++;
178 }
179 }
180 }
181 return CGUIDialogBoxBase::OnAction(action);
182}
183
184void CGUIDialogAddonSettings::OnInitWindow()
185{
186 m_currentSection = 0;
187 m_totalSections = 1;
188 CreateSections();
189 CreateControls();
190 CGUIDialogBoxBase::OnInitWindow();
191}
192
193// \brief Show CGUIDialogOK dialog, then wait for user to dismiss it.
194bool CGUIDialogAddonSettings::ShowAndGetInput(const AddonPtr &addon, bool saveToDisk /* = true */)
195{
196 if (!addon)
197 return false;
198
199 if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
200 return false;
201
202 bool ret(false);
203 if (addon->HasSettings())
204 {
205 // Create the dialog
206 CGUIDialogAddonSettings* pDialog = NULL;
207 pDialog = (CGUIDialogAddonSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_SETTINGS);
208 if (!pDialog)
209 return false;
210
211 // Set the heading
212 std::string heading = StringUtils::Format("$LOCALIZE[10004] - %s", addon->Name().c_str()); // "Settings - AddonName"
213 pDialog->m_strHeading = heading;
214
215 pDialog->m_addon = addon;
216 pDialog->m_saveToDisk = saveToDisk;
217 pDialog->DoModal();
218 ret = true;
219 }
220 else
221 { // addon does not support settings, inform user
222 CGUIDialogOK::ShowAndGetInput(24000,0,24030,0);
223 }
224
225 return ret;
226}
227
228bool CGUIDialogAddonSettings::ShowVirtualKeyboard(int iControl)
229{
230 int controlId = CONTROL_START_SETTING;
231 bool bCloseDialog = false;
232
233 const TiXmlElement *setting = GetFirstSetting();
234 while (setting)
235 {
236 if (controlId == iControl)
237 {
238 const CGUIControl* control = GetControl(controlId);
239 const std::string id = XMLUtils::GetAttribute(setting, "id");
240 const std::string type = XMLUtils::GetAttribute(setting, "type");
241
242 //Special handling for actions: does not require id attribute. TODO: refactor me.
243 if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON && type == "action")
244 {
245 const char *option = setting->Attribute("option");
246 std::string action = XMLUtils::GetAttribute(setting, "action");
247 if (!action.empty())
248 {
249 // replace $CWD with the url of plugin/script
250 StringUtils::Replace(action, "$CWD", m_addon->Path());
251 StringUtils::Replace(action, "$ID", m_addon->ID());
252 if (option)
253 bCloseDialog = (strcmpi(option, "close") == 0);
254 CApplicationMessenger::Get().ExecBuiltIn(action);
255 }
256 break;
257 }
258
259 if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON &&
260 !id.empty() && !type.empty())
261 {
262 const char *option = setting->Attribute("option");
263 const char *source = setting->Attribute("source");
264 std::string value = m_buttonValues[id];
265 std::string label = GetString(setting->Attribute("label"));
266
267 if (type == "text")
268 {
269 // get any options
270 bool bHidden = false;
271 bool bEncoded = false;
272 if (option)
273 {
274 bHidden = (strstr(option, "hidden") != NULL);
275 bEncoded = (strstr(option, "urlencoded") != NULL);
276 }
277 if (bEncoded)
278 value = CURL::Decode(value);
279
280 if (CGUIKeyboardFactory::ShowAndGetInput(value, label, true, bHidden))
281 {
282 // if hidden hide input
283 if (bHidden)
284 {
285 std::string hiddenText;
286 hiddenText.append(value.size(), L'*');
287 ((CGUIButtonControl *)control)->SetLabel2(hiddenText);
288 }
289 else
290 ((CGUIButtonControl*) control)->SetLabel2(value);
291 if (bEncoded)
292 value = CURL::Encode(value);
293 }
294 }
295 else if (type == "number" && CGUIDialogNumeric::ShowAndGetNumber(value, label))
296 {
297 ((CGUIButtonControl*) control)->SetLabel2(value);
298 }
299 else if (type == "ipaddress" && CGUIDialogNumeric::ShowAndGetIPAddress(value, label))
300 {
301 ((CGUIButtonControl*) control)->SetLabel2(value);
302 }
303 else if (type == "select")
304 {
305 CGUIDialogSelect *pDlg = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
306 if (pDlg)
307 {
308 pDlg->SetHeading(label.c_str());
309 pDlg->Reset();
310
311 int selected = -1;
312 vector<std::string> valuesVec;
313 if (setting->Attribute("values"))
314 StringUtils::Tokenize(setting->Attribute("values"), valuesVec, "|");
315 else if (setting->Attribute("lvalues"))
316 { // localize
317 StringUtils::Tokenize(setting->Attribute("lvalues"), valuesVec, "|");
318 for (unsigned int i = 0; i < valuesVec.size(); i++)
319 {
320 if (i == (unsigned int)atoi(value.c_str()))
321 selected = i;
322 std::string localized = m_addon->GetString(atoi(valuesVec[i].c_str()));
323 if (localized.empty())
324 localized = g_localizeStrings.Get(atoi(valuesVec[i].c_str()));
325 valuesVec[i] = localized;
326 }
327 }
328 else if (source)
329 {
330 valuesVec = GetFileEnumValues(source, XMLUtils::GetAttribute(setting, "mask"), XMLUtils::GetAttribute(setting, "option"));
331 }
332
333 for (unsigned int i = 0; i < valuesVec.size(); i++)
334 {
335 pDlg->Add(valuesVec[i]);
336 if (selected == (int)i || (selected < 0 && StringUtils::EqualsNoCase(valuesVec[i], value)))
337 pDlg->SetSelected(i); // FIXME: the SetSelected() does not select "i", it always defaults to the first position
338 }
339 pDlg->DoModal();
340 int iSelected = pDlg->GetSelectedLabel();
341 if (iSelected >= 0)
342 {
343 if (setting->Attribute("lvalues"))
344 value = StringUtils::Format("%i", iSelected);
345 else
346 value = valuesVec[iSelected];
347 ((CGUIButtonControl*) control)->SetLabel2(valuesVec[iSelected]);
348 }
349 }
350 }
351 else if (type == "audio" || type == "video"
352 || type == "image" || type == "executable"
353 || type == "file" || type == "folder")
354 {
355 // setup the shares
356 VECSOURCES *shares = NULL;
357 if (source && strcmpi(source, "") != 0)
358 shares = CMediaSourceSettings::Get().GetSources(source);
359
360 VECSOURCES localShares;
361 if (!shares)
362 {
363 g_mediaManager.GetLocalDrives(localShares);
364 if (!source || strcmpi(source, "local") != 0)
365 g_mediaManager.GetNetworkLocations(localShares);
366 }
367 else // always append local drives
368 {
369 localShares = *shares;
370 g_mediaManager.GetLocalDrives(localShares);
371 }
372
373 if (type == "folder")
374 {
375 // get any options
376 bool bWriteOnly = false;
377 if (option)
378 bWriteOnly = (strcmpi(option, "writeable") == 0);
379
380 if (CGUIDialogFileBrowser::ShowAndGetDirectory(localShares, label, value, bWriteOnly))
381 ((CGUIButtonControl*) control)->SetLabel2(value);
382 }
383 else if (type == "image")
384 {
385 if (CGUIDialogFileBrowser::ShowAndGetImage(localShares, label, value))
386 ((CGUIButtonControl*) control)->SetLabel2(value);
387 }
388 else
389 {
390 // set the proper mask
391 std::string strMask;
392 if (setting->Attribute("mask"))
393 {
394 strMask = setting->Attribute("mask");
395 // convert mask qualifiers
396 StringUtils::Replace(strMask, "$AUDIO", g_advancedSettings.m_musicExtensions);
397 StringUtils::Replace(strMask, "$VIDEO", g_advancedSettings.m_videoExtensions);
398 StringUtils::Replace(strMask, "$IMAGE", g_advancedSettings.m_pictureExtensions);
399#if defined(_WIN32_WINNT)
400 StringUtils::Replace(strMask, "$EXECUTABLE", ".exe|.bat|.cmd|.py");
401#else
402 StringUtils::Replace(strMask, "$EXECUTABLE", "");
403#endif
404 }
405 else
406 {
407 if (type == "video")
408 strMask = g_advancedSettings.m_videoExtensions;
409 else if (type == "audio")
410 strMask = g_advancedSettings.m_musicExtensions;
411 else if (type == "executable")
412#if defined(_WIN32_WINNT)
413 strMask = ".exe|.bat|.cmd|.py";
414#else
415 strMask = "";
416#endif
417 }
418
419 // get any options
420 bool bUseThumbs = false;
421 bool bUseFileDirectories = false;
422 if (option)
423 {
424 vector<string> options = StringUtils::Split(option, '|');
425 bUseThumbs = find(options.begin(), options.end(), "usethumbs") != options.end();
426 bUseFileDirectories = find(options.begin(), options.end(), "treatasfolder") != options.end();
427 }
428
429 if (CGUIDialogFileBrowser::ShowAndGetFile(localShares, strMask, label, value, bUseThumbs, bUseFileDirectories))
430 ((CGUIButtonControl*) control)->SetLabel2(value);
431 }
432 }
433 else if (type == "date")
434 {
435 CDateTime date;
436 if (!value.empty())
437 date.SetFromDBDate(value);
438 SYSTEMTIME timedate;
439 date.GetAsSystemTime(timedate);
440 if(CGUIDialogNumeric::ShowAndGetDate(timedate, label))
441 {
442 date = timedate;
443 value = date.GetAsDBDate();
444 ((CGUIButtonControl*) control)->SetLabel2(value);
445 }
446 }
447 else if (type == "time")
448 {
449 SYSTEMTIME timedate;
450 if (value.size() >= 5)
451 {
452 // assumes HH:MM
453 timedate.wHour = atoi(value.substr(0, 2).c_str());
454 timedate.wMinute = atoi(value.substr(3, 2).c_str());
455 }
456 if (CGUIDialogNumeric::ShowAndGetTime(timedate, label))
457 {
458 value = StringUtils::Format("%02d:%02d", timedate.wHour, timedate.wMinute);
459 ((CGUIButtonControl*) control)->SetLabel2(value);
460 }
461 }
462 else if (type == "addon")
463 {
464 const char *strType = setting->Attribute("addontype");
465 if (strType)
466 {
467 vector<string> addonTypes = StringUtils::Split(strType, ',');
468 vector<ADDON::TYPE> types;
469 for (vector<string>::iterator i = addonTypes.begin(); i != addonTypes.end(); ++i)
470 {
471 StringUtils::Trim(*i);
472 ADDON::TYPE type = TranslateType(*i);
473 if (type != ADDON_UNKNOWN)
474 types.push_back(type);
475 }
476 if (types.size() > 0)
477 {
478 const char *strMultiselect = setting->Attribute("multiselect");
479 bool multiSelect = strMultiselect && strcmpi(strMultiselect, "true") == 0;
480 if (multiSelect)
481 {
482 // construct vector of addon IDs (IDs are comma seperated in single string)
483 vector<string> addonIDs = StringUtils::Split(value, ',');
484 if (CGUIWindowAddonBrowser::SelectAddonID(types, addonIDs, false) == 1)
485 {
486 value = StringUtils::Join(addonIDs, ",");
487 ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value));
488 }
489 }
490 else // no need of string splitting/joining if we select only 1 addon
491 if (CGUIWindowAddonBrowser::SelectAddonID(types, value, false) == 1)
492 ((CGUIButtonControl*) control)->SetLabel2(GetAddonNames(value));
493 }
494 }
495 }
496 m_buttonValues[id] = value;
497 break;
498 }
499 }
500 setting = setting->NextSiblingElement("setting");
501 controlId++;
502 }
503 EnableControls();
504 return bCloseDialog;
505}
506
507void CGUIDialogAddonSettings::UpdateFromControls()
508{
509 int controlID = CONTROL_START_SETTING;
510 const TiXmlElement *setting = GetFirstSetting();
511 while (setting)
512 {
513 const std::string id = XMLUtils::GetAttribute(setting, "id");
514 const std::string type = XMLUtils::GetAttribute(setting, "type");
515 const CGUIControl* control = GetControl(controlID++);
516
517 if (control)
518 {
519 std::string value;
520 switch (control->GetControlType())
521 {
522 case CGUIControl::GUICONTROL_BUTTON:
523 value = m_buttonValues[id];
524 break;
525 case CGUIControl::GUICONTROL_RADIO:
526 value = ((CGUIRadioButtonControl*) control)->IsSelected() ? "true" : "false";
527 break;
528 case CGUIControl::GUICONTROL_SPINEX:
529 if (type == "fileenum" || type == "labelenum")
530 value = ((CGUISpinControlEx*) control)->GetLabel();
531 else
532 value = StringUtils::Format("%i", ((CGUISpinControlEx*) control)->GetValue());
533 break;
534 case CGUIControl::GUICONTROL_SETTINGS_SLIDER:
535 {
536 std::string option = XMLUtils::GetAttribute(setting, "option");
537 if (option.size() == 0 || StringUtils::EqualsNoCase(option, "float"))
538 value = StringUtils::Format("%f", ((CGUISettingsSliderControl *)control)->GetFloatValue());
539 else
540 value = StringUtils::Format("%i", ((CGUISettingsSliderControl *)control)->GetIntValue());
541 }
542 break;
543 default:
544 break;
545 }
546 m_settings[id] = value;
547 }
548
549 setting = setting->NextSiblingElement("setting");
550 }
551}
552
553void CGUIDialogAddonSettings::SaveSettings(void)
554{
555 UpdateFromControls();
556
557 for (map<std::string, std::string>::iterator i = m_settings.begin(); i != m_settings.end(); ++i)
558 m_addon->UpdateSetting(i->first, i->second);
559
560 if (m_saveToDisk)
561 {
562 m_addon->SaveSettings();
563 }
564}
565
566void CGUIDialogAddonSettings::FreeSections()
567{
568 CGUIControlGroupList *group = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SECTION_AREA));
569 if (group)
570 {
571 group->FreeResources();
572 group->ClearAll();
573 }
574 m_settings.clear();
575 m_buttonValues.clear();
576 FreeControls();
577}
578
579void CGUIDialogAddonSettings::FreeControls()
580{
581 // clear the category group
582 CGUIControlGroupList *control = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SETTINGS_AREA));
583 if (control)
584 {
585 control->FreeResources();
586 control->ClearAll();
587 }
588}
589
590void CGUIDialogAddonSettings::CreateSections()
591{
592 CGUIControlGroupList *group = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SECTION_AREA));
593 CGUIButtonControl *originalButton = dynamic_cast<CGUIButtonControl *>(GetControl(CONTROL_DEFAULT_SECTION_BUTTON));
594 if (!m_addon)
595 return;
596
597 if (originalButton)
598 originalButton->SetVisible(false);
599
600 // clear the category group
601 FreeSections();
602
603 // grab our categories
604 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
605 if (!category) // add a default one...
606 category = m_addon->GetSettingsXML();
607
608 int buttonID = CONTROL_START_SECTION;
609 while (category)
610 { // add a category
611 CGUIButtonControl *button = originalButton ? originalButton->Clone() : NULL;
612
613 std::string label = GetString(category->Attribute("label"));
614 if (label.empty())
615 label = g_localizeStrings.Get(128);
616
617 if (buttonID >= CONTROL_START_SETTING)
618 {
619 CLog::Log(LOGERROR, "%s - cannot have more than %d categories - simplify your addon!", __FUNCTION__, CONTROL_START_SETTING - CONTROL_START_SECTION);
620 break;
621 }
622
623 // add the category button
624 if (button && group)
625 {
626 button->SetID(buttonID++);
627 button->SetLabel(label);
628 button->SetVisible(true);
629 group->AddControl(button);
630 }
631
632 // grab a local copy of all the settings in this category
633 const TiXmlElement *setting = category->FirstChildElement("setting");
634 while (setting)
635 {
636 const std::string id = XMLUtils::GetAttribute(setting, "id");
637 if (!id.empty())
638 m_settings[id] = m_addon->GetSetting(id);
639 setting = setting->NextSiblingElement("setting");
640 }
641 category = category->NextSiblingElement("category");
642 }
643 m_totalSections = buttonID - CONTROL_START_SECTION;
644}
645
646void CGUIDialogAddonSettings::CreateControls()
647{
648 FreeControls();
649
650 CGUISpinControlEx *pOriginalSpin = dynamic_cast<CGUISpinControlEx*>(GetControl(CONTROL_DEFAULT_SPIN));
651 CGUIRadioButtonControl *pOriginalRadioButton = dynamic_cast<CGUIRadioButtonControl *>(GetControl(CONTROL_DEFAULT_RADIOBUTTON));
652 CGUIButtonControl *pOriginalButton = dynamic_cast<CGUIButtonControl *>(GetControl(CONTROL_DEFAULT_BUTTON));
653 CGUIImage *pOriginalImage = dynamic_cast<CGUIImage *>(GetControl(CONTROL_DEFAULT_SEPARATOR));
654 CGUILabelControl *pOriginalLabel = dynamic_cast<CGUILabelControl *>(GetControl(CONTROL_DEFAULT_LABEL_SEPARATOR));
655 CGUISettingsSliderControl *pOriginalSlider = dynamic_cast<CGUISettingsSliderControl *>(GetControl(CONTROL_DEFAULT_SLIDER));
656
657 if (!m_addon || !pOriginalSpin || !pOriginalRadioButton || !pOriginalButton || !pOriginalImage
658 || !pOriginalLabel || !pOriginalSlider)
659 return;
660
661 pOriginalSpin->SetVisible(false);
662 pOriginalRadioButton->SetVisible(false);
663 pOriginalButton->SetVisible(false);
664 pOriginalImage->SetVisible(false);
665 pOriginalLabel->SetVisible(false);
666 pOriginalSlider->SetVisible(false);
667
668 CGUIControlGroupList *group = dynamic_cast<CGUIControlGroupList *>(GetControl(CONTROL_SETTINGS_AREA));
669 if (!group)
670 return;
671
672 // set our dialog heading
673 SET_CONTROL_LABEL(CONTROL_HEADING_LABEL, m_strHeading);
674
675 CGUIControl* pControl = NULL;
676 int controlId = CONTROL_START_SETTING;
677 const TiXmlElement *setting = GetFirstSetting();
678 while (setting)
679 {
680 const std::string type = XMLUtils::GetAttribute(setting, "type");
681 const std::string id = XMLUtils::GetAttribute(setting, "id");
682 const std::string values = XMLUtils::GetAttribute(setting, "values");
683 const std::string lvalues = XMLUtils::GetAttribute(setting, "lvalues");
684 const std::string entries = XMLUtils::GetAttribute(setting, "entries");
685 const std::string defaultVal = XMLUtils::GetAttribute(setting, "default");
686 const std::string subsetting = XMLUtils::GetAttribute(setting, "subsetting");
687 const std::string label = GetString(setting->Attribute("label"), subsetting == "true");
688
689 bool bSort = XMLUtils::GetAttribute(setting, "sort") == "yes";
690 if (!type.empty())
691 {
692 bool isAddonSetting = false;
693 if (type == "text" || type == "ipaddress"
694 || type == "number" || type == "video"
695 || type == "audio" || type == "image"
696 || type == "folder" || type == "executable"
697 || type == "file" || type == "action"
698 || type == "date" || type == "time"
699 || type == "select" || (isAddonSetting = type == "addon"))
700 {
701 pControl = new CGUIButtonControl(*pOriginalButton);
702 if (!pControl) return;
703 ((CGUIButtonControl *)pControl)->SetLabel(label);
704 if (!id.empty())
705 {
706 std::string value = m_settings[id];
707 m_buttonValues[id] = value;
708 // get any option to test for hidden
709 const std::string option = XMLUtils::GetAttribute(setting, "option");
710 if (option == "urlencoded")
711 value = CURL::Decode(value);
712 else if (option == "hidden")
713 {
714 std::string hiddenText;
715 hiddenText.append(value.size(), L'*');
716 ((CGUIButtonControl *)pControl)->SetLabel2(hiddenText);
717 }
718 else
719 {
720 if (isAddonSetting)
721 ((CGUIButtonControl *)pControl)->SetLabel2(GetAddonNames(value));
722 else if (type == "select" && !lvalues.empty())
723 {
724 vector<string> valuesVec = StringUtils::Split(lvalues, '|');
725 int selected = atoi(value.c_str());
726 if (selected >= 0 && selected < (int)valuesVec.size())
727 {
728 std::string label = m_addon->GetString(atoi(valuesVec[selected].c_str()));
729 if (label.empty())
730 label = g_localizeStrings.Get(atoi(valuesVec[selected].c_str()));
731 ((CGUIButtonControl *)pControl)->SetLabel2(label);
732 }
733 }
734 else
735 ((CGUIButtonControl *)pControl)->SetLabel2(value);
736 }
737 }
738 else
739 ((CGUIButtonControl *)pControl)->SetLabel2(defaultVal);
740 }
741 else if (type == "bool" && !id.empty())
742 {
743 pControl = new CGUIRadioButtonControl(*pOriginalRadioButton);
744 if (!pControl) return;
745 ((CGUIRadioButtonControl *)pControl)->SetLabel(label);
746 ((CGUIRadioButtonControl *)pControl)->SetSelected(m_settings[id] == "true");
747 }
748 else if ((type == "enum" || type == "labelenum") && !id.empty())
749 {
750 vector<std::string> valuesVec;
751 vector<std::string> entryVec;
752
753 pControl = new CGUISpinControlEx(*pOriginalSpin);
754 if (!pControl) return;
755 ((CGUISpinControlEx *)pControl)->SetText(label);
756
757 if (!lvalues.empty())
758 StringUtils::Tokenize(lvalues, valuesVec, "|");
759 else if (values == "$HOURS")
760 {
761 for (unsigned int i = 0; i < 24; i++)
762 {
763 CDateTime time(2000, 1, 1, i, 0, 0);
764 valuesVec.push_back(g_infoManager.LocalizeTime(time, TIME_FORMAT_HH_MM_XX));
765 }
766 }
767 else
768 StringUtils::Tokenize(values, valuesVec, "|");
769 if (!entries.empty())
770 StringUtils::Tokenize(entries, entryVec, "|");
771
772 if(bSort && type == "labelenum")
773 std::sort(valuesVec.begin(), valuesVec.end(), sortstringbyname());
774
775 for (unsigned int i = 0; i < valuesVec.size(); i++)
776 {
777 int iAdd = i;
778 if (entryVec.size() > i)
779 iAdd = atoi(entryVec[i].c_str());
780 if (!lvalues.empty())
781 {
782 std::string replace = m_addon->GetString(atoi(valuesVec[i].c_str()));
783 if (replace.empty())
784 replace = g_localizeStrings.Get(atoi(valuesVec[i].c_str()));
785 ((CGUISpinControlEx *)pControl)->AddLabel(replace, iAdd);
786 }
787 else
788 ((CGUISpinControlEx *)pControl)->AddLabel(valuesVec[i], iAdd);
789 }
790 if (type == "labelenum")
791 { // need to run through all our settings and find the one that matches
792 ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_settings[id]);
793 }
794 else
795 ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_settings[id].c_str()));
796
797 }
798 else if (type == "fileenum" && !id.empty())
799 {
800 pControl = new CGUISpinControlEx(*pOriginalSpin);
801 if (!pControl) return;
802 ((CGUISpinControlEx *)pControl)->SetText(label);
803 ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f);
804
805 vector<std::string> items = GetFileEnumValues(values, XMLUtils::GetAttribute(setting, "mask"), XMLUtils::GetAttribute(setting, "option"));
806 for (unsigned int i = 0; i < items.size(); ++i)
807 {
808 ((CGUISpinControlEx *)pControl)->AddLabel(items[i], i);
809 if (StringUtils::EqualsNoCase(items[i], m_settings[id]))
810 ((CGUISpinControlEx *)pControl)->SetValue(i);
811 }
812 }
813 // Sample: <setting id="mysettingname" type="rangeofnum" label="30000" rangestart="0" rangeend="100" elements="11" valueformat="30001" default="0" />
814 // in strings.xml: <string id="30001">%2.0f mp</string>
815 // creates 11 piece, text formated number labels from 0 to 100
816 else if (type == "rangeofnum" && !id.empty())
817 {
818 pControl = new CGUISpinControlEx(*pOriginalSpin);
819 if (!pControl)
820 return;
821 ((CGUISpinControlEx *)pControl)->SetText(label);
822 ((CGUISpinControlEx *)pControl)->SetFloatValue(1.0f);
823
824 double rangestart = 0, rangeend = 1;
825 setting->Attribute("rangestart", &rangestart);
826 setting->Attribute("rangeend", &rangeend);
827
828 int elements = 2;
829 setting->Attribute("elements", &elements);
830
831 std::string valueformat;
832 if (setting->Attribute("valueformat"))
833 valueformat = m_addon->GetString(atoi(setting->Attribute("valueformat")));
834 for (int i = 0; i < elements; i++)
835 {
836 std::string valuestring;
837 if (elements < 2)
838 valuestring = StringUtils::Format(valueformat.c_str(), rangestart);
839 else
840 valuestring = StringUtils::Format(valueformat.c_str(), rangestart+(rangeend-rangestart)/(elements-1)*i);
841 ((CGUISpinControlEx *)pControl)->AddLabel(valuestring, i);
842 }
843 ((CGUISpinControlEx *)pControl)->SetValue(atoi(m_settings[id].c_str()));
844 }
845 // Sample: <setting id="mysettingname" type="slider" label="30000" range="5,5,60" option="int" default="5"/>
846 // to make ints from 5-60 with 5 steps
847 else if (type == "slider" && !id.empty())
848 {
849 pControl = new CGUISettingsSliderControl(*pOriginalSlider);
850 if (!pControl) return;
851 ((CGUISettingsSliderControl *)pControl)->SetText(label);
852
853 float fMin = 0.0f;
854 float fMax = 100.0f;
855 float fInc = 1.0f;
856 vector<std::string> range = StringUtils::Split(XMLUtils::GetAttribute(setting, "range"), ',');
857 if (range.size() > 1)
858 {
859 fMin = (float)atof(range[0].c_str());
860 if (range.size() > 2)
861 {
862 fMax = (float)atof(range[2].c_str());
863 fInc = (float)atof(range[1].c_str());
864 }
865 else
866 fMax = (float)atof(range[1].c_str());
867 }
868
869 std::string option = XMLUtils::GetAttribute(setting, "option");
870 int iType=0;
871
872 if (option.empty() || StringUtils::EqualsNoCase(option, "float"))
873 iType = SLIDER_CONTROL_TYPE_FLOAT;
874 else if (StringUtils::EqualsNoCase(option, "int"))
875 iType = SLIDER_CONTROL_TYPE_INT;
876 else if (StringUtils::EqualsNoCase(option, "percent"))
877 iType = SLIDER_CONTROL_TYPE_PERCENTAGE;
878
879 ((CGUISettingsSliderControl *)pControl)->SetType(iType);
880 ((CGUISettingsSliderControl *)pControl)->SetFloatRange(fMin, fMax);
881 ((CGUISettingsSliderControl *)pControl)->SetFloatInterval(fInc);
882 ((CGUISettingsSliderControl *)pControl)->SetFloatValue((float)atof(m_settings[id].c_str()));
883 }
884 else if (type == "lsep")
885 {
886 pControl = new CGUILabelControl(*pOriginalLabel);
887 if (pControl)
888 ((CGUILabelControl *)pControl)->SetLabel(label);
889 }
890 else if (type == "sep")
891 pControl = new CGUIImage(*pOriginalImage);
892 }
893
894 if (pControl)
895 {
896 pControl->SetWidth(group->GetWidth());
897 pControl->SetVisible(true);
898 pControl->SetID(controlId);
899 pControl->AllocResources();
900 group->AddControl(pControl);
901 pControl = NULL;
902 }
903
904 setting = setting->NextSiblingElement("setting");
905 controlId++;
906 }
907 EnableControls();
908}
909
910std::string CGUIDialogAddonSettings::GetAddonNames(const std::string& addonIDslist) const
911{
912 std::string retVal;
913 vector<string> addons = StringUtils::Split(addonIDslist, ',');
914 for (vector<string>::const_iterator it = addons.begin(); it != addons.end() ; ++it)
915 {
916 if (!retVal.empty())
917 retVal += ", ";
918 AddonPtr addon;
919 if (CAddonMgr::Get().GetAddon(*it ,addon))
920 retVal += addon->Name();
921 else
922 retVal += *it;
923 }
924 return retVal;
925}
926
927vector<std::string> CGUIDialogAddonSettings::GetFileEnumValues(const std::string &path, const std::string &mask, const std::string &options) const
928{
929 // Create our base path, used for type "fileenum" settings
930 // replace $PROFILE with the profile path of the plugin/script
931 std::string fullPath = path;
932 if (fullPath.find("$PROFILE") != std::string::npos)
933 StringUtils::Replace(fullPath, "$PROFILE", m_addon->Profile());
934 else
935 fullPath = URIUtils::AddFileToFolder(m_addon->Path(), path);
936
937 bool hideExtensions = StringUtils::EqualsNoCase(options, "hideext");
938 // fetch directory
939 CFileItemList items;
940 if (!mask.empty())
941 CDirectory::GetDirectory(fullPath, items, mask, XFILE::DIR_FLAG_NO_FILE_DIRS);
942 else
943 CDirectory::GetDirectory(fullPath, items, "", XFILE::DIR_FLAG_NO_FILE_DIRS);
944
945 vector<std::string> values;
946 for (int i = 0; i < items.Size(); ++i)
947 {
948 CFileItemPtr pItem = items[i];
949 if ((mask == "/" && pItem->m_bIsFolder) || !pItem->m_bIsFolder)
950 {
951 if (hideExtensions)
952 pItem->RemoveExtension();
953 values.push_back(pItem->GetLabel());
954 }
955 }
956 return values;
957}
958
959// Go over all the settings and set their enabled condition according to the values of the enabled attribute
960void CGUIDialogAddonSettings::EnableControls()
961{
962 int controlId = CONTROL_START_SETTING;
963 const TiXmlElement *setting = GetFirstSetting();
964 while (setting)
965 {
966 const CGUIControl* control = GetControl(controlId);
967 if (control)
968 {
969 // set enable status
970 const char *enable = setting->Attribute("enable");
971 if (enable)
972 ((CGUIControl*) control)->SetEnabled(GetCondition(enable, controlId));
973 else
974 ((CGUIControl*) control)->SetEnabled(true);
975 // set visible status
976 const char *visible = setting->Attribute("visible");
977 if (visible)
978 ((CGUIControl*) control)->SetVisible(GetCondition(visible, controlId));
979 else
980 ((CGUIControl*) control)->SetVisible(true);
981 }
982 setting = setting->NextSiblingElement("setting");
983 controlId++;
984 }
985}
986
987bool CGUIDialogAddonSettings::GetCondition(const std::string &condition, const int controlId)
988{
989 if (condition.empty()) return true;
990
991 bool bCondition = true;
992 bool bCompare = true;
993 bool bControlDependend = false;//flag if the condition depends on another control
994 vector<std::string> conditionVec;
995
996 if (condition.find("+") != std::string::npos)
997 StringUtils::Tokenize(condition, conditionVec, "+");
998 else
999 {
1000 bCondition = false;
1001 bCompare = false;
1002 StringUtils::Tokenize(condition, conditionVec, "|");
1003 }
1004
1005 for (unsigned int i = 0; i < conditionVec.size(); i++)
1006 {
1007 vector<std::string> condVec;
1008 if (!TranslateSingleString(conditionVec[i], condVec)) continue;
1009
1010 const CGUIControl* control2 = GetControl(controlId + atoi(condVec[1].c_str()));
1011 if (!control2)
1012 continue;
1013
1014 bControlDependend = true; //once we are here - this condition depends on another control
1015
1016 std::string value;
1017 switch (control2->GetControlType())
1018 {
1019 case CGUIControl::GUICONTROL_BUTTON:
1020 value = ((CGUIButtonControl*) control2)->GetLabel2();
1021 break;
1022 case CGUIControl::GUICONTROL_RADIO:
1023 value = ((CGUIRadioButtonControl*) control2)->IsSelected() ? "true" : "false";
1024 break;
1025 case CGUIControl::GUICONTROL_SPINEX:
1026 if (((CGUISpinControlEx*) control2)->GetFloatValue() > 0.0f)
1027 value = ((CGUISpinControlEx*) control2)->GetLabel();
1028 else
1029 value = StringUtils::Format("%i", ((CGUISpinControlEx*) control2)->GetValue());
1030 break;
1031 default:
1032 break;
1033 }
1034
1035 if (condVec[0] == "eq")
1036 {
1037 if (bCompare)
1038 bCondition &= StringUtils::EqualsNoCase(value, condVec[2]);
1039 else
1040 bCondition |= StringUtils::EqualsNoCase(value, condVec[2]);
1041 }
1042 else if (condVec[0] == "!eq")
1043 {
1044 if (bCompare)
1045 bCondition &= !StringUtils::EqualsNoCase(value, condVec[2]);
1046 else
1047 bCondition |= !StringUtils::EqualsNoCase(value, condVec[2]);
1048 }
1049 else if (condVec[0] == "gt")
1050 {
1051 if (bCompare)
1052 bCondition &= (atoi(value.c_str()) > atoi(condVec[2].c_str()));
1053 else
1054 bCondition |= (atoi(value.c_str()) > atoi(condVec[2].c_str()));
1055 }
1056 else if (condVec[0] == "lt")
1057 {
1058 if (bCompare)
1059 bCondition &= (atoi(value.c_str()) < atoi(condVec[2].c_str()));
1060 else
1061 bCondition |= (atoi(value.c_str()) < atoi(condVec[2].c_str()));
1062 }
1063 }
1064
1065 if (!bControlDependend)//if condition doesn't depend on another control - try if its an infobool expression
1066 {
1067 bCondition = g_infoManager.EvaluateBool(condition);
1068 }
1069
1070 return bCondition;
1071}
1072
1073bool CGUIDialogAddonSettings::TranslateSingleString(const std::string &strCondition, vector<std::string> &condVec)
1074{
1075 std::string strTest = strCondition;
1076 StringUtils::ToLower(strTest);
1077 StringUtils::Trim(strTest);
1078
1079 size_t pos1 = strTest.find("(");
1080 size_t pos2 = strTest.find(",", pos1);
1081 size_t pos3 = strTest.find(")", pos2);
1082 if (pos1 != std::string::npos &&
1083 pos2 != std::string::npos &&
1084 pos3 != std::string::npos)
1085 {
1086 condVec.push_back(strTest.substr(0, pos1));
1087 condVec.push_back(strTest.substr(pos1 + 1, pos2 - pos1 - 1));
1088 condVec.push_back(strTest.substr(pos2 + 1, pos3 - pos2 - 1));
1089 return true;
1090 }
1091 return false;
1092}
1093
1094std::string CGUIDialogAddonSettings::GetString(const char *value, bool subSetting) const
1095{
1096 if (!value)
1097 return "";
1098 std::string prefix(subSetting ? "- " : "");
1099 if (StringUtils::IsNaturalNumber(value))
1100 return prefix + m_addon->GetString(atoi(value));
1101 return prefix + value;
1102}
1103
1104// Go over all the settings and set their default values
1105void CGUIDialogAddonSettings::SetDefaultSettings()
1106{
1107 if(!m_addon)
1108 return;
1109
1110 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
1111 if (!category) // add a default one...
1112 category = m_addon->GetSettingsXML();
1113
1114 while (category)
1115 {
1116 const TiXmlElement *setting = category->FirstChildElement("setting");
1117 while (setting)
1118 {
1119 const std::string id = XMLUtils::GetAttribute(setting, "id");
1120 const std::string type = XMLUtils::GetAttribute(setting, "type");
1121 const char *value = setting->Attribute("default");
1122 if (!id.empty())
1123 {
1124 if (value)
1125 m_settings[id] = value;
1126 else if (type == "bool")
1127 m_settings[id] = "false";
1128 else if (type == "slider" || type == "enum")
1129 m_settings[id] = "0";
1130 else
1131 m_settings[id] = "";
1132 }
1133 setting = setting->NextSiblingElement("setting");
1134 }
1135 category = category->NextSiblingElement("category");
1136 }
1137 CreateControls();
1138}
1139
1140const TiXmlElement *CGUIDialogAddonSettings::GetFirstSetting() const
1141{
1142 const TiXmlElement *category = m_addon->GetSettingsXML()->FirstChildElement("category");
1143 if (!category)
1144 category = m_addon->GetSettingsXML();
1145 for (unsigned int i = 0; i < m_currentSection && category; i++)
1146 category = category->NextSiblingElement("category");
1147 if (category)
1148 return category->FirstChildElement("setting");
1149 return NULL;
1150}
1151
1152void CGUIDialogAddonSettings::DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions)
1153{
1154 // update status of current section button
1155 bool alphaFaded = false;
1156 CGUIControl *control = GetFirstFocusableControl(CONTROL_START_SECTION + m_currentSection);
1157 if (control && !control->HasFocus())
1158 {
1159 if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
1160 {
1161 control->SetFocus(true);
1162 ((CGUIButtonControl *)control)->SetAlpha(0x80);
1163 alphaFaded = true;
1164 }
1165 else if (control->GetControlType() == CGUIControl::GUICONTROL_TOGGLEBUTTON)
1166 {
1167 control->SetFocus(true);
1168 ((CGUIButtonControl *)control)->SetSelected(true);
1169 alphaFaded = true;
1170 }
1171 }
1172 CGUIDialogBoxBase::DoProcess(currentTime, dirtyregions);
1173 if (alphaFaded && m_active) // dialog may close
1174 {
1175 control->SetFocus(false);
1176 if (control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
1177 ((CGUIButtonControl *)control)->SetAlpha(0xFF);
1178 else
1179 ((CGUIButtonControl *)control)->SetSelected(false);
1180 }
1181}
1182
1183std::string CGUIDialogAddonSettings::GetCurrentID() const
1184{
1185 if (m_addon)
1186 return m_addon->ID();
1187 return "";
1188}
1189
1190int CGUIDialogAddonSettings::GetDefaultLabelID(int controlId) const
1191{
1192 if (controlId == ID_BUTTON_OK)
1193 return 186;
1194 else if (controlId == ID_BUTTON_CANCEL)
1195 return 222;
1196 else if (controlId == ID_BUTTON_DEFAULT)
1197 return 409;
1198
1199 return CGUIDialogBoxBase::GetDefaultLabelID(controlId);
1200}
diff --git a/xbmc/addons/GUIDialogAddonSettings.h b/xbmc/addons/GUIDialogAddonSettings.h
new file mode 100644
index 0000000..9c9c156
--- /dev/null
+++ b/xbmc/addons/GUIDialogAddonSettings.h
@@ -0,0 +1,91 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "dialogs/GUIDialogBoxBase.h"
23#include "addons/Addon.h"
24
25class CGUIDialogAddonSettings : public CGUIDialogBoxBase
26{
27public:
28 CGUIDialogAddonSettings(void);
29 virtual ~CGUIDialogAddonSettings(void);
30 virtual bool OnMessage(CGUIMessage& message);
31 virtual bool OnAction(const CAction& action);
32 /*! \brief Show the addon settings dialog, allowing the user to configure an addon
33 \param addon the addon to configure
34 \param saveToDisk whether the changes should be saved to disk or just made local to the addon. Defaults to true
35 \return true if settings were changed and the dialog confirmed, false otherwise.
36 */
37 static bool ShowAndGetInput(const ADDON::AddonPtr &addon, bool saveToDisk = true);
38 virtual void DoProcess(unsigned int currentTime, CDirtyRegionList &dirtyregions);
39
40 std::string GetCurrentID() const;
41protected:
42 virtual void OnInitWindow();
43 virtual int GetDefaultLabelID(int controlId) const;
44
45private:
46 /*! \brief return a (localized) addon string.
47 \param value either a character string (which is used directly) or a number to lookup in the addons strings.xml
48 \param subsetting whether the character string should be prefixed by "- ", defaults to false
49 \return the localized addon string
50 */
51 std::string GetString(const char *value, bool subSetting = false) const;
52
53 /*! \brief return a the values for a fileenum setting
54 \param path the path to use for files
55 \param mask the mask to use
56 \param options any options, such as "hideext" to hide extensions
57 \return the filenames in the path that match the mask
58 */
59 std::vector<std::string> GetFileEnumValues(const std::string &path, const std::string &mask, const std::string &options) const;
60
61 /*! \brief Translate list of addon IDs to list of addon names
62 \param addonIDslist comma seperated list of addon IDs
63 \return comma seperated list of addon names
64 */
65 std::string GetAddonNames(const std::string& addonIDslist) const;
66
67 void CreateSections();
68 void FreeSections();
69 void CreateControls();
70 void FreeControls();
71 void UpdateFromControls();
72 void EnableControls();
73 void SetDefaultSettings();
74 bool GetCondition(const std::string &condition, const int controlId);
75
76 void SaveSettings(void);
77 bool ShowVirtualKeyboard(int iControl);
78 bool TranslateSingleString(const std::string &strCondition, std::vector<std::string> &enableVec);
79
80 const TiXmlElement *GetFirstSetting() const;
81
82 ADDON::AddonPtr m_addon;
83 std::map<std::string,std::string> m_buttonValues;
84 bool m_saveToDisk; // whether the addon settings should be saved to disk or just stored locally in the addon
85
86 unsigned int m_currentSection;
87 unsigned int m_totalSections;
88
89 std::map<std::string,std::string> m_settings; // local storage of values
90};
91
diff --git a/xbmc/addons/GUIViewStateAddonBrowser.cpp b/xbmc/addons/GUIViewStateAddonBrowser.cpp
new file mode 100644
index 0000000..4f42b2e
--- /dev/null
+++ b/xbmc/addons/GUIViewStateAddonBrowser.cpp
@@ -0,0 +1,132 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "GUIViewStateAddonBrowser.h"
22#include "FileItem.h"
23#include "filesystem/File.h"
24#include "guilib/GraphicContext.h"
25#include "guilib/WindowIDs.h"
26#include "view/ViewState.h"
27#include "addons/Addon.h"
28#include "addons/AddonManager.h"
29#include "addons/AddonInstaller.h"
30#include "AddonDatabase.h"
31#include "utils/StringUtils.h"
32
33using namespace XFILE;
34using namespace ADDON;
35
36CGUIViewStateAddonBrowser::CGUIViewStateAddonBrowser(const CFileItemList& items) : CGUIViewState(items)
37{
38 if (items.IsVirtualDirectoryRoot())
39 {
40 AddSortMethod(SortByNone, 551, LABEL_MASKS("%F", "", "%L", ""));
41 SetSortMethod(SortByNone);
42 }
43 else
44 {
45 AddSortMethod(SortByLabel, SortAttributeIgnoreFolders, 551, LABEL_MASKS("%L", "%I", "%L", "")); // Filename, Size | Foldername, empty
46 AddSortMethod(SortByDate, 552, LABEL_MASKS("%L", "%J", "%L", "%J")); // Filename, Date | Foldername, Date
47 SetSortMethod(SortByLabel);
48 }
49 SetViewAsControl(DEFAULT_VIEW_AUTO);
50
51 SetSortOrder(SortOrderAscending);
52 LoadViewState(items.GetPath(), WINDOW_ADDON_BROWSER);
53}
54
55void CGUIViewStateAddonBrowser::SaveViewState()
56{
57 SaveViewToDb(m_items.GetPath(), WINDOW_ADDON_BROWSER);
58}
59
60std::string CGUIViewStateAddonBrowser::GetExtensions()
61{
62 return "";
63}
64
65VECSOURCES& CGUIViewStateAddonBrowser::GetSources()
66{
67 m_sources.clear();
68
69 { // check for updates
70 CMediaSource share;
71 share.strPath = "addons://check/";
72 share.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOTE; // hack for sorting
73 share.strName = g_localizeStrings.Get(24055); // "Check for updates"
74 CDateTime lastChecked = CAddonInstaller::Get().LastRepoUpdate();
75 if (lastChecked.IsValid())
76 share.strStatus = StringUtils::Format(g_localizeStrings.Get(24056).c_str(),
77 lastChecked.GetAsLocalizedDateTime(false, false).c_str());
78 m_sources.push_back(share);
79 }
80 if (CAddonMgr::Get().HasOutdatedAddons())
81 {
82 CMediaSource share;
83 share.strPath = "addons://outdated/";
84 share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
85 share.strName = g_localizeStrings.Get(24043); // "Available updates"
86 m_sources.push_back(share);
87 }
88 CAddonDatabase db;
89 if (db.Open() && db.HasDisabledAddons())
90 {
91 CMediaSource share;
92 share.strPath = "addons://disabled/";
93 share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
94 share.strName = g_localizeStrings.Get(24039);
95 m_sources.push_back(share);
96 }
97 // we always have some enabled addons
98 {
99 CMediaSource share;
100 share.strPath = "addons://enabled/";
101 share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
102 share.strName = g_localizeStrings.Get(24062);
103 m_sources.push_back(share);
104 }
105 if (CAddonMgr::Get().HasAddons(ADDON_REPOSITORY,true))
106 {
107 CMediaSource share;
108 share.strPath = "addons://repos/";
109 share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
110 share.strName = g_localizeStrings.Get(24033);
111 m_sources.push_back(share);
112 }
113 // add "install from zip"
114 {
115 CMediaSource share;
116 share.strPath = "addons://install/";
117 share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
118 share.strName = g_localizeStrings.Get(24041);
119 m_sources.push_back(share);
120 }
121 // add "search"
122 {
123 CMediaSource share;
124 share.strPath = "addons://search/";
125 share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
126 share.strName = g_localizeStrings.Get(137);
127 m_sources.push_back(share);
128 }
129
130 return CGUIViewState::GetSources();
131}
132
diff --git a/xbmc/addons/GUIViewStateAddonBrowser.h b/xbmc/addons/GUIViewStateAddonBrowser.h
new file mode 100644
index 0000000..565cdc8
--- /dev/null
+++ b/xbmc/addons/GUIViewStateAddonBrowser.h
@@ -0,0 +1,35 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "view/GUIViewState.h"
24
25class CGUIViewStateAddonBrowser : public CGUIViewState
26{
27public:
28 CGUIViewStateAddonBrowser(const CFileItemList& items);
29
30protected:
31 virtual void SaveViewState();
32 virtual std::string GetExtensions();
33 virtual VECSOURCES& GetSources();
34};
35
diff --git a/xbmc/addons/GUIWindowAddonBrowser.cpp b/xbmc/addons/GUIWindowAddonBrowser.cpp
new file mode 100644
index 0000000..f4560dd
--- /dev/null
+++ b/xbmc/addons/GUIWindowAddonBrowser.cpp
@@ -0,0 +1,677 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "GUIWindowAddonBrowser.h"
22#include "addons/AddonManager.h"
23#include "addons/Repository.h"
24#include "GUIDialogAddonInfo.h"
25#include "GUIDialogAddonSettings.h"
26#include "dialogs/GUIDialogBusy.h"
27#include "dialogs/GUIDialogOK.h"
28#include "dialogs/GUIDialogYesNo.h"
29#include "dialogs/GUIDialogSelect.h"
30#include "dialogs/GUIDialogFileBrowser.h"
31#include "GUIUserMessages.h"
32#include "guilib/GUIWindowManager.h"
33#include "utils/URIUtils.h"
34#include "URL.h"
35#include "FileItem.h"
36#include "filesystem/File.h"
37#include "filesystem/Directory.h"
38#include "filesystem/AddonsDirectory.h"
39#include "addons/AddonInstaller.h"
40#include "utils/JobManager.h"
41#include "utils/log.h"
42#include "threads/SingleLock.h"
43#include "settings/Settings.h"
44#include "settings/MediaSourceSettings.h"
45#include "utils/StringUtils.h"
46#include "AddonDatabase.h"
47#include "settings/AdvancedSettings.h"
48#include "storage/MediaManager.h"
49#include "LangInfo.h"
50#include "input/Key.h"
51#include "ContextMenuManager.h"
52
53#define CONTROL_AUTOUPDATE 5
54#define CONTROL_SHUTUP 6
55#define CONTROL_FOREIGNFILTER 7
56#define CONTROL_BROKENFILTER 8
57
58using namespace ADDON;
59using namespace XFILE;
60using namespace std;
61
62CGUIWindowAddonBrowser::CGUIWindowAddonBrowser(void)
63: CGUIMediaWindow(WINDOW_ADDON_BROWSER, "AddonBrowser.xml")
64{
65}
66
67CGUIWindowAddonBrowser::~CGUIWindowAddonBrowser()
68{
69}
70
71bool CGUIWindowAddonBrowser::OnMessage(CGUIMessage& message)
72{
73 switch ( message.GetMessage() )
74 {
75 case GUI_MSG_WINDOW_DEINIT:
76 {
77 if (m_thumbLoader.IsLoading())
78 m_thumbLoader.StopThread();
79 }
80 break;
81 case GUI_MSG_WINDOW_INIT:
82 {
83 m_rootDir.AllowNonLocalSources(false);
84
85 // is this the first time the window is opened?
86 if (m_vecItems->GetPath() == "?" && message.GetStringParam().empty())
87 m_vecItems->SetPath("");
88 }
89 break;
90 case GUI_MSG_CLICKED:
91 {
92 int iControl = message.GetSenderId();
93 if (iControl == CONTROL_AUTOUPDATE)
94 {
95 const CGUIControl *control = GetControl(CONTROL_AUTOUPDATE);
96 if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
97 CSettings::Get().SetInt("general.addonupdates", (CSettings::Get().GetInt("general.addonupdates")+1) % AUTO_UPDATES_MAX);
98 else
99 CSettings::Get().SetInt("general.addonupdates", (CSettings::Get().GetInt("general.addonupdates") == 0) ? 1 : 0);
100 UpdateButtons();
101 return true;
102 }
103 else if (iControl == CONTROL_SHUTUP)
104 {
105 CSettings::Get().ToggleBool("general.addonnotifications");
106 CSettings::Get().Save();
107 return true;
108 }
109 else if (iControl == CONTROL_FOREIGNFILTER)
110 {
111 CSettings::Get().ToggleBool("general.addonforeignfilter");
112 CSettings::Get().Save();
113 Refresh();
114 return true;
115 }
116 else if (iControl == CONTROL_BROKENFILTER)
117 {
118 CSettings::Get().ToggleBool("general.addonbrokenfilter");
119 CSettings::Get().Save();
120 Refresh();
121 return true;
122 }
123 else if (m_viewControl.HasControl(iControl)) // list/thumb control
124 {
125 // get selected item
126 int iItem = m_viewControl.GetSelectedItem();
127 int iAction = message.GetParam1();
128
129 // iItem is checked for validity inside these routines
130 if (iAction == ACTION_SHOW_INFO)
131 {
132 if (!m_vecItems->Get(iItem)->GetProperty("Addon.ID").empty())
133 return CGUIDialogAddonInfo::ShowForItem((*m_vecItems)[iItem]);
134 return false;
135 }
136 }
137 }
138 break;
139 case GUI_MSG_NOTIFY_ALL:
140 {
141 if (message.GetParam1() == GUI_MSG_UPDATE_ITEM && IsActive() && message.GetNumStringParams() == 1)
142 { // update this item
143 for (int i = 0; i < m_vecItems->Size(); ++i)
144 {
145 CFileItemPtr item = m_vecItems->Get(i);
146 if (item->GetProperty("Addon.ID") == message.GetStringParam())
147 {
148 SetItemLabel2(item);
149 return true;
150 }
151 }
152 }
153 }
154 break;
155 default:
156 break;
157 }
158 return CGUIMediaWindow::OnMessage(message);
159}
160
161void CGUIWindowAddonBrowser::GetContextButtons(int itemNumber, CContextButtons& buttons)
162{
163 if (itemNumber < 0 || itemNumber >= m_vecItems->Size())
164 return;
165
166 CFileItemPtr pItem = m_vecItems->Get(itemNumber);
167 if (!pItem->IsPath("addons://enabled/"))
168 buttons.Add(CONTEXT_BUTTON_SCAN,24034);
169
170 AddonPtr addon;
171 if (!CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false)) // allow disabled addons
172 return;
173
174 if (addon->Type() == ADDON_REPOSITORY && pItem->m_bIsFolder)
175 {
176 buttons.Add(CONTEXT_BUTTON_SCAN,24034);
177 buttons.Add(CONTEXT_BUTTON_REFRESH,24035);
178 }
179
180 buttons.Add(CONTEXT_BUTTON_INFO,24003);
181
182 if (addon->HasSettings())
183 buttons.Add(CONTEXT_BUTTON_SETTINGS,24020);
184
185 CContextMenuManager::Get().AddVisibleItems(pItem, buttons);
186}
187
188bool CGUIWindowAddonBrowser::OnContextButton(int itemNumber,
189 CONTEXT_BUTTON button)
190{
191 CFileItemPtr pItem = m_vecItems->Get(itemNumber);
192 if (pItem->IsPath("addons://enabled/"))
193 {
194 if (button == CONTEXT_BUTTON_SCAN)
195 {
196 CAddonMgr::Get().FindAddons();
197 return true;
198 }
199 }
200
201 AddonPtr addon;
202 if (CAddonMgr::Get().GetAddon(pItem->GetProperty("Addon.ID").asString(), addon, ADDON_UNKNOWN, false))
203 {
204 if (button == CONTEXT_BUTTON_SETTINGS)
205 return CGUIDialogAddonSettings::ShowAndGetInput(addon);
206
207 if (button == CONTEXT_BUTTON_REFRESH)
208 {
209 CAddonDatabase database;
210 database.Open();
211 database.DeleteRepository(addon->ID());
212 button = CONTEXT_BUTTON_SCAN;
213 }
214
215 if (button == CONTEXT_BUTTON_SCAN)
216 {
217 CAddonInstaller::Get().UpdateRepos(true);
218 return true;
219 }
220
221 if (button == CONTEXT_BUTTON_INFO)
222 {
223 CGUIDialogAddonInfo::ShowForItem(pItem);
224 return true;
225 }
226 }
227
228 return CGUIMediaWindow::OnContextButton(itemNumber, button);
229}
230
231class UpdateAddons : public IRunnable
232{
233 virtual void Run()
234 {
235 VECADDONS addons;
236 CAddonMgr::Get().GetAllOutdatedAddons(addons, true); // get local
237 for (VECADDONS::iterator i = addons.begin(); i != addons.end(); ++i)
238 {
239 std::string referer = StringUtils::Format("Referer=%s-%s.zip",(*i)->ID().c_str(),(*i)->Version().asString().c_str());
240 CAddonInstaller::Get().Install((*i)->ID(), true, referer); // force install
241 }
242 }
243};
244
245class UpdateRepos : public IRunnable
246{
247 virtual void Run()
248 {
249 CAddonInstaller::Get().UpdateRepos(true, true);
250 }
251};
252
253bool CGUIWindowAddonBrowser::OnClick(int iItem)
254{
255 CFileItemPtr item = m_vecItems->Get(iItem);
256 if (item->GetPath() == "addons://install/")
257 {
258 // pop up filebrowser to grab an installed folder
259 VECSOURCES shares = *CMediaSourceSettings::Get().GetSources("files");
260 g_mediaManager.GetLocalDrives(shares);
261 g_mediaManager.GetNetworkLocations(shares);
262 std::string path;
263 if (CGUIDialogFileBrowser::ShowAndGetFile(shares, "*.zip", g_localizeStrings.Get(24041), path))
264 CAddonInstaller::Get().InstallFromZip(path);
265 return true;
266 }
267 else if (item->GetPath() == "addons://check/")
268 {
269 // perform the check for updates
270 UpdateRepos updater;
271 if (CGUIDialogBusy::Wait(&updater))
272 Refresh();
273 return true;
274 }
275 if (item->GetPath() == "addons://update_all/")
276 {
277 // fire off a threaded update of all addons
278 UpdateAddons updater;
279 if (CGUIDialogBusy::Wait(&updater))
280 return Update("addons://downloading/");
281 return true;
282 }
283 if (!item->m_bIsFolder)
284 {
285 // cancel a downloading job
286 if (item->HasProperty("Addon.Downloading"))
287 {
288 if (CGUIDialogYesNo::ShowAndGetInput(g_localizeStrings.Get(24000),
289 item->GetProperty("Addon.Name").asString(),
290 g_localizeStrings.Get(24066),""))
291 {
292 if (CAddonInstaller::Get().Cancel(item->GetProperty("Addon.ID").asString()))
293 Refresh();
294 }
295 return true;
296 }
297
298 CGUIDialogAddonInfo::ShowForItem(item);
299 return true;
300 }
301 if (item->IsPath("addons://search/"))
302 return Update(item->GetPath());
303
304 return CGUIMediaWindow::OnClick(iItem);
305}
306
307void CGUIWindowAddonBrowser::UpdateButtons()
308{
309 const CGUIControl *control = GetControl(CONTROL_AUTOUPDATE);
310 if (control && control->GetControlType() == CGUIControl::GUICONTROL_BUTTON)
311 { // set label
312 CSettingInt *setting = (CSettingInt *)CSettings::Get().GetSetting("general.addonupdates");
313 if (setting)
314 {
315 const StaticIntegerSettingOptions& options = setting->GetOptions();
316 for (StaticIntegerSettingOptions::const_iterator it = options.begin(); it != options.end(); ++it)
317 {
318 if (it->second == setting->GetValue())
319 {
320 SET_CONTROL_LABEL(CONTROL_AUTOUPDATE, it->first);
321 break;
322 }
323 }
324 }
325 }
326 else
327 { // old skin with toggle button - set on if auto updates are on
328 SET_CONTROL_SELECTED(GetID(),CONTROL_AUTOUPDATE, CSettings::Get().GetInt("general.addonupdates") == AUTO_UPDATES_ON);
329 }
330 SET_CONTROL_SELECTED(GetID(),CONTROL_SHUTUP, CSettings::Get().GetBool("general.addonnotifications"));
331 SET_CONTROL_SELECTED(GetID(),CONTROL_FOREIGNFILTER, CSettings::Get().GetBool("general.addonforeignfilter"));
332 SET_CONTROL_SELECTED(GetID(),CONTROL_BROKENFILTER, CSettings::Get().GetBool("general.addonbrokenfilter"));
333 CGUIMediaWindow::UpdateButtons();
334}
335
336static bool FilterVar(bool valid, const CVariant& variant,
337 const std::string& check)
338{
339 if (!valid)
340 return false;
341
342 if (variant.isNull() || variant.asString().empty())
343 return false;
344
345 std::string regions = variant.asString();
346 return regions.find(check) == std::string::npos;
347}
348
349bool CGUIWindowAddonBrowser::GetDirectory(const std::string& strDirectory,
350 CFileItemList& items)
351{
352 bool result;
353 if (URIUtils::PathEquals(strDirectory, "addons://downloading/"))
354 {
355 VECADDONS addons;
356 CAddonInstaller::Get().GetInstallList(addons);
357
358 CURL url(strDirectory);
359 CAddonsDirectory::GenerateListing(url,addons,items);
360 result = true;
361 items.SetProperty("reponame",g_localizeStrings.Get(24067));
362 items.SetPath(strDirectory);
363
364 if (m_guiState.get() && !m_guiState->HideParentDirItems())
365 {
366 CFileItemPtr pItem(new CFileItem(".."));
367 pItem->SetPath(m_history.GetParentPath());
368 pItem->m_bIsFolder = true;
369 pItem->m_bIsShareOrDrive = false;
370 items.AddFront(pItem, 0);
371 }
372
373 }
374 else
375 {
376 result = CGUIMediaWindow::GetDirectory(strDirectory,items);
377 if (CSettings::Get().GetBool("general.addonforeignfilter"))
378 {
379 int i=0;
380 while (i < items.Size())
381 {
382 if (!FilterVar(true, items[i]->GetProperty("Addon.Language"), "en") ||
383 !FilterVar(true, items[i]->GetProperty("Addon.Language"), g_langInfo.GetLanguageLocale()))
384 {
385 i++;
386 }
387 else
388 items.Remove(i);
389 }
390 }
391 if (CSettings::Get().GetBool("general.addonbrokenfilter"))
392 {
393 for (int i = items.Size() - 1; i >= 0; i--)
394 {
395 if (!items[i]->GetProperty("Addon.Broken").empty())
396 { //check if it's installed
397 AddonPtr addon;
398 if (!CAddonMgr::Get().GetAddon(items[i]->GetProperty("Addon.ID").asString(), addon))
399 items.Remove(i);
400 }
401 }
402 }
403 }
404
405 if (strDirectory.empty() && CAddonInstaller::Get().IsDownloading())
406 {
407 CFileItemPtr item(new CFileItem("addons://downloading/",true));
408 item->SetLabel(g_localizeStrings.Get(24067));
409 item->SetLabelPreformated(true);
410 item->SetIconImage("DefaultNetwork.png");
411 items.Add(item);
412 }
413
414 items.SetContent("addons");
415
416 for (int i=0;i<items.Size();++i)
417 SetItemLabel2(items[i]);
418
419 return result;
420}
421
422void CGUIWindowAddonBrowser::SetItemLabel2(CFileItemPtr item)
423{
424 if (!item || item->m_bIsFolder) return;
425 unsigned int percent;
426 if (CAddonInstaller::Get().GetProgress(item->GetProperty("Addon.ID").asString(), percent))
427 {
428 std::string progress = StringUtils::Format(g_localizeStrings.Get(24042).c_str(), percent);
429 item->SetProperty("Addon.Status", progress);
430 item->SetProperty("Addon.Downloading", true);
431 }
432 else
433 item->ClearProperty("Addon.Downloading");
434 item->SetLabel2(item->GetProperty("Addon.Status").asString());
435 // to avoid the view state overriding label 2
436 item->SetLabelPreformated(true);
437}
438
439bool CGUIWindowAddonBrowser::Update(const std::string &strDirectory, bool updateFilterPath /* = true */)
440{
441 if (m_thumbLoader.IsLoading())
442 m_thumbLoader.StopThread();
443
444 if (!CGUIMediaWindow::Update(strDirectory, updateFilterPath))
445 return false;
446
447 m_thumbLoader.Load(*m_vecItems);
448
449 return true;
450}
451
452int CGUIWindowAddonBrowser::SelectAddonID(TYPE type, std::string &addonID, bool showNone /* = false */, bool showDetails /* = true */, bool showInstalled /* = true */, bool showInstallable /*= false */, bool showMore /* = true */)
453{
454 vector<ADDON::TYPE> types;
455 types.push_back(type);
456 return SelectAddonID(types, addonID, showNone, showDetails, showInstalled, showInstallable, showMore);
457}
458
459int CGUIWindowAddonBrowser::SelectAddonID(ADDON::TYPE type, vector<string> &addonIDs, bool showNone /* = false */, bool showDetails /* = true */, bool multipleSelection /* = true */, bool showInstalled /* = true */, bool showInstallable /* = false */, bool showMore /* = true */)
460{
461 vector<ADDON::TYPE> types;
462 types.push_back(type);
463 return SelectAddonID(types, addonIDs, showNone, showDetails, multipleSelection, showInstalled, showInstallable, showMore);
464}
465
466int CGUIWindowAddonBrowser::SelectAddonID(const vector<ADDON::TYPE> &types, std::string &addonID, bool showNone /* = false */, bool showDetails /* = true */, bool showInstalled /* = true */, bool showInstallable /* = false */, bool showMore /* = true */)
467{
468 vector<string> addonIDs;
469 if (!addonID.empty())
470 addonIDs.push_back(addonID);
471 int retval = SelectAddonID(types, addonIDs, showNone, showDetails, false, showInstalled, showInstallable, showMore);
472 if (addonIDs.size() > 0)
473 addonID = addonIDs.at(0);
474 else
475 addonID = "";
476 return retval;
477}
478
479int CGUIWindowAddonBrowser::SelectAddonID(const vector<ADDON::TYPE> &types, vector<string> &addonIDs, bool showNone /* = false */, bool showDetails /* = true */, bool multipleSelection /* = true */, bool showInstalled /* = true */, bool showInstallable /* = false */, bool showMore /* = true */)
480{
481 // if we shouldn't show neither installed nor installable addons the list will be empty
482 if (!showInstalled && !showInstallable)
483 return 0;
484
485 // can't show the "Get More" button if we already show installable addons
486 if (showInstallable)
487 showMore = false;
488
489 CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
490 if (!dialog)
491 return 0;
492
493 // get rid of any invalid addon types
494 vector<ADDON::TYPE> validTypes(types.size());
495 std::copy_if(types.begin(), types.end(), validTypes.begin(), [](ADDON::TYPE type) { return type != ADDON_UNKNOWN; });
496
497 if (validTypes.empty())
498 return 0;
499
500 // get all addons to show
501 VECADDONS addons;
502 if (showInstalled)
503 {
504 for (vector<ADDON::TYPE>::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type)
505 {
506 VECADDONS typeAddons;
507 if (*type == ADDON_AUDIO)
508 CAddonsDirectory::GetScriptsAndPlugins("audio", typeAddons);
509 else if (*type == ADDON_EXECUTABLE)
510 CAddonsDirectory::GetScriptsAndPlugins("executable", typeAddons);
511 else if (*type == ADDON_IMAGE)
512 CAddonsDirectory::GetScriptsAndPlugins("image", typeAddons);
513 else if (*type == ADDON_VIDEO)
514 CAddonsDirectory::GetScriptsAndPlugins("video", typeAddons);
515 else
516 CAddonMgr::Get().GetAddons(*type, typeAddons);
517
518 addons.insert(addons.end(), typeAddons.begin(), typeAddons.end());
519 }
520 }
521
522 if (showInstallable || showMore)
523 {
524 VECADDONS installableAddons;
525 CAddonDatabase database;
526 if (database.Open() && database.GetAddons(installableAddons))
527 {
528 for (ADDON::IVECADDONS addon = installableAddons.begin(); addon != installableAddons.end();)
529 {
530 AddonPtr pAddon = *addon;
531
532 // check if the addon matches one of the provided addon types
533 bool matchesType = false;
534 for (vector<ADDON::TYPE>::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type)
535 {
536 if (pAddon->IsType(*type))
537 {
538 matchesType = true;
539 break;
540 }
541 }
542
543 // only show addons that match one of the provided addon types and that aren't disabled
544 if (matchesType && !CAddonMgr::Get().IsAddonDisabled(pAddon->ID()))
545 {
546 // check if the addon is installed
547 bool isInstalled = CAddonMgr::Get().IsAddonInstalled(pAddon->ID());
548
549 // check if the addon is installed or can be installed
550 if ((showInstallable || showMore) && !isInstalled && CAddonMgr::Get().CanAddonBeInstalled(pAddon))
551 {
552 ++addon;
553 continue;
554 }
555 }
556
557 addon = installableAddons.erase(addon);
558 }
559
560 if (showInstallable)
561 addons.insert(addons.end(), installableAddons.begin(), installableAddons.end());
562 else if (showMore)
563 showMore = !installableAddons.empty();
564 }
565 }
566
567 if (addons.empty() && !showNone)
568 return 0;
569
570 // turn the addons into items
571 std::map<std::string, AddonPtr> addonMap;
572 CFileItemList items;
573 for (ADDON::IVECADDONS addon = addons.begin(); addon != addons.end(); ++addon)
574 {
575 CFileItemPtr item(CAddonsDirectory::FileItemFromAddon(*addon, ""));
576 if (!items.Contains(item->GetPath()))
577 {
578 items.Add(item);
579 addonMap.insert(std::make_pair(item->GetPath(), *addon));
580 }
581 }
582
583 if (items.IsEmpty() && !showNone)
584 return 0;
585
586 std::string heading;
587 for (vector<ADDON::TYPE>::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type)
588 {
589 if (!heading.empty())
590 heading += ", ";
591 heading += TranslateType(*type, true);
592 }
593
594 dialog->SetHeading(heading);
595 dialog->Reset();
596 dialog->SetUseDetails(showDetails);
597
598 if (multipleSelection)
599 {
600 showNone = false;
601 showMore = false;
602 dialog->EnableButton(true, 186);
603 }
604 else if (showMore)
605 dialog->EnableButton(true, 21452);
606
607 if (showNone)
608 {
609 CFileItemPtr item(new CFileItem("", false));
610 item->SetLabel(g_localizeStrings.Get(231));
611 item->SetLabel2(g_localizeStrings.Get(24040));
612 item->SetIconImage("DefaultAddonNone.png");
613 item->SetSpecialSort(SortSpecialOnTop);
614 items.Add(item);
615 }
616 items.Sort(SortByLabel, SortOrderAscending);
617
618 if (addonIDs.size() > 0)
619 {
620 for (vector<string>::const_iterator it = addonIDs.begin(); it != addonIDs.end() ; ++it)
621 {
622 CFileItemPtr item = items.Get(*it);
623 if (item)
624 item->Select(true);
625 }
626 }
627 dialog->SetItems(&items);
628 dialog->SetMultiSelection(multipleSelection);
629 dialog->DoModal();
630
631 // if the "Get More" button has been pressed and we haven't shown the
632 // installable addons so far show a list of installable addons
633 if (showMore&& dialog->IsButtonPressed())
634 return SelectAddonID(types, addonIDs, showNone, showDetails, multipleSelection, false, true, false);
635
636 if (!dialog->IsConfirmed())
637 return 0;
638
639 addonIDs.clear();
640 const CFileItemList& list = dialog->GetSelectedItems();
641 for (int i = 0 ; i < list.Size() ; i++)
642 {
643 const CFileItemPtr& item = list.Get(i);
644
645 // check if one of the selected addons needs to be installed
646 if (showInstallable)
647 {
648 std::map<std::string, AddonPtr>::const_iterator itAddon = addonMap.find(item->GetPath());
649 if (itAddon != addonMap.end())
650 {
651 const AddonPtr& addon = itAddon->second;
652
653 // if the addon isn't installed we need to install it
654 if (!CAddonMgr::Get().IsAddonInstalled(addon->ID()))
655 {
656 AddonPtr installedAddon;
657 if (!CAddonInstaller::Get().InstallModal(addon->ID(), installedAddon, false))
658 continue;
659 }
660
661 // if the addon is disabled we need to enable it
662 if (CAddonMgr::Get().IsAddonDisabled(addon->ID()))
663 CAddonMgr::Get().DisableAddon(addon->ID(), false);
664 }
665 }
666
667 addonIDs.push_back(item->GetPath());
668 }
669 return 1;
670}
671
672std::string CGUIWindowAddonBrowser::GetStartFolder(const std::string &dir)
673{
674 if (URIUtils::PathStarts(dir, "addons://"))
675 return dir;
676 return CGUIMediaWindow::GetStartFolder(dir);
677}
diff --git a/xbmc/addons/GUIWindowAddonBrowser.h b/xbmc/addons/GUIWindowAddonBrowser.h
new file mode 100644
index 0000000..d7c0ee0
--- /dev/null
+++ b/xbmc/addons/GUIWindowAddonBrowser.h
@@ -0,0 +1,79 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "addons/Addon.h"
24#include "windows/GUIMediaWindow.h"
25#include "ThumbLoader.h"
26
27class CFileItem;
28class CFileItemList;
29
30class CGUIWindowAddonBrowser : public CGUIMediaWindow
31{
32public:
33 CGUIWindowAddonBrowser(void);
34 virtual ~CGUIWindowAddonBrowser(void);
35 virtual bool OnMessage(CGUIMessage& message);
36
37 /*! \brief Popup a selection dialog with a list of addons of the given type
38 \param type the type of addon wanted
39 \param addonID [out] the addon ID of the selected item
40 \param showNone whether there should be a "None" item in the list (defaults to false)
41 \param showDetails whether to show details of the addons or not
42 \param showInstalled whether installed addons should be in the list
43 \param showInstallable whether installable addons should be in the list
44 \param showMore whether to show the "Get More" button (only makes sense if showInstalled is true and showInstallable is false)
45 \return 1 if an addon was selected, 2 if "Get More" was chosen, or 0 if an error occurred or if the selection process was cancelled
46 */
47 static int SelectAddonID(ADDON::TYPE type, std::string &addonID, bool showNone = false, bool showDetails = true, bool showInstalled = true, bool showInstallable = false, bool showMore = true);
48 static int SelectAddonID(const std::vector<ADDON::TYPE> &types, std::string &addonID, bool showNone = false, bool showDetails = true, bool showInstalled = true, bool showInstallable = false, bool showMore = true);
49 /*! \brief Popup a selection dialog with a list of addons of the given type
50 \param type the type of addon wanted
51 \param addonIDs [out] array of selected addon IDs
52 \param showNone whether there should be a "None" item in the list (defaults to false)
53 \param showDetails whether to show details of the addons or not
54 \param multipleSelection allow selection of multiple addons, if set to true showNone will automaticly switch to false
55 \param showInstalled whether installed addons should be in the list
56 \param showInstallable whether installable addons should be in the list
57 \param showMore whether to show the "Get More" button (only makes sense if showInstalled is true and showInstallable is false)
58 \return 1 if an addon was selected or multiple selection was specified, 2 if "Get More" was chosen, or 0 if an error occurred or if the selection process was cancelled
59 */
60 static int SelectAddonID(ADDON::TYPE type, std::vector<std::string> &addonIDs, bool showNone = false, bool showDetails = true, bool multipleSelection = true, bool showInstalled = true, bool showInstallable = false, bool showMore = true);
61 static int SelectAddonID(const std::vector<ADDON::TYPE> &types, std::vector<std::string> &addonIDs, bool showNone = false, bool showDetails = true, bool multipleSelection = true, bool showInstalled = true, bool showInstallable = false, bool showMore = true);
62
63protected:
64 /* \brief set label2 of an item based on the Addon.Status property
65 \param item the item to update
66 */
67 void SetItemLabel2(CFileItemPtr item);
68
69 virtual void GetContextButtons(int itemNumber, CContextButtons &buttons);
70 virtual bool OnContextButton(int itemNumber, CONTEXT_BUTTON button);
71 virtual bool OnClick(int iItem);
72 virtual void UpdateButtons();
73 virtual bool GetDirectory(const std::string &strDirectory, CFileItemList &items);
74 virtual bool Update(const std::string &strDirectory, bool updateFilterPath = true);
75 virtual std::string GetStartFolder(const std::string &dir);
76private:
77 CProgramThumbLoader m_thumbLoader;
78};
79
diff --git a/xbmc/addons/IAddon.h b/xbmc/addons/IAddon.h
new file mode 100644
index 0000000..76f22fa
--- /dev/null
+++ b/xbmc/addons/IAddon.h
@@ -0,0 +1,138 @@
1#pragma once
2/*
3* Copyright (C) 2005-2013 Team XBMC
4* http://xbmc.org
5*
6* This Program is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2, or (at your option)
9* any later version.
10*
11* This Program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with XBMC; see the file COPYING. If not, see
18* <http://www.gnu.org/licenses/>.
19*
20*/
21#include <memory>
22
23#include <map>
24#include <set>
25#include <string>
26#include <stdint.h>
27
28class TiXmlElement;
29
30namespace ADDON
31{
32 typedef enum
33 {
34 ADDON_UNKNOWN,
35 ADDON_VIZ,
36 ADDON_SKIN,
37 ADDON_PVRDLL,
38 ADDON_SCRIPT,
39 ADDON_SCRIPT_WEATHER,
40 ADDON_SUBTITLE_MODULE,
41 ADDON_SCRIPT_LYRICS,
42 ADDON_SCRAPER_ALBUMS,
43 ADDON_SCRAPER_ARTISTS,
44 ADDON_SCRAPER_MOVIES,
45 ADDON_SCRAPER_MUSICVIDEOS,
46 ADDON_SCRAPER_TVSHOWS,
47 ADDON_SCREENSAVER,
48 ADDON_PLUGIN,
49 ADDON_REPOSITORY,
50 ADDON_WEB_INTERFACE,
51 ADDON_SERVICE,
52 ADDON_AUDIOENCODER,
53 ADDON_CONTEXT_ITEM,
54 ADDON_VIDEO, // virtual addon types
55 ADDON_AUDIO,
56 ADDON_IMAGE,
57 ADDON_EXECUTABLE,
58 ADDON_VIZ_LIBRARY,
59 ADDON_SCRAPER_LIBRARY,
60 ADDON_SCRIPT_LIBRARY,
61 ADDON_SCRIPT_MODULE,
62 ADDON_MAX
63 } TYPE;
64
65 class IAddon;
66 typedef std::shared_ptr<IAddon> AddonPtr;
67 class CVisualisation;
68 typedef std::shared_ptr<CVisualisation> VizPtr;
69 class CSkinInfo;
70 typedef std::shared_ptr<CSkinInfo> SkinPtr;
71 class CPluginSource;
72 typedef std::shared_ptr<CPluginSource> PluginPtr;
73
74 class CAddonMgr;
75 class AddonVersion;
76 typedef std::map<std::string, std::pair<const AddonVersion, bool> > ADDONDEPS;
77 typedef std::map<std::string, std::string> InfoMap;
78 class AddonProps;
79
80 class IAddon : public std::enable_shared_from_this<IAddon>
81 {
82 public:
83 virtual ~IAddon() {};
84 virtual AddonPtr Clone() const =0;
85 virtual TYPE Type() const =0;
86 virtual bool IsType(TYPE type) const =0;
87 virtual AddonProps Props() const =0;
88 virtual AddonProps& Props() =0;
89 virtual const std::string ID() const =0;
90 virtual const std::string Name() const =0;
91 virtual bool Enabled() const =0;
92 virtual bool IsInUse() const =0;
93 virtual const AddonVersion Version() const =0;
94 virtual const AddonVersion MinVersion() const =0;
95 virtual const std::string Summary() const =0;
96 virtual const std::string Description() const =0;
97 virtual const std::string Path() const =0;
98 virtual const std::string Profile() const =0;
99 virtual const std::string LibPath() const =0;
100 virtual const std::string ChangeLog() const =0;
101 virtual const std::string FanArt() const =0;
102 virtual const std::string Author() const =0;
103 virtual const std::string Icon() const =0;
104 virtual int Stars() const =0;
105 virtual const std::string Disclaimer() const =0;
106 virtual const InfoMap &ExtraInfo() const =0;
107 virtual bool HasSettings() =0;
108 virtual void SaveSettings() =0;
109 virtual void UpdateSetting(const std::string& key, const std::string& value) =0;
110 virtual std::string GetSetting(const std::string& key) =0;
111 virtual TiXmlElement* GetSettingsXML() =0;
112 virtual std::string GetString(uint32_t id) =0;
113 virtual const ADDONDEPS &GetDeps() const =0;
114 virtual AddonVersion GetDependencyVersion(const std::string &dependencyID) const =0;
115 virtual bool MeetsVersion(const AddonVersion &version) const =0;
116 virtual bool ReloadSettings() =0;
117 virtual void OnDisabled() =0;
118 virtual void OnEnabled() =0;
119 virtual AddonPtr GetRunningInstance() const=0;
120 virtual bool OnPreInstall() =0;
121 virtual void OnPostInstall(bool restart, bool update, bool modal) =0;
122 virtual void OnPreUnInstall() =0;
123 virtual void OnPostUnInstall() =0;
124 virtual bool CanInstall(const std::string& referer) =0;
125
126 protected:
127 virtual bool LoadSettings(bool bForce = false) =0;
128
129 private:
130 friend class CAddonMgr;
131 virtual bool IsAddonLibrary() =0;
132 virtual void Enable() =0;
133 virtual void Disable() =0;
134 virtual bool LoadStrings() =0;
135 virtual void ClearStrings() =0;
136 };
137};
138
diff --git a/xbmc/addons/Makefile b/xbmc/addons/Makefile
new file mode 100644
index 0000000..4cf5b17
--- /dev/null
+++ b/xbmc/addons/Makefile
@@ -0,0 +1,31 @@
1SRCS=Addon.cpp \
2 AddonCallbacks.cpp \
3 AddonCallbacksAddon.cpp \
4 AddonCallbacksCodec.cpp \
5 AddonCallbacksGUI.cpp \
6 AddonCallbacksPVR.cpp \
7 AddonDatabase.cpp \
8 AddonInstaller.cpp \
9 AddonManager.cpp \
10 AddonStatusHandler.cpp \
11 AddonVersion.cpp \
12 AudioEncoder.cpp \
13 ContextItemAddon.cpp \
14 GUIDialogAddonInfo.cpp \
15 GUIDialogAddonSettings.cpp \
16 GUIViewStateAddonBrowser.cpp \
17 GUIWindowAddonBrowser.cpp \
18 PluginSource.cpp \
19 Repository.cpp \
20 Scraper.cpp \
21 ScreenSaver.cpp \
22 Service.cpp \
23 Skin.cpp \
24 Visualisation.cpp \
25 Webinterface.cpp \
26
27LIB=addons.a
28
29include ../../Makefile.include
30-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
31
diff --git a/xbmc/addons/PluginSource.cpp b/xbmc/addons/PluginSource.cpp
new file mode 100644
index 0000000..a5729cf
--- /dev/null
+++ b/xbmc/addons/PluginSource.cpp
@@ -0,0 +1,96 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#include "PluginSource.h"
21#include "AddonManager.h"
22#include "utils/StringUtils.h"
23
24using namespace std;
25
26namespace ADDON
27{
28
29CPluginSource::CPluginSource(const AddonProps &props)
30 : CAddon(props)
31{
32 std::string provides;
33 InfoMap::const_iterator i = Props().extrainfo.find("provides");
34 if (i != Props().extrainfo.end())
35 provides = i->second;
36 SetProvides(provides);
37}
38
39CPluginSource::CPluginSource(const cp_extension_t *ext)
40 : CAddon(ext)
41{
42 std::string provides;
43 if (ext)
44 {
45 provides = CAddonMgr::Get().GetExtValue(ext->configuration, "provides");
46 if (!provides.empty())
47 Props().extrainfo.insert(make_pair("provides", provides));
48 }
49 SetProvides(provides);
50}
51
52AddonPtr CPluginSource::Clone() const
53{
54 return AddonPtr(new CPluginSource(*this));
55}
56
57void CPluginSource::SetProvides(const std::string &content)
58{
59 if (!content.empty())
60 {
61 vector<string> provides = StringUtils::Split(content, ' ');
62 for (vector<string>::const_iterator i = provides.begin(); i != provides.end(); ++i)
63 {
64 Content content = Translate(*i);
65 if (content != UNKNOWN)
66 m_providedContent.insert(content);
67 }
68 }
69 if (Type() == ADDON_SCRIPT && m_providedContent.empty())
70 m_providedContent.insert(EXECUTABLE);
71}
72
73CPluginSource::Content CPluginSource::Translate(const std::string &content)
74{
75 if (content == "audio")
76 return CPluginSource::AUDIO;
77 else if (content == "image")
78 return CPluginSource::IMAGE;
79 else if (content == "executable")
80 return CPluginSource::EXECUTABLE;
81 else if (content == "video")
82 return CPluginSource::VIDEO;
83 else
84 return CPluginSource::UNKNOWN;
85}
86
87bool CPluginSource::IsType(TYPE type) const
88{
89 return ((type == ADDON_VIDEO && Provides(VIDEO))
90 || (type == ADDON_AUDIO && Provides(AUDIO))
91 || (type == ADDON_IMAGE && Provides(IMAGE))
92 || (type == ADDON_EXECUTABLE && Provides(EXECUTABLE)));
93}
94
95} /*namespace ADDON*/
96
diff --git a/xbmc/addons/PluginSource.h b/xbmc/addons/PluginSource.h
new file mode 100644
index 0000000..87e1f34
--- /dev/null
+++ b/xbmc/addons/PluginSource.h
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#pragma once
21
22#include "Addon.h"
23
24namespace ADDON
25{
26
27class CPluginSource : public CAddon
28{
29public:
30
31 enum Content { UNKNOWN, AUDIO, IMAGE, EXECUTABLE, VIDEO };
32
33 CPluginSource(const cp_extension_t *ext);
34 CPluginSource(const AddonProps &props);
35 virtual ~CPluginSource() {}
36 virtual AddonPtr Clone() const;
37 virtual bool IsType(TYPE type) const;
38 bool Provides(const Content& content) const
39 {
40 return content == UNKNOWN ? false : m_providedContent.count(content) > 0;
41 }
42
43 bool ProvidesSeveral() const
44 {
45 return m_providedContent.size() > 1;
46 }
47
48 static Content Translate(const std::string &content);
49private:
50 /*! \brief Set the provided content for this plugin
51 If no valid content types are passed in, we set the EXECUTABLE type
52 \param content a space-separated list of content types
53 */
54 void SetProvides(const std::string &content);
55 std::set<Content> m_providedContent;
56};
57
58} /*namespace ADDON*/
diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp
new file mode 100644
index 0000000..e65a195
--- /dev/null
+++ b/xbmc/addons/Repository.cpp
@@ -0,0 +1,395 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Repository.h"
22#include "addons/AddonDatabase.h"
23#include "addons/AddonInstaller.h"
24#include "addons/AddonManager.h"
25#include "dialogs/GUIDialogYesNo.h"
26#include "dialogs/GUIDialogKaiToast.h"
27#include "filesystem/File.h"
28#include "filesystem/PluginDirectory.h"
29#include "settings/Settings.h"
30#include "utils/log.h"
31#include "utils/JobManager.h"
32#include "utils/StringUtils.h"
33#include "utils/URIUtils.h"
34#include "utils/XBMCTinyXML.h"
35#include "FileItem.h"
36#include "TextureDatabase.h"
37#include "URL.h"
38
39using namespace std;
40using namespace XFILE;
41using namespace ADDON;
42
43AddonPtr CRepository::Clone() const
44{
45 return AddonPtr(new CRepository(*this));
46}
47
48CRepository::CRepository(const AddonProps& props) :
49 CAddon(props)
50{
51}
52
53CRepository::CRepository(const cp_extension_t *ext)
54 : CAddon(ext)
55{
56 // read in the other props that we need
57 if (ext)
58 {
59 AddonVersion version("0.0.0");
60 AddonPtr addonver;
61 if (CAddonMgr::Get().GetAddon("xbmc.addon", addonver))
62 version = addonver->Version();
63 for (size_t i = 0; i < ext->configuration->num_children; ++i)
64 {
65 if(ext->configuration->children[i].name &&
66 strcmp(ext->configuration->children[i].name, "dir") == 0)
67 {
68 AddonVersion min_version(CAddonMgr::Get().GetExtValue(&ext->configuration->children[i], "@minversion"));
69 if (min_version <= version)
70 {
71 DirInfo dir;
72 dir.version = min_version;
73 dir.checksum = CAddonMgr::Get().GetExtValue(&ext->configuration->children[i], "checksum");
74 dir.compressed = CAddonMgr::Get().GetExtValue(&ext->configuration->children[i], "info@compressed") == "true";
75 dir.info = CAddonMgr::Get().GetExtValue(&ext->configuration->children[i], "info");
76 dir.datadir = CAddonMgr::Get().GetExtValue(&ext->configuration->children[i], "datadir");
77 dir.zipped = CAddonMgr::Get().GetExtValue(&ext->configuration->children[i], "datadir@zip") == "true";
78 dir.hashes = CAddonMgr::Get().GetExtValue(&ext->configuration->children[i], "hashes") == "true";
79 m_dirs.push_back(dir);
80 }
81 }
82 }
83 // backward compatibility
84 if (!CAddonMgr::Get().GetExtValue(ext->configuration, "info").empty())
85 {
86 DirInfo info;
87 info.checksum = CAddonMgr::Get().GetExtValue(ext->configuration, "checksum");
88 info.compressed = CAddonMgr::Get().GetExtValue(ext->configuration, "info@compressed") == "true";
89 info.info = CAddonMgr::Get().GetExtValue(ext->configuration, "info");
90 info.datadir = CAddonMgr::Get().GetExtValue(ext->configuration, "datadir");
91 info.zipped = CAddonMgr::Get().GetExtValue(ext->configuration, "datadir@zip") == "true";
92 info.hashes = CAddonMgr::Get().GetExtValue(ext->configuration, "hashes") == "true";
93 m_dirs.push_back(info);
94 }
95 }
96}
97
98CRepository::CRepository(const CRepository &rhs)
99 : CAddon(rhs), m_dirs(rhs.m_dirs)
100{
101}
102
103CRepository::~CRepository()
104{
105}
106
107string CRepository::FetchChecksum(const string& url)
108{
109 CFile file;
110 try
111 {
112 if (file.Open(url))
113 {
114 // we intentionally avoid using file.GetLength() for
115 // Transfer-Encoding: chunked servers.
116 std::stringstream str;
117 char temp[1024];
118 int read;
119 while ((read=file.Read(temp, sizeof(temp))) > 0)
120 str.write(temp, read);
121 return str.str();
122 }
123 return "";
124 }
125 catch (...)
126 {
127 return "";
128 }
129}
130
131string CRepository::GetAddonHash(const AddonPtr& addon) const
132{
133 string checksum;
134 DirList::const_iterator it;
135 for (it = m_dirs.begin();it != m_dirs.end(); ++it)
136 if (URIUtils::IsInPath(addon->Path(), it->datadir))
137 break;
138 if (it != m_dirs.end() && it->hashes)
139 {
140 checksum = FetchChecksum(addon->Path()+".md5");
141 size_t pos = checksum.find_first_of(" \n");
142 if (pos != string::npos)
143 return checksum.substr(0, pos);
144 }
145 return checksum;
146}
147
148#define SET_IF_NOT_EMPTY(x,y) \
149 { \
150 if (!x.empty()) \
151 x = y; \
152 }
153
154bool CRepository::Parse(const DirInfo& dir, VECADDONS &result)
155{
156 string file = dir.info;
157 if (dir.compressed)
158 {
159 CURL url(dir.info);
160 string opts = url.GetProtocolOptions();
161 if (!opts.empty())
162 opts += "&";
163 url.SetProtocolOptions(opts+"Encoding=gzip");
164 file = url.Get();
165 }
166
167 CXBMCTinyXML doc;
168 if (doc.LoadFile(file) && doc.RootElement() &&
169 CAddonMgr::Get().AddonsFromRepoXML(doc.RootElement(), result))
170 {
171 for (IVECADDONS i = result.begin(); i != result.end(); ++i)
172 {
173 AddonPtr addon = *i;
174 if (dir.zipped)
175 {
176 string file = StringUtils::Format("%s/%s-%s.zip", addon->ID().c_str(), addon->ID().c_str(), addon->Version().asString().c_str());
177 addon->Props().path = URIUtils::AddFileToFolder(dir.datadir,file);
178 SET_IF_NOT_EMPTY(addon->Props().icon,URIUtils::AddFileToFolder(dir.datadir,addon->ID()+"/icon.png"))
179 file = StringUtils::Format("%s/changelog-%s.txt", addon->ID().c_str(), addon->Version().asString().c_str());
180 SET_IF_NOT_EMPTY(addon->Props().changelog,URIUtils::AddFileToFolder(dir.datadir,file))
181 SET_IF_NOT_EMPTY(addon->Props().fanart,URIUtils::AddFileToFolder(dir.datadir,addon->ID()+"/fanart.jpg"))
182 }
183 else
184 {
185 addon->Props().path = URIUtils::AddFileToFolder(dir.datadir,addon->ID()+"/");
186 SET_IF_NOT_EMPTY(addon->Props().icon,URIUtils::AddFileToFolder(dir.datadir,addon->ID()+"/icon.png"))
187 SET_IF_NOT_EMPTY(addon->Props().changelog,URIUtils::AddFileToFolder(dir.datadir,addon->ID()+"/changelog.txt"))
188 SET_IF_NOT_EMPTY(addon->Props().fanart,URIUtils::AddFileToFolder(dir.datadir,addon->ID()+"/fanart.jpg"))
189 }
190 }
191 return true;
192 }
193 return false;
194}
195
196void CRepository::OnPostInstall(bool restart, bool update, bool modal)
197{
198 VECADDONS addons;
199 AddonPtr repo(new CRepository(*this));
200 addons.push_back(repo);
201 CJobManager::GetInstance().AddJob(new CRepositoryUpdateJob(addons), &CAddonInstaller::Get());
202}
203
204void CRepository::OnPostUnInstall()
205{
206 CAddonDatabase database;
207 database.Open();
208 database.DeleteRepository(ID());
209}
210
211CRepositoryUpdateJob::CRepositoryUpdateJob(const VECADDONS &repos)
212 : m_repos(repos)
213{
214}
215
216void MergeAddons(map<string, AddonPtr> &addons, const VECADDONS &new_addons)
217{
218 for (VECADDONS::const_iterator it = new_addons.begin(); it != new_addons.end(); ++it)
219 {
220 map<string, AddonPtr>::iterator existing = addons.find((*it)->ID());
221 if (existing != addons.end())
222 { // already got it - replace if we have a newer version
223 if (existing->second->Version() < (*it)->Version())
224 existing->second = *it;
225 }
226 else
227 addons.insert(make_pair((*it)->ID(), *it));
228 }
229}
230
231bool CRepositoryUpdateJob::DoWork()
232{
233 map<string, AddonPtr> addons;
234 for (VECADDONS::const_iterator i = m_repos.begin(); i != m_repos.end(); ++i)
235 {
236 if (ShouldCancel(0, 0))
237 return false;
238 const RepositoryPtr repo = std::dynamic_pointer_cast<CRepository>(*i);
239 VECADDONS newAddons;
240 if (GrabAddons(repo, newAddons))
241 MergeAddons(addons, newAddons);
242 }
243 if (addons.empty())
244 return true; //Nothing to do
245
246 // check for updates
247 CAddonDatabase database;
248 database.Open();
249 database.BeginMultipleExecute();
250
251 CTextureDatabase textureDB;
252 textureDB.Open();
253 textureDB.BeginMultipleExecute();
254 VECADDONS notifications;
255 for (map<string, AddonPtr>::const_iterator i = addons.begin(); i != addons.end(); ++i)
256 {
257 // manager told us to feck off
258 if (ShouldCancel(0,0))
259 break;
260
261 AddonPtr newAddon = i->second;
262 bool deps_met = CAddonInstaller::Get().CheckDependencies(newAddon, &database);
263 if (!deps_met && newAddon->Props().broken.empty())
264 newAddon->Props().broken = "DEPSNOTMET";
265
266 // invalidate the art associated with this item
267 if (!newAddon->Props().fanart.empty())
268 textureDB.InvalidateCachedTexture(newAddon->Props().fanart);
269 if (!newAddon->Props().icon.empty())
270 textureDB.InvalidateCachedTexture(newAddon->Props().icon);
271
272 AddonPtr addon;
273 CAddonMgr::Get().GetAddon(newAddon->ID(),addon);
274 if (addon && newAddon->Version() > addon->Version() &&
275 !database.IsAddonBlacklisted(newAddon->ID(),newAddon->Version().asString()) &&
276 deps_met)
277 {
278 if (CSettings::Get().GetInt("general.addonupdates") == AUTO_UPDATES_ON)
279 {
280 string referer;
281 if (URIUtils::IsInternetStream(newAddon->Path()))
282 referer = StringUtils::Format("Referer=%s-%s.zip",addon->ID().c_str(),addon->Version().asString().c_str());
283
284 if (newAddon->CanInstall(referer))
285 CAddonInstaller::Get().Install(addon->ID(), true, referer);
286 }
287 else
288 notifications.push_back(addon);
289 }
290
291 // Check if we should mark the add-on as broken. We may have a newer version
292 // of this add-on in the database or installed - if so, we keep it unbroken.
293 bool haveNewer = (addon && addon->Version() > newAddon->Version()) ||
294 database.GetAddonVersion(newAddon->ID()) > newAddon->Version();
295 if (!haveNewer)
296 {
297 if (!newAddon->Props().broken.empty())
298 {
299 if (database.IsAddonBroken(newAddon->ID()).empty())
300 {
301 std::string line = g_localizeStrings.Get(24096);
302 if (newAddon->Props().broken == "DEPSNOTMET")
303 line = g_localizeStrings.Get(24104);
304 if (addon && CGUIDialogYesNo::ShowAndGetInput(newAddon->Name(),
305 line,
306 g_localizeStrings.Get(24097),
307 ""))
308 CAddonMgr::Get().DisableAddon(newAddon->ID());
309 }
310 }
311 database.BreakAddon(newAddon->ID(), newAddon->Props().broken);
312 }
313 }
314 database.CommitMultipleExecute();
315 textureDB.CommitMultipleExecute();
316 if (!notifications.empty() && CSettings::Get().GetBool("general.addonnotifications"))
317 {
318 if (notifications.size() == 1)
319 CGUIDialogKaiToast::QueueNotification(notifications[0]->Icon(),
320 g_localizeStrings.Get(24061),
321 notifications[0]->Name(),TOAST_DISPLAY_TIME,false,TOAST_DISPLAY_TIME);
322 else
323 CGUIDialogKaiToast::QueueNotification("",
324 g_localizeStrings.Get(24001),
325 g_localizeStrings.Get(24061),TOAST_DISPLAY_TIME,false,TOAST_DISPLAY_TIME);
326 }
327
328 return true;
329}
330
331bool CRepositoryUpdateJob::GrabAddons(const RepositoryPtr& repo, VECADDONS& addons)
332{
333 CAddonDatabase database;
334 database.Open();
335 string oldReposum;
336 if (!database.GetRepoChecksum(repo->ID(), oldReposum))
337 oldReposum = "";
338
339 string reposum;
340 for (CRepository::DirList::const_iterator it = repo->m_dirs.begin(); it != repo->m_dirs.end(); ++it)
341 {
342 if (ShouldCancel(0, 0))
343 return false;
344 if (!it->checksum.empty())
345 {
346 const string dirsum = CRepository::FetchChecksum(it->checksum);
347 if (dirsum.empty())
348 {
349 CLog::Log(LOGERROR, "Failed to fetch checksum for directory listing %s for repository %s. ", (*it).info.c_str(), repo->ID().c_str());
350 return false;
351 }
352 reposum += dirsum;
353 }
354 }
355
356 if (oldReposum != reposum || oldReposum.empty())
357 {
358 map<string, AddonPtr> uniqueAddons;
359 for (CRepository::DirList::const_iterator it = repo->m_dirs.begin(); it != repo->m_dirs.end(); ++it)
360 {
361 if (ShouldCancel(0, 0))
362 return false;
363 VECADDONS addons;
364 if (!CRepository::Parse(*it, addons))
365 { //TODO: Hash is invalid and should not be saved, but should we fail?
366 //We can still report a partial addon listing.
367 CLog::Log(LOGERROR, "Failed to read directory listing %s for repository %s. ", (*it).info.c_str(), repo->ID().c_str());
368 return false;
369 }
370 MergeAddons(uniqueAddons, addons);
371 }
372
373 bool add = true;
374 if (!repo->Props().libname.empty())
375 {
376 CFileItemList dummy;
377 string s = StringUtils::Format("plugin://%s/?action=update", repo->ID().c_str());
378 add = CDirectory::GetDirectory(s, dummy);
379 }
380 if (add)
381 {
382 for (map<string, AddonPtr>::const_iterator i = uniqueAddons.begin(); i != uniqueAddons.end(); ++i)
383 addons.push_back(i->second);
384 database.AddRepository(repo->ID(), addons, reposum, repo->Version());
385 }
386 }
387 else
388 {
389 CLog::Log(LOGDEBUG, "Checksum for repository %s not changed.", repo->ID().c_str());
390 database.GetRepository(repo->ID(), addons);
391 database.SetRepoTimestamp(repo->ID(), CDateTime::GetCurrentDateTime().GetAsDBDateTime(), repo->Version());
392 }
393 return true;
394}
395
diff --git a/xbmc/addons/Repository.h b/xbmc/addons/Repository.h
new file mode 100644
index 0000000..5120c38
--- /dev/null
+++ b/xbmc/addons/Repository.h
@@ -0,0 +1,82 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "Addon.h"
23#include "utils/Job.h"
24
25namespace ADDON
26{
27 class CRepository;
28 typedef std::shared_ptr<CRepository> RepositoryPtr;
29 class CRepository : public CAddon
30 {
31 public:
32 virtual AddonPtr Clone() const;
33 CRepository(const AddonProps& props);
34 CRepository(const cp_extension_t *props);
35 virtual ~CRepository();
36
37 /*! \brief Get the md5 hash for an addon.
38 \param the addon in question.
39 \return the md5 hash for the given addon, empty if non exists.
40 */
41 std::string GetAddonHash(const AddonPtr& addon) const;
42
43 struct DirInfo
44 {
45 DirInfo() : version("0.0.0"), compressed(false), zipped(false), hashes(false) {}
46 AddonVersion version;
47 std::string info;
48 std::string checksum;
49 std::string datadir;
50 bool compressed;
51 bool zipped;
52 bool hashes;
53 };
54
55 typedef std::vector<DirInfo> DirList;
56 DirList m_dirs;
57
58 static bool Parse(const DirInfo& dir, VECADDONS& addons);
59 static std::string FetchChecksum(const std::string& url);
60
61 virtual void OnPostInstall(bool restart, bool update, bool modal);
62 virtual void OnPostUnInstall();
63
64 private:
65 CRepository(const CRepository &rhs);
66 };
67
68 class CRepositoryUpdateJob : public CJob
69 {
70 public:
71 CRepositoryUpdateJob(const VECADDONS& repos);
72 virtual ~CRepositoryUpdateJob() {}
73
74 virtual const char *GetType() const { return "repoupdate"; };
75 virtual bool DoWork();
76 private:
77 bool GrabAddons(const RepositoryPtr& repo, VECADDONS& addons);
78
79 VECADDONS m_repos;
80 };
81}
82
diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp
new file mode 100644
index 0000000..06f34f2
--- /dev/null
+++ b/xbmc/addons/Scraper.cpp
@@ -0,0 +1,1033 @@
1/*
2* Copyright (C) 2005-2013 Team XBMC
3* http://xbmc.org
4*
5* This Program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation; either version 2, or (at your option)
8* any later version.
9*
10* This Program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with XBMC; see the file COPYING. If not, see
17* <http://www.gnu.org/licenses/>.
18*
19*/
20#include "Scraper.h"
21#include "filesystem/File.h"
22#include "filesystem/Directory.h"
23#include "filesystem/CurlFile.h"
24#include "AddonManager.h"
25#include "utils/ScraperParser.h"
26#include "utils/ScraperUrl.h"
27#include "utils/CharsetConverter.h"
28#include "utils/log.h"
29#include "music/infoscanner/MusicAlbumInfo.h"
30#include "music/infoscanner/MusicArtistInfo.h"
31#include "utils/fstrcmp.h"
32#include "settings/AdvancedSettings.h"
33#include "FileItem.h"
34#include "utils/URIUtils.h"
35#include "utils/XMLUtils.h"
36#include "utils/StringUtils.h"
37#include "music/MusicDatabase.h"
38#include "video/VideoDatabase.h"
39#include "music/Album.h"
40#include "music/Artist.h"
41#include "Util.h"
42#include "URL.h"
43
44#include <sstream>
45#include <algorithm>
46
47using namespace std;
48using namespace XFILE;
49using namespace MUSIC_GRABBER;
50using namespace VIDEO;
51
52namespace ADDON
53{
54
55typedef struct
56{
57 const char* name;
58 CONTENT_TYPE type;
59 int pretty;
60} ContentMapping;
61
62static const ContentMapping content[] =
63 {{"unknown", CONTENT_NONE, 231 },
64 {"albums", CONTENT_ALBUMS, 132 },
65 {"music", CONTENT_ALBUMS, 132 },
66 {"artists", CONTENT_ARTISTS, 133 },
67 {"movies", CONTENT_MOVIES, 20342 },
68 {"tvshows", CONTENT_TVSHOWS, 20343 },
69 {"musicvideos", CONTENT_MUSICVIDEOS, 20389 }};
70
71std::string TranslateContent(const CONTENT_TYPE &type, bool pretty/*=false*/)
72{
73 for (unsigned int index=0; index < ARRAY_SIZE(content); ++index)
74 {
75 const ContentMapping &map = content[index];
76 if (type == map.type)
77 {
78 if (pretty && map.pretty)
79 return g_localizeStrings.Get(map.pretty);
80 else
81 return map.name;
82 }
83 }
84 return "";
85}
86
87CONTENT_TYPE TranslateContent(const std::string &string)
88{
89 for (unsigned int index=0; index < ARRAY_SIZE(content); ++index)
90 {
91 const ContentMapping &map = content[index];
92 if (string == map.name)
93 return map.type;
94 }
95 return CONTENT_NONE;
96}
97
98TYPE ScraperTypeFromContent(const CONTENT_TYPE &content)
99{
100 switch (content)
101 {
102 case CONTENT_ALBUMS:
103 return ADDON_SCRAPER_ALBUMS;
104 case CONTENT_ARTISTS:
105 return ADDON_SCRAPER_ARTISTS;
106 case CONTENT_MOVIES:
107 return ADDON_SCRAPER_MOVIES;
108 case CONTENT_MUSICVIDEOS:
109 return ADDON_SCRAPER_MUSICVIDEOS;
110 case CONTENT_TVSHOWS:
111 return ADDON_SCRAPER_TVSHOWS;
112 default:
113 return ADDON_UNKNOWN;
114 }
115}
116
117// if the XML root is <error>, throw CScraperError with enclosed <title>/<message> values
118static void CheckScraperError(const TiXmlElement *pxeRoot)
119{
120 if (!pxeRoot || stricmp(pxeRoot->Value(), "error"))
121 return;
122 std::string sTitle;
123 std::string sMessage;
124 XMLUtils::GetString(pxeRoot, "title", sTitle);
125 XMLUtils::GetString(pxeRoot, "message", sMessage);
126 throw CScraperError(sTitle, sMessage);
127}
128
129CScraper::CScraper(const cp_extension_t *ext) : CAddon(ext), m_fLoaded(false)
130{
131 if (ext)
132 {
133 m_language = CAddonMgr::Get().GetExtValue(ext->configuration, "@language");
134 m_requiressettings = CAddonMgr::Get().GetExtValue(ext->configuration,"@requiressettings") == "true";
135 std::string persistence = CAddonMgr::Get().GetExtValue(ext->configuration, "@cachepersistence");
136 if (!persistence.empty())
137 m_persistence.SetFromTimeString(persistence);
138 }
139 switch (Type())
140 {
141 case ADDON_SCRAPER_ALBUMS:
142 m_pathContent = CONTENT_ALBUMS;
143 break;
144 case ADDON_SCRAPER_ARTISTS:
145 m_pathContent = CONTENT_ARTISTS;
146 break;
147 case ADDON_SCRAPER_MOVIES:
148 m_pathContent = CONTENT_MOVIES;
149 break;
150 case ADDON_SCRAPER_MUSICVIDEOS:
151 m_pathContent = CONTENT_MUSICVIDEOS;
152 break;
153 case ADDON_SCRAPER_TVSHOWS:
154 m_pathContent = CONTENT_TVSHOWS;
155 break;
156 default:
157 m_pathContent = CONTENT_NONE;
158 break;
159 }
160}
161
162AddonPtr CScraper::Clone() const
163{
164 return AddonPtr(new CScraper(*this));
165}
166
167CScraper::CScraper(const CScraper &rhs)
168 : CAddon(rhs), m_fLoaded(false),
169 m_language(rhs.m_language),
170 m_requiressettings(rhs.m_requiressettings),
171 m_persistence(rhs.m_persistence),
172 m_pathContent(rhs.m_pathContent)
173{
174}
175
176bool CScraper::Supports(const CONTENT_TYPE &content) const
177{
178 return Type() == ScraperTypeFromContent(content);
179}
180
181bool CScraper::SetPathSettings(CONTENT_TYPE content, const std::string& xml)
182{
183 m_pathContent = content;
184 if (!LoadSettings())
185 return false;
186
187 if (xml.empty())
188 return true;
189
190 CXBMCTinyXML doc;
191 doc.Parse(xml);
192 m_userSettingsLoaded = SettingsFromXML(doc);
193
194 return m_userSettingsLoaded;
195}
196
197std::string CScraper::GetPathSettings()
198{
199 if (!LoadSettings())
200 return "";
201
202 stringstream stream;
203 CXBMCTinyXML doc;
204 SettingsToXML(doc);
205 if (doc.RootElement())
206 stream << *doc.RootElement();
207
208 return stream.str();
209}
210
211void CScraper::ClearCache()
212{
213 std::string strCachePath = URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath, "scrapers");
214
215 // create scraper cache dir if needed
216 if (!CDirectory::Exists(strCachePath))
217 CDirectory::Create(strCachePath);
218
219 strCachePath = URIUtils::AddFileToFolder(strCachePath, ID());
220 URIUtils::AddSlashAtEnd(strCachePath);
221
222 if (CDirectory::Exists(strCachePath))
223 {
224 CFileItemList items;
225 CDirectory::GetDirectory(strCachePath,items);
226 for (int i=0;i<items.Size();++i)
227 {
228 // wipe cache
229 if (items[i]->m_dateTime + m_persistence <= CDateTime::GetCurrentDateTime())
230 CFile::Delete(items[i]->GetPath());
231 }
232 }
233 else
234 CDirectory::Create(strCachePath);
235}
236
237// returns a vector of strings: the first is the XML output by the function; the rest
238// is XML output by chained functions, possibly recursively
239// the CCurlFile object is passed in so that URL fetches can be canceled from other threads
240// throws CScraperError abort on internal failures (e.g., parse errors)
241vector<string> CScraper::Run(const std::string& function,
242 const CScraperUrl& scrURL,
243 CCurlFile& http,
244 const vector<string>* extras)
245{
246 if (!Load())
247 throw CScraperError();
248
249 std::string strXML = InternalRun(function,scrURL,http,extras);
250 if (strXML.empty())
251 {
252 if (function != "NfoUrl" && function != "ResolveIDToUrl")
253 CLog::Log(LOGERROR, "%s: Unable to parse web site",__FUNCTION__);
254 throw CScraperError();
255 }
256
257 CLog::Log(LOGDEBUG,"scraper: %s returned %s",function.c_str(),strXML.c_str());
258
259 CXBMCTinyXML doc;
260 /* all data was converted to UTF-8 before being processed by scraper */
261 doc.Parse(strXML, TIXML_ENCODING_UTF8);
262 if (!doc.RootElement())
263 {
264 CLog::Log(LOGERROR, "%s: Unable to parse XML",__FUNCTION__);
265 throw CScraperError();
266 }
267
268 vector<string> result;
269 result.push_back(strXML);
270 TiXmlElement* xchain = doc.RootElement()->FirstChildElement();
271 // skip children of the root element until <url> or <chain>
272 while (xchain && strcmp(xchain->Value(),"url") && strcmp(xchain->Value(),"chain"))
273 xchain = xchain->NextSiblingElement();
274 while (xchain)
275 {
276 // <chain|url function="...">param</>
277 const char* szFunction = xchain->Attribute("function");
278 if (szFunction)
279 {
280 CScraperUrl scrURL2;
281 vector<string> extras;
282 // for <chain>, pass the contained text as a parameter; for <url>, as URL content
283 if (strcmp(xchain->Value(),"chain")==0)
284 {
285 if (xchain->FirstChild())
286 extras.push_back(xchain->FirstChild()->Value());
287 }
288 else
289 scrURL2.ParseElement(xchain);
290 // Fix for empty chains. $$1 would still contain the
291 // previous value as there is no child of the xml node.
292 // since $$1 will always either contain the data from an
293 // url or the parameters to a chain, we can safely clear it here
294 // to fix this issue
295 m_parser.m_param[0].clear();
296 vector<string> result2 = RunNoThrow(szFunction,scrURL2,http,&extras);
297 result.insert(result.end(),result2.begin(),result2.end());
298 }
299 xchain = xchain->NextSiblingElement();
300 // continue to skip past non-<url> or <chain> elements
301 while (xchain && strcmp(xchain->Value(),"url") && strcmp(xchain->Value(),"chain"))
302 xchain = xchain->NextSiblingElement();
303 }
304
305 return result;
306}
307
308// just like Run, but returns an empty list instead of throwing in case of error
309// don't use in new code; errors should be handled appropriately
310vector<string> CScraper::RunNoThrow(const std::string& function,
311 const CScraperUrl& url,
312 XFILE::CCurlFile& http,
313 const vector<string>* extras)
314{
315 vector<string> vcs;
316 try
317 {
318 vcs = Run(function, url, http, extras);
319 }
320 catch (const CScraperError &sce)
321 {
322 assert(sce.FAborted()); // the only kind we should get
323 }
324 return vcs;
325}
326
327std::string CScraper::InternalRun(const std::string& function,
328 const CScraperUrl& scrURL,
329 CCurlFile& http,
330 const vector<string>* extras)
331{
332 // walk the list of input URLs and fetch each into parser parameters
333 unsigned int i;
334 for (i=0;i<scrURL.m_url.size();++i)
335 {
336 if (!CScraperUrl::Get(scrURL.m_url[i],m_parser.m_param[i],http,ID()) || m_parser.m_param[i].size() == 0)
337 return "";
338 }
339 // put the 'extra' parameterts into the parser parameter list too
340 if (extras)
341 {
342 for (unsigned int j=0;j<extras->size();++j)
343 m_parser.m_param[j+i] = (*extras)[j];
344 }
345
346 return m_parser.Parse(function,this);
347}
348
349bool CScraper::Load()
350{
351 if (m_fLoaded)
352 return true;
353
354 bool result=m_parser.Load(LibPath());
355 if (result)
356 {
357 // TODO: this routine assumes that deps are a single level, and assumes the dep is installed.
358 // 1. Does it make sense to have recursive dependencies?
359 // 2. Should we be checking the dep versions or do we assume it is ok?
360 ADDONDEPS deps = GetDeps();
361 ADDONDEPS::iterator itr = deps.begin();
362 while (itr != deps.end())
363 {
364 if (itr->first == "xbmc.metadata")
365 {
366 ++itr;
367 continue;
368 }
369 AddonPtr dep;
370
371 bool bOptional = itr->second.second;
372
373 if (CAddonMgr::Get().GetAddon((*itr).first, dep))
374 {
375 CXBMCTinyXML doc;
376 if (dep->Type() == ADDON_SCRAPER_LIBRARY && doc.LoadFile(dep->LibPath()))
377 m_parser.AddDocument(&doc);
378 }
379 else
380 {
381 if (!bOptional)
382 {
383 result = false;
384 break;
385 }
386 }
387 ++itr;
388 }
389 }
390
391 if (!result)
392 CLog::Log(LOGWARNING, "failed to load scraper XML from %s", LibPath().c_str());
393 return m_fLoaded = result;
394}
395
396bool CScraper::IsInUse() const
397{
398 if (Supports(CONTENT_ALBUMS) || Supports(CONTENT_ARTISTS))
399 { // music scraper
400 CMusicDatabase db;
401 if (db.Open() && db.ScraperInUse(ID()))
402 return true;
403 }
404 else
405 { // video scraper
406 CVideoDatabase db;
407 if (db.Open() && db.ScraperInUse(ID()))
408 return true;
409 }
410 return false;
411}
412
413bool CScraper::IsNoop()
414{
415 if (!Load())
416 throw CScraperError();
417
418 return m_parser.IsNoop();
419}
420
421// pass in contents of .nfo file; returns URL (possibly empty if none found)
422// and may populate strId, or throws CScraperError on error
423CScraperUrl CScraper::NfoUrl(const std::string &sNfoContent)
424{
425 CScraperUrl scurlRet;
426
427 if (IsNoop())
428 return scurlRet;
429
430 // scraper function takes contents of .nfo file, returns XML (see below)
431 vector<string> vcsIn;
432 vcsIn.push_back(sNfoContent);
433 CScraperUrl scurl;
434 CCurlFile fcurl;
435 vector<string> vcsOut = Run("NfoUrl", scurl, fcurl, &vcsIn);
436 if (vcsOut.empty() || vcsOut[0].empty())
437 return scurlRet;
438 if (vcsOut.size() > 1)
439 CLog::Log(LOGWARNING, "%s: scraper returned multiple results; using first", __FUNCTION__);
440
441 // parse returned XML: either <error> element on error, blank on failure,
442 // or <url>...</url> or <url>...</url><id>...</id> on success
443 for (unsigned int i=0; i < vcsOut.size(); ++i)
444 {
445 CXBMCTinyXML doc;
446 doc.Parse(vcsOut[i], TIXML_ENCODING_UTF8);
447 CheckScraperError(doc.RootElement());
448
449 if (doc.RootElement())
450 {
451 /*
452 NOTE: Scrapers might return invalid xml with some loose
453 elements (eg. '<url>http://some.url</url><id>123</id>').
454 Since XMLUtils::GetString() is assuming well formed xml
455 with start and end-tags we're not able to use it.
456 Check for the desired Elements instead.
457 */
458 TiXmlElement* pxeUrl=NULL;
459 TiXmlElement* pId=NULL;
460 if (!strcmp(doc.RootElement()->Value(),"details"))
461 {
462 pxeUrl = doc.RootElement()->FirstChildElement("url");
463 pId = doc.RootElement()->FirstChildElement("id");
464 }
465 else
466 {
467 pId = doc.FirstChildElement("id");
468 pxeUrl = doc.FirstChildElement("url");
469 }
470 if (pId && pId->FirstChild())
471 scurlRet.strId = pId->FirstChild()->Value();
472
473 if (pxeUrl && pxeUrl->Attribute("function"))
474 continue;
475
476 if (pxeUrl)
477 scurlRet.ParseElement(pxeUrl);
478 else if (!strcmp(doc.RootElement()->Value(), "url"))
479 scurlRet.ParseElement(doc.RootElement());
480 else
481 continue;
482 break;
483 }
484 }
485 return scurlRet;
486}
487
488CScraperUrl CScraper::ResolveIDToUrl(const std::string& externalID)
489{
490 CScraperUrl scurlRet;
491
492 // scraper function takes an external ID, returns XML (see below)
493 vector<string> vcsIn;
494 vcsIn.push_back(externalID);
495 CScraperUrl scurl;
496 CCurlFile fcurl;
497 vector<string> vcsOut = Run("ResolveIDToUrl", scurl, fcurl, &vcsIn);
498 if (vcsOut.empty() || vcsOut[0].empty())
499 return scurlRet;
500 if (vcsOut.size() > 1)
501 CLog::Log(LOGWARNING, "%s: scraper returned multiple results; using first", __FUNCTION__);
502
503 // parse returned XML: either <error> element on error, blank on failure,
504 // or <url>...</url> or <url>...</url><id>...</id> on success
505 for (unsigned int i=0; i < vcsOut.size(); ++i)
506 {
507 CXBMCTinyXML doc;
508 doc.Parse(vcsOut[i], TIXML_ENCODING_UTF8);
509 CheckScraperError(doc.RootElement());
510
511 if (doc.RootElement())
512 {
513 /*
514 NOTE: Scrapers might return invalid xml with some loose
515 elements (eg. '<url>http://some.url</url><id>123</id>').
516 Since XMLUtils::GetString() is assuming well formed xml
517 with start and end-tags we're not able to use it.
518 Check for the desired Elements instead.
519 */
520 TiXmlElement* pxeUrl=NULL;
521 TiXmlElement* pId=NULL;
522 if (!strcmp(doc.RootElement()->Value(),"details"))
523 {
524 pxeUrl = doc.RootElement()->FirstChildElement("url");
525 pId = doc.RootElement()->FirstChildElement("id");
526 }
527 else
528 {
529 pId = doc.FirstChildElement("id");
530 pxeUrl = doc.FirstChildElement("url");
531 }
532 if (pId && pId->FirstChild())
533 scurlRet.strId = pId->FirstChild()->Value();
534
535 if (pxeUrl && pxeUrl->Attribute("function"))
536 continue;
537
538 if (pxeUrl)
539 scurlRet.ParseElement(pxeUrl);
540 else if (!strcmp(doc.RootElement()->Value(), "url"))
541 scurlRet.ParseElement(doc.RootElement());
542 else
543 continue;
544 break;
545 }
546 }
547 return scurlRet;
548}
549
550static bool RelevanceSortFunction(const CScraperUrl &left, const CScraperUrl &right)
551{
552 return left.relevance > right.relevance;
553}
554
555// fetch list of matching movies sorted by relevance (may be empty);
556// throws CScraperError on error; first called with fFirst set, then unset if first try fails
557std::vector<CScraperUrl> CScraper::FindMovie(XFILE::CCurlFile &fcurl, const std::string &sMovie,
558 bool fFirst)
559{
560 // prepare parameters for URL creation
561 std::string sTitle, sTitleYear, sYear;
562 CUtil::CleanString(sMovie, sTitle, sTitleYear, sYear, true/*fRemoveExt*/, fFirst);
563
564 CLog::Log(LOGDEBUG, "%s: Searching for '%s' using %s scraper "
565 "(path: '%s', content: '%s', version: '%s')", __FUNCTION__, sTitle.c_str(),
566 Name().c_str(), Path().c_str(),
567 ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
568
569 std::vector<CScraperUrl> vcscurl;
570 if (IsNoop())
571 return vcscurl;
572
573 if (!fFirst)
574 StringUtils::Replace(sTitle, '-',' ');
575
576 vector<string> vcsIn(1);
577 g_charsetConverter.utf8To(SearchStringEncoding(), sTitle, vcsIn[0]);
578 vcsIn[0] = CURL::Encode(vcsIn[0]);
579 if (fFirst && !sYear.empty())
580 vcsIn.push_back(sYear);
581
582 // request a search URL from the title/filename/etc.
583 CScraperUrl scurl;
584 vector<string> vcsOut = Run("CreateSearchUrl", scurl, fcurl, &vcsIn);
585 if (vcsOut.empty())
586 {
587 CLog::Log(LOGDEBUG, "%s: CreateSearchUrl failed", __FUNCTION__);
588 throw CScraperError();
589 }
590 scurl.ParseString(vcsOut[0]);
591
592 // do the search, and parse the result into a list
593 vcsIn.clear();
594 vcsIn.push_back(scurl.m_url[0].m_url);
595 vcsOut = Run("GetSearchResults", scurl, fcurl, &vcsIn);
596
597 bool fSort(true);
598 std::set<std::string> stsDupeCheck;
599 bool fResults(false);
600 for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
601 {
602 CXBMCTinyXML doc;
603 doc.Parse(*i, TIXML_ENCODING_UTF8);
604 if (!doc.RootElement())
605 {
606 CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__);
607 continue; // might have more valid results later
608 }
609
610 CheckScraperError(doc.RootElement());
611
612 TiXmlHandle xhDoc(&doc);
613 TiXmlHandle xhResults = xhDoc.FirstChild("results");
614 if (!xhResults.Element())
615 continue;
616 fResults = true; // even if empty
617
618 // we need to sort if returned results don't specify 'sorted="yes"'
619 if (fSort)
620 {
621 const char *sorted = xhResults.Element()->Attribute("sorted");
622 if (sorted != NULL)
623 fSort = !StringUtils::EqualsNoCase(sorted, "yes");
624 }
625
626 for (TiXmlElement *pxeMovie = xhResults.FirstChild("entity").Element();
627 pxeMovie; pxeMovie = pxeMovie->NextSiblingElement())
628 {
629 CScraperUrl scurlMovie;
630 TiXmlNode *pxnTitle = pxeMovie->FirstChild("title");
631 TiXmlElement *pxeLink = pxeMovie->FirstChildElement("url");
632 if (pxnTitle && pxnTitle->FirstChild() && pxeLink && pxeLink->FirstChild())
633 {
634 scurlMovie.strTitle = pxnTitle->FirstChild()->Value();
635 XMLUtils::GetString(pxeMovie, "id", scurlMovie.strId);
636
637 for ( ; pxeLink && pxeLink->FirstChild(); pxeLink = pxeLink->NextSiblingElement("url"))
638 scurlMovie.ParseElement(pxeLink);
639
640 // calculate the relavance of this hit
641 std::string sCompareTitle = scurlMovie.strTitle;
642 StringUtils::ToLower(sCompareTitle);
643 std::string sMatchTitle = sTitle;
644 StringUtils::ToLower(sMatchTitle);
645
646 /*
647 * Identify the best match by performing a fuzzy string compare on the search term and
648 * the result. Additionally, use the year (if available) to further refine the best match.
649 * An exact match scores 1, a match off by a year scores 0.5 (release dates can vary between
650 * countries), otherwise it scores 0.
651 */
652 std::string sCompareYear;
653 XMLUtils::GetString(pxeMovie, "year", sCompareYear);
654
655 double yearScore = 0;
656 if (!sYear.empty() && !sCompareYear.empty())
657 yearScore = std::max(0.0, 1-0.5*abs(atoi(sYear.c_str())-atoi(sCompareYear.c_str())));
658
659 scurlMovie.relevance = fstrcmp(sMatchTitle.c_str(), sCompareTitle.c_str(), 0.0) + yearScore;
660
661 // reconstruct a title for the user
662 if (!sCompareYear.empty())
663 scurlMovie.strTitle += StringUtils::Format(" (%s)", sCompareYear.c_str());
664
665 std::string sLanguage;
666 if (XMLUtils::GetString(pxeMovie, "language", sLanguage) && !sLanguage.empty())
667 scurlMovie.strTitle += StringUtils::Format(" (%s)", sLanguage.c_str());
668
669 // filter for dupes from naughty scrapers
670 if (stsDupeCheck.insert(scurlMovie.m_url[0].m_url + " " + scurlMovie.strTitle).second)
671 vcscurl.push_back(scurlMovie);
672 }
673 }
674 }
675
676 if (!fResults)
677 throw CScraperError(); // scraper aborted
678
679 if (fSort)
680 std::stable_sort(vcscurl.begin(), vcscurl.end(), RelevanceSortFunction);
681
682 return vcscurl;
683}
684
685// find album by artist, using fcurl for web fetches
686// returns a list of albums (empty if no match or failure)
687std::vector<CMusicAlbumInfo> CScraper::FindAlbum(CCurlFile &fcurl, const std::string &sAlbum,
688 const std::string &sArtist)
689{
690 CLog::Log(LOGDEBUG, "%s: Searching for '%s - %s' using %s scraper "
691 "(path: '%s', content: '%s', version: '%s')", __FUNCTION__, sArtist.c_str(),
692 sAlbum.c_str(), Name().c_str(), Path().c_str(),
693 ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
694
695 std::vector<CMusicAlbumInfo> vcali;
696 if (IsNoop())
697 return vcali;
698
699 // scraper function is given the album and artist as parameters and
700 // returns an XML <url> element parseable by CScraperUrl
701 std::vector<string> extras(2);
702 g_charsetConverter.utf8To(SearchStringEncoding(), sAlbum, extras[0]);
703 g_charsetConverter.utf8To(SearchStringEncoding(), sArtist, extras[1]);
704 extras[0] = CURL::Encode(extras[0]);
705 extras[1] = CURL::Encode(extras[1]);
706 CScraperUrl scurl;
707 vector<string> vcsOut = RunNoThrow("CreateAlbumSearchUrl", scurl, fcurl, &extras);
708 if (vcsOut.size() > 1)
709 CLog::Log(LOGWARNING, "%s: scraper returned multiple results; using first", __FUNCTION__);
710
711 if (vcsOut.empty() || vcsOut[0].empty())
712 return vcali;
713 scurl.ParseString(vcsOut[0]);
714
715 // the next function is passed the contents of the returned URL, and returns
716 // an empty string on failure; on success, returns XML matches in the form:
717 // <results>
718 // <entity>
719 // <title>...</title>
720 // <url>...</url> (with the usual CScraperUrl decorations like post or spoof)
721 // <artist>...</artist>
722 // <year>...</year>
723 // <relevance [scale="..."]>...</relevance> (scale defaults to 1; score is divided by it)
724 // </entity>
725 // ...
726 // </results>
727 vcsOut = RunNoThrow("GetAlbumSearchResults", scurl, fcurl);
728
729 // parse the returned XML into a vector of album objects
730 for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
731 {
732 CXBMCTinyXML doc;
733 doc.Parse(*i, TIXML_ENCODING_UTF8);
734 TiXmlHandle xhDoc(&doc);
735
736 for (TiXmlElement* pxeAlbum = xhDoc.FirstChild("results").FirstChild("entity").Element();
737 pxeAlbum; pxeAlbum = pxeAlbum->NextSiblingElement())
738 {
739 std::string sTitle;
740 if (XMLUtils::GetString(pxeAlbum, "title", sTitle) && !sTitle.empty())
741 {
742 std::string sArtist;
743 std::string sAlbumName;
744 if (XMLUtils::GetString(pxeAlbum, "artist", sArtist) && !sArtist.empty())
745 sAlbumName = StringUtils::Format("%s - %s", sArtist.c_str(), sTitle.c_str());
746 else
747 sAlbumName = sTitle;
748
749 std::string sYear;
750 if (XMLUtils::GetString(pxeAlbum, "year", sYear) && !sYear.empty())
751 sAlbumName = StringUtils::Format("%s (%s)", sAlbumName.c_str(), sYear.c_str());
752
753 // if no URL is provided, use the URL we got back from CreateAlbumSearchUrl
754 // (e.g., in case we only got one result back and were sent to the detail page)
755 TiXmlElement* pxeLink = pxeAlbum->FirstChildElement("url");
756 CScraperUrl scurlAlbum;
757 if (!pxeLink)
758 scurlAlbum.ParseString(scurl.m_xml);
759 for ( ; pxeLink && pxeLink->FirstChild(); pxeLink = pxeLink->NextSiblingElement("url"))
760 scurlAlbum.ParseElement(pxeLink);
761
762 if (!scurlAlbum.m_url.size())
763 continue;
764
765 CMusicAlbumInfo ali(sTitle, sArtist, sAlbumName, scurlAlbum);
766
767 TiXmlElement* pxeRel = pxeAlbum->FirstChildElement("relevance");
768 if (pxeRel && pxeRel->FirstChild())
769 {
770 const char* szScale = pxeRel->Attribute("scale");
771 float flScale = szScale ? float(atof(szScale)) : 1;
772 ali.SetRelevance(float(atof(pxeRel->FirstChild()->Value())) / flScale);
773 }
774
775 vcali.push_back(ali);
776 }
777 }
778 }
779 return vcali;
780}
781
782// find artist, using fcurl for web fetches
783// returns a list of artists (empty if no match or failure)
784std::vector<CMusicArtistInfo> CScraper::FindArtist(CCurlFile &fcurl,
785 const std::string &sArtist)
786{
787 CLog::Log(LOGDEBUG, "%s: Searching for '%s' using %s scraper "
788 "(file: '%s', content: '%s', version: '%s')", __FUNCTION__, sArtist.c_str(),
789 Name().c_str(), Path().c_str(),
790 ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
791
792 std::vector<CMusicArtistInfo> vcari;
793 if (IsNoop())
794 return vcari;
795
796 // scraper function is given the artist as parameter and
797 // returns an XML <url> element parseable by CScraperUrl
798 std::vector<string> extras(1);
799 g_charsetConverter.utf8To(SearchStringEncoding(), sArtist, extras[0]);
800 extras[0] = CURL::Encode(extras[0]);
801 CScraperUrl scurl;
802 vector<string> vcsOut = RunNoThrow("CreateArtistSearchUrl", scurl, fcurl, &extras);
803
804 if (vcsOut.empty() || vcsOut[0].empty())
805 return vcari;
806 scurl.ParseString(vcsOut[0]);
807
808 // the next function is passed the contents of the returned URL, and returns
809 // an empty string on failure; on success, returns XML matches in the form:
810 // <results>
811 // <entity>
812 // <title>...</title>
813 // <year>...</year>
814 // <genre>...</genre>
815 // <url>...</url> (with the usual CScraperUrl decorations like post or spoof)
816 // </entity>
817 // ...
818 // </results>
819 vcsOut = RunNoThrow("GetArtistSearchResults", scurl, fcurl);
820
821 // parse the returned XML into a vector of artist objects
822 for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
823 {
824 CXBMCTinyXML doc;
825 doc.Parse(*i, TIXML_ENCODING_UTF8);
826 if (!doc.RootElement())
827 {
828 CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__);
829 return vcari;
830 }
831 TiXmlHandle xhDoc(&doc);
832 for (TiXmlElement* pxeArtist = xhDoc.FirstChild("results").FirstChild("entity").Element();
833 pxeArtist; pxeArtist = pxeArtist->NextSiblingElement())
834 {
835 TiXmlNode* pxnTitle = pxeArtist->FirstChild("title");
836 if (pxnTitle && pxnTitle->FirstChild())
837 {
838 CScraperUrl scurlArtist;
839
840 TiXmlElement* pxeLink = pxeArtist->FirstChildElement("url");
841 if (!pxeLink)
842 scurlArtist.ParseString(scurl.m_xml);
843 for ( ; pxeLink && pxeLink->FirstChild(); pxeLink = pxeLink->NextSiblingElement("url"))
844 scurlArtist.ParseElement(pxeLink);
845
846 if (!scurlArtist.m_url.size())
847 continue;
848
849 CMusicArtistInfo ari(pxnTitle->FirstChild()->Value(), scurlArtist);
850 std::string genre;
851 XMLUtils::GetString(pxeArtist, "genre", genre);
852 if (!genre.empty())
853 ari.GetArtist().genre = StringUtils::Split(genre, g_advancedSettings.m_musicItemSeparator);
854 XMLUtils::GetString(pxeArtist, "year", ari.GetArtist().strBorn);
855
856 vcari.push_back(ari);
857 }
858 }
859 }
860 return vcari;
861}
862
863// fetch list of episodes from URL (from video database)
864EPISODELIST CScraper::GetEpisodeList(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl)
865{
866 EPISODELIST vcep;
867 if (scurl.m_url.empty())
868 return vcep;
869
870 CLog::Log(LOGDEBUG, "%s: Searching '%s' using %s scraper "
871 "(file: '%s', content: '%s', version: '%s')", __FUNCTION__,
872 scurl.m_url[0].m_url.c_str(), Name().c_str(), Path().c_str(),
873 ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
874
875 vector<string> vcsIn;
876 vcsIn.push_back(scurl.m_url[0].m_url);
877 vector<string> vcsOut = RunNoThrow("GetEpisodeList", scurl, fcurl, &vcsIn);
878
879 // parse the XML response
880 for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
881 {
882 CXBMCTinyXML doc;
883 doc.Parse(*i);
884 if (!doc.RootElement())
885 {
886 CLog::Log(LOGERROR, "%s: Unable to parse XML",__FUNCTION__);
887 continue;
888 }
889
890 TiXmlHandle xhDoc(&doc);
891 for (TiXmlElement *pxeMovie = xhDoc.FirstChild("episodeguide").FirstChild("episode").
892 Element(); pxeMovie; pxeMovie = pxeMovie->NextSiblingElement())
893 {
894 EPISODE ep;
895 TiXmlElement *pxeLink = pxeMovie->FirstChildElement("url");
896 std::string strEpNum;
897 if (pxeLink && XMLUtils::GetInt(pxeMovie, "season", ep.iSeason) &&
898 XMLUtils::GetString(pxeMovie, "epnum", strEpNum) && !strEpNum.empty())
899 {
900 CScraperUrl &scurlEp(ep.cScraperUrl);
901 size_t dot = strEpNum.find(".");
902 ep.iEpisode = atoi(strEpNum.c_str());
903 ep.iSubepisode = (dot != std::string::npos) ? atoi(strEpNum.substr(dot + 1).c_str()) : 0;
904 if (!XMLUtils::GetString(pxeMovie, "title", scurlEp.strTitle) || scurlEp.strTitle.empty() )
905 scurlEp.strTitle = g_localizeStrings.Get(416);
906 XMLUtils::GetString(pxeMovie, "id", scurlEp.strId);
907
908 for ( ; pxeLink && pxeLink->FirstChild(); pxeLink = pxeLink->NextSiblingElement("url"))
909 scurlEp.ParseElement(pxeLink);
910
911 // date must be the format of yyyy-mm-dd
912 ep.cDate.SetValid(FALSE);
913 std::string sDate;
914 if (XMLUtils::GetString(pxeMovie, "aired", sDate) && sDate.length() == 10)
915 {
916 tm tm;
917 if (strptime(sDate.c_str(), "%Y-%m-%d", &tm))
918 ep.cDate.SetDate(1900+tm.tm_year, tm.tm_mon + 1, tm.tm_mday);
919 }
920 vcep.push_back(ep);
921 }
922 }
923 }
924
925 return vcep;
926}
927
928// takes URL; returns true and populates video details on success, false otherwise
929bool CScraper::GetVideoDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
930 bool fMovie/*else episode*/, CVideoInfoTag &video)
931{
932 CLog::Log(LOGDEBUG, "%s: Reading %s '%s' using %s scraper "
933 "(file: '%s', content: '%s', version: '%s')", __FUNCTION__,
934 fMovie ? MediaTypeMovie : MediaTypeEpisode, scurl.m_url[0].m_url.c_str(), Name().c_str(), Path().c_str(),
935 ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
936
937 video.Reset();
938 std::string sFunc = fMovie ? "GetDetails" : "GetEpisodeDetails";
939 vector<string> vcsIn;
940 vcsIn.push_back(scurl.strId);
941 vcsIn.push_back(scurl.m_url[0].m_url);
942 vector<string> vcsOut = RunNoThrow(sFunc, scurl, fcurl, &vcsIn);
943
944 // parse XML output
945 bool fRet(false);
946 for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
947 {
948 CXBMCTinyXML doc;
949 doc.Parse(*i, TIXML_ENCODING_UTF8);
950 if (!doc.RootElement())
951 {
952 CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__);
953 continue;
954 }
955
956 TiXmlHandle xhDoc(&doc);
957 TiXmlElement *pxeDetails = xhDoc.FirstChild("details").Element();
958 if (!pxeDetails)
959 {
960 CLog::Log(LOGERROR, "%s: Invalid XML file (want <details>)", __FUNCTION__);
961 continue;
962 }
963 video.Load(pxeDetails, true/*fChain*/);
964 fRet = true; // but don't exit in case of chaining
965 }
966 return fRet;
967}
968
969// takes a URL; returns true and populates album on success, false otherwise
970bool CScraper::GetAlbumDetails(CCurlFile &fcurl, const CScraperUrl &scurl, CAlbum &album)
971{
972 CLog::Log(LOGDEBUG, "%s: Reading '%s' using %s scraper "
973 "(file: '%s', content: '%s', version: '%s')", __FUNCTION__,
974 scurl.m_url[0].m_url.c_str(), Name().c_str(), Path().c_str(),
975 ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
976
977 vector<string> vcsOut = RunNoThrow("GetAlbumDetails", scurl, fcurl);
978
979 // parse the returned XML into an album object (see CAlbum::Load for details)
980 bool fRet(false);
981 for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
982 {
983 CXBMCTinyXML doc;
984 doc.Parse(*i, TIXML_ENCODING_UTF8);
985 if (!doc.RootElement())
986 {
987 CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__);
988 return false;
989 }
990 fRet = album.Load(doc.RootElement(), i != vcsOut.begin());
991 }
992 return fRet;
993}
994
995// takes a URL (one returned from FindArtist), the original search string, and
996// returns true and populates artist on success, false on failure
997bool CScraper::GetArtistDetails(CCurlFile &fcurl, const CScraperUrl &scurl,
998 const std::string &sSearch, CArtist &artist)
999{
1000 if (!scurl.m_url.size())
1001 return false;
1002
1003 CLog::Log(LOGDEBUG, "%s: Reading '%s' ('%s') using %s scraper "
1004 "(file: '%s', content: '%s', version: '%s')", __FUNCTION__,
1005 scurl.m_url[0].m_url.c_str(), sSearch.c_str(), Name().c_str(), Path().c_str(),
1006 ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str());
1007
1008 // pass in the original search string for chaining to search other sites
1009 vector<string> vcIn;
1010 vcIn.push_back(sSearch);
1011 vcIn[0] = CURL::Encode(vcIn[0]);
1012
1013 vector<string> vcsOut = RunNoThrow("GetArtistDetails", scurl, fcurl, &vcIn);
1014
1015 // ok, now parse the xml file
1016 bool fRet(false);
1017 for (vector<string>::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i)
1018 {
1019 CXBMCTinyXML doc;
1020 doc.Parse(*i, TIXML_ENCODING_UTF8);
1021 if (!doc.RootElement())
1022 {
1023 CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__);
1024 return false;
1025 }
1026
1027 fRet = artist.Load(doc.RootElement(), i != vcsOut.begin());
1028 }
1029 return fRet;
1030}
1031
1032}
1033
diff --git a/xbmc/addons/Scraper.h b/xbmc/addons/Scraper.h
new file mode 100644
index 0000000..7302972
--- /dev/null
+++ b/xbmc/addons/Scraper.h
@@ -0,0 +1,178 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21#include "addons/Addon.h"
22#include "XBDateTime.h"
23#include "utils/ScraperUrl.h"
24#include "utils/ScraperParser.h"
25#include "video/Episode.h"
26
27class CAlbum;
28class CArtist;
29class CVideoInfoTag;
30
31namespace MUSIC_GRABBER
32{
33class CMusicAlbumInfo;
34class CMusicArtistInfo;
35}
36
37typedef enum
38{
39 CONTENT_MOVIES,
40 CONTENT_TVSHOWS,
41 CONTENT_MUSICVIDEOS,
42 CONTENT_ALBUMS,
43 CONTENT_ARTISTS,
44 CONTENT_NONE,
45} CONTENT_TYPE;
46
47namespace XFILE
48{
49 class CCurlFile;
50}
51
52class CScraperUrl;
53
54namespace ADDON
55{
56class CScraper;
57typedef std::shared_ptr<CScraper> ScraperPtr;
58
59std::string TranslateContent(const CONTENT_TYPE &content, bool pretty=false);
60CONTENT_TYPE TranslateContent(const std::string &string);
61TYPE ScraperTypeFromContent(const CONTENT_TYPE &content);
62
63// thrown as exception to signal abort or show error dialog
64class CScraperError
65{
66public:
67 CScraperError() : m_fAborted(true) {}
68 CScraperError(const std::string &sTitle, const std::string &sMessage) :
69 m_fAborted(false), m_sTitle(sTitle), m_sMessage(sMessage) {}
70
71 bool FAborted() const { return m_fAborted; }
72 const std::string &Title() const { return m_sTitle; }
73 const std::string &Message() const { return m_sMessage; }
74
75private:
76 bool m_fAborted;
77 std::string m_sTitle;
78 std::string m_sMessage;
79};
80
81class CScraper : public CAddon
82{
83public:
84 CScraper(const AddonProps &props) : CAddon(props), m_fLoaded(false) {}
85 CScraper(const cp_extension_t *ext);
86 virtual ~CScraper() {}
87 virtual AddonPtr Clone() const;
88
89 /*! \brief Set the scraper settings for a particular path from an XML string
90 Loads the default and user settings (if not already loaded) and, if the given XML string is non-empty,
91 overrides the user settings with the XML.
92 \param content Content type of the path
93 \param xml string of XML with the settings. If non-empty this overrides any saved user settings.
94 \return true if settings are available, false otherwise
95 \sa GetPathSettings
96 */
97 bool SetPathSettings(CONTENT_TYPE content, const std::string& xml);
98
99 /*! \brief Get the scraper settings for a particular path in the form of an XML string
100 Loads the default and user settings (if not already loaded) and returns the user settings in the
101 form or an XML string
102 \return a string containing the XML settings
103 \sa SetPathSettings
104 */
105 std::string GetPathSettings();
106
107 /*! \brief Clear any previously cached results for this scraper
108 Any previously cached files are cleared if they have been cached for longer than the specified
109 cachepersistence.
110 */
111 void ClearCache();
112
113 CONTENT_TYPE Content() const { return m_pathContent; }
114 const std::string& Language() const { return m_language; }
115 bool RequiresSettings() const { return m_requiressettings; }
116 bool Supports(const CONTENT_TYPE &content) const;
117
118 bool IsInUse() const;
119 bool IsNoop();
120
121 // scraper media functions
122 CScraperUrl NfoUrl(const std::string &sNfoContent);
123
124 /*! \brief Resolve an external ID (e.g. MusicBrainz IDs) to a URL using scrapers
125 If we have an ID in hand, e.g. MusicBrainz IDs or TheTVDB Season IDs
126 we can get directly to a URL instead of searching by name and choosing from
127 the search results. The correct scraper type should be used to get the right
128 URL for a given ID, so we can differentiate albums, artists, TV Seasons, etc.
129 \param externalID the external ID - e.g. MusicBrainzArtist/AlbumID
130 \return a populated URL pointing to the details page for the given ID or
131 an empty URL if we couldn't resolve the ID.
132 */
133 CScraperUrl ResolveIDToUrl(const std::string &externalID);
134
135 std::vector<CScraperUrl> FindMovie(XFILE::CCurlFile &fcurl,
136 const std::string &sMovie, bool fFirst);
137 std::vector<MUSIC_GRABBER::CMusicAlbumInfo> FindAlbum(XFILE::CCurlFile &fcurl,
138 const std::string &sAlbum, const std::string &sArtist = "");
139 std::vector<MUSIC_GRABBER::CMusicArtistInfo> FindArtist(
140 XFILE::CCurlFile &fcurl, const std::string &sArtist);
141 VIDEO::EPISODELIST GetEpisodeList(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl);
142
143 bool GetVideoDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
144 bool fMovie/*else episode*/, CVideoInfoTag &video);
145 bool GetAlbumDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
146 CAlbum &album);
147 bool GetArtistDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
148 const std::string &sSearch, CArtist &artist);
149
150private:
151 CScraper(const CScraper &rhs);
152 std::string SearchStringEncoding() const
153 { return m_parser.GetSearchStringEncoding(); }
154
155 bool Load();
156 std::vector<std::string> Run(const std::string& function,
157 const CScraperUrl& url,
158 XFILE::CCurlFile& http,
159 const std::vector<std::string>* extras = NULL);
160 std::vector<std::string> RunNoThrow(const std::string& function,
161 const CScraperUrl& url,
162 XFILE::CCurlFile& http,
163 const std::vector<std::string>* extras = NULL);
164 std::string InternalRun(const std::string& function,
165 const CScraperUrl& url,
166 XFILE::CCurlFile& http,
167 const std::vector<std::string>* extras);
168
169 bool m_fLoaded;
170 std::string m_language;
171 bool m_requiressettings;
172 CDateTimeSpan m_persistence;
173 CONTENT_TYPE m_pathContent;
174 CScraperParser m_parser;
175};
176
177}
178
diff --git a/xbmc/addons/ScreenSaver.cpp b/xbmc/addons/ScreenSaver.cpp
new file mode 100644
index 0000000..ef345f5
--- /dev/null
+++ b/xbmc/addons/ScreenSaver.cpp
@@ -0,0 +1,125 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#include "ScreenSaver.h"
21#include "guilib/GraphicContext.h"
22#include "interfaces/generic/ScriptInvocationManager.h"
23#include "settings/DisplaySettings.h"
24#include "utils/AlarmClock.h"
25#include "windowing/WindowingFactory.h"
26
27// What sound does a python screensaver make?
28#define SCRIPT_ALARM "sssssscreensaver"
29
30#define SCRIPT_TIMEOUT 5 // seconds
31
32namespace ADDON
33{
34
35 CScreenSaver::CScreenSaver(const char *addonID)
36 : ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>(AddonProps(addonID, ADDON_UNKNOWN, "", ""))
37 {
38 }
39
40AddonPtr CScreenSaver::Clone() const
41{
42 // Copy constructor is generated by compiler and calls parent copy constructor
43 return AddonPtr(new CScreenSaver(*this));
44}
45
46bool CScreenSaver::CreateScreenSaver()
47{
48 if (CScriptInvocationManager::Get().HasLanguageInvoker(LibPath()))
49 {
50 // Don't allow a previously-scheduled alarm to kill our new screensaver
51 g_alarmClock.Stop(SCRIPT_ALARM, true);
52
53 if (!CScriptInvocationManager::Get().Stop(LibPath()))
54 CScriptInvocationManager::Get().ExecuteAsync(LibPath(), Clone());
55 return true;
56 }
57 // pass it the screen width,height
58 // and the name of the screensaver
59 int iWidth = g_graphicsContext.GetWidth();
60 int iHeight = g_graphicsContext.GetHeight();
61
62 m_pInfo = new SCR_PROPS;
63#ifdef HAS_DX
64 m_pInfo->device = g_Windowing.Get3DDevice();
65#else
66 m_pInfo->device = NULL;
67#endif
68 m_pInfo->x = 0;
69 m_pInfo->y = 0;
70 m_pInfo->width = iWidth;
71 m_pInfo->height = iHeight;
72 m_pInfo->pixelRatio = g_graphicsContext.GetResInfo().fPixelRatio;
73 m_pInfo->name = strdup(Name().c_str());
74 m_pInfo->presets = strdup(CSpecialProtocol::TranslatePath(Path()).c_str());
75 m_pInfo->profile = strdup(CSpecialProtocol::TranslatePath(Profile()).c_str());
76
77 if (CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>::Create() == ADDON_STATUS_OK)
78 return true;
79
80 return false;
81}
82
83void CScreenSaver::Start()
84{
85 // notify screen saver that they should start
86 if (Initialized()) m_pStruct->Start();
87}
88
89void CScreenSaver::Render()
90{
91 // ask screensaver to render itself
92 if (Initialized()) m_pStruct->Render();
93}
94
95void CScreenSaver::GetInfo(SCR_INFO *info)
96{
97 // get info from screensaver
98 if (Initialized()) m_pStruct->GetInfo(info);
99}
100
101void CScreenSaver::Destroy()
102{
103#ifdef HAS_PYTHON
104 if (URIUtils::HasExtension(LibPath(), ".py"))
105 {
106 g_alarmClock.Start(SCRIPT_ALARM, SCRIPT_TIMEOUT, "StopScript(" + LibPath() + ")", true, false);
107 return;
108 }
109#endif
110 // Release what was allocated in method CScreenSaver::CreateScreenSaver.
111 if (m_pInfo)
112 {
113 free((void *) m_pInfo->name);
114 free((void *) m_pInfo->presets);
115 free((void *) m_pInfo->profile);
116
117 delete m_pInfo;
118 m_pInfo = NULL;
119 }
120
121 CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>::Destroy();
122}
123
124} /*namespace ADDON*/
125
diff --git a/xbmc/addons/ScreenSaver.h b/xbmc/addons/ScreenSaver.h
new file mode 100644
index 0000000..1b2a741
--- /dev/null
+++ b/xbmc/addons/ScreenSaver.h
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#pragma once
21
22#include "AddonDll.h"
23#include "include/xbmc_scr_types.h"
24
25typedef DllAddon<ScreenSaver, SCR_PROPS> DllScreenSaver;
26
27namespace ADDON
28{
29
30class CScreenSaver : public ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>
31{
32public:
33 CScreenSaver(const AddonProps &props) : ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>(props) {};
34 CScreenSaver(const cp_extension_t *ext) : ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>(ext) {};
35 CScreenSaver(const char *addonID);
36 virtual ~CScreenSaver() {}
37 virtual AddonPtr Clone() const;
38
39 // Things that MUST be supplied by the child classes
40 bool CreateScreenSaver();
41 void Start();
42 void Render();
43 void GetInfo(SCR_INFO *info);
44 void Destroy();
45};
46
47} /*namespace ADDON*/
diff --git a/xbmc/addons/Service.cpp b/xbmc/addons/Service.cpp
new file mode 100644
index 0000000..2fc7670
--- /dev/null
+++ b/xbmc/addons/Service.cpp
@@ -0,0 +1,158 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#include "Service.h"
21#include "AddonManager.h"
22#include "interfaces/generic/ScriptInvocationManager.h"
23#include "utils/log.h"
24#include "system.h"
25
26using namespace std;
27
28namespace ADDON
29{
30
31CService::CService(const cp_extension_t *ext)
32 : CAddon(ext), m_type(UNKNOWN), m_startOption(LOGIN)
33{
34 BuildServiceType();
35
36 std::string start = CAddonMgr::Get().GetExtValue(ext->configuration, "@start");
37 if (start == "startup")
38 m_startOption = STARTUP;
39}
40
41
42CService::CService(const AddonProps &props)
43 : CAddon(props), m_type(UNKNOWN), m_startOption(LOGIN)
44{
45 BuildServiceType();
46}
47
48AddonPtr CService::Clone() const
49{
50 return AddonPtr(new CService(*this));
51}
52
53bool CService::Start()
54{
55 bool ret = true;
56 switch (m_type)
57 {
58#ifdef HAS_PYTHON
59 case PYTHON:
60 ret = (CScriptInvocationManager::Get().ExecuteAsync(LibPath(), this->shared_from_this()) != -1);
61 break;
62#endif
63
64 case UNKNOWN:
65 default:
66 ret = false;
67 break;
68 }
69
70 return ret;
71}
72
73bool CService::Stop()
74{
75 bool ret = true;
76
77 switch (m_type)
78 {
79#ifdef HAS_PYTHON
80 case PYTHON:
81 ret = CScriptInvocationManager::Get().Stop(LibPath());
82 break;
83#endif
84
85 case UNKNOWN:
86 default:
87 ret = false;
88 break;
89 }
90
91 return ret;
92}
93
94void CService::BuildServiceType()
95{
96 std::string str = LibPath();
97 std::string ext;
98
99 size_t p = str.find_last_of('.');
100 if (p != string::npos)
101 ext = str.substr(p + 1);
102
103#ifdef HAS_PYTHON
104 std::string pythonExt = ADDON_PYTHON_EXT;
105 pythonExt.erase(0, 2);
106 if ( ext == pythonExt )
107 m_type = PYTHON;
108 else
109#endif
110 {
111 m_type = UNKNOWN;
112 CLog::Log(LOGERROR, "ADDON: extension '%s' is not currently supported for service addon", ext.c_str());
113 }
114}
115
116void CService::OnDisabled()
117{
118 Stop();
119}
120
121void CService::OnEnabled()
122{
123 Start();
124}
125
126bool CService::OnPreInstall()
127{
128 // make sure the addon is stopped
129 AddonPtr localAddon; // need to grab the local addon so we have the correct library path to stop
130 if (CAddonMgr::Get().GetAddon(ID(), localAddon, ADDON_SERVICE, false))
131 {
132 std::shared_ptr<CService> service = std::dynamic_pointer_cast<CService>(localAddon);
133 if (service)
134 service->Stop();
135 }
136 return !CAddonMgr::Get().IsAddonDisabled(ID());
137}
138
139void CService::OnPostInstall(bool restart, bool update, bool modal)
140{
141 if (restart) // reload/start it if it was running
142 {
143 AddonPtr localAddon; // need to grab the local addon so we have the correct library path to stop
144 if (CAddonMgr::Get().GetAddon(ID(), localAddon, ADDON_SERVICE, false))
145 {
146 std::shared_ptr<CService> service = std::dynamic_pointer_cast<CService>(localAddon);
147 if (service)
148 service->Start();
149 }
150 }
151}
152
153void CService::OnPreUnInstall()
154{
155 Stop();
156}
157
158}
diff --git a/xbmc/addons/Service.h b/xbmc/addons/Service.h
new file mode 100644
index 0000000..f7394de
--- /dev/null
+++ b/xbmc/addons/Service.h
@@ -0,0 +1,63 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21#include "Addon.h"
22
23namespace ADDON
24{
25
26 class CService: public CAddon
27 {
28 public:
29
30 enum TYPE
31 {
32 UNKNOWN,
33 PYTHON
34 };
35
36 enum START_OPTION
37 {
38 STARTUP,
39 LOGIN
40 };
41
42 CService(const cp_extension_t *ext);
43 CService(const AddonProps &props);
44 virtual AddonPtr Clone() const;
45
46 bool Start();
47 bool Stop();
48 TYPE GetServiceType() { return m_type; }
49 START_OPTION GetStartOption() { return m_startOption; }
50 virtual void OnDisabled();
51 virtual void OnEnabled();
52 virtual bool OnPreInstall();
53 virtual void OnPostInstall(bool restart, bool update, bool modal);
54 virtual void OnPreUnInstall();
55
56 protected:
57 void BuildServiceType();
58
59 private:
60 TYPE m_type;
61 START_OPTION m_startOption;
62 };
63}
diff --git a/xbmc/addons/Skin.cpp b/xbmc/addons/Skin.cpp
new file mode 100644
index 0000000..acb5799
--- /dev/null
+++ b/xbmc/addons/Skin.cpp
@@ -0,0 +1,491 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Skin.h"
22#include "AddonManager.h"
23#include "LangInfo.h"
24#include "Util.h"
25#include "dialogs/GUIDialogKaiToast.h"
26#include "dialogs/GUIDialogYesNo.h"
27#include "filesystem/File.h"
28#include "filesystem/SpecialProtocol.h"
29#include "guilib/GUIWindowManager.h"
30#include "guilib/WindowIDs.h"
31#include "settings/Settings.h"
32#include "settings/lib/Setting.h"
33#include "utils/URIUtils.h"
34#include "utils/log.h"
35#include "utils/StringUtils.h"
36#include "ApplicationMessenger.h"
37
38// fallback for new skin resolution code
39#include "filesystem/Directory.h"
40
41using namespace std;
42using namespace XFILE;
43
44std::shared_ptr<ADDON::CSkinInfo> g_SkinInfo;
45
46namespace ADDON
47{
48
49CSkinInfo::CSkinInfo(const AddonProps &props, const RESOLUTION_INFO &resolution)
50 : CAddon(props), m_defaultRes(resolution), m_version(""), m_effectsSlowDown(1.f), m_debugging(false)
51{
52}
53
54CSkinInfo::CSkinInfo(const cp_extension_t *ext)
55 : CAddon(ext), m_version(""), m_effectsSlowDown(1.f)
56{
57 ELEMENTS elements;
58 if (CAddonMgr::Get().GetExtElements(ext->configuration, "res", elements))
59 {
60 for (ELEMENTS::iterator i = elements.begin(); i != elements.end(); ++i)
61 {
62 int width = atoi(CAddonMgr::Get().GetExtValue(*i, "@width").c_str());
63 int height = atoi(CAddonMgr::Get().GetExtValue(*i, "@height").c_str());
64 bool defRes = CAddonMgr::Get().GetExtValue(*i, "@default") == "true";
65 std::string folder = CAddonMgr::Get().GetExtValue(*i, "@folder");
66 float aspect = 0;
67 std::string strAspect = CAddonMgr::Get().GetExtValue(*i, "@aspect");
68 vector<string> fracs = StringUtils::Split(strAspect, ':');
69 if (fracs.size() == 2)
70 aspect = (float)(atof(fracs[0].c_str())/atof(fracs[1].c_str()));
71 if (width > 0 && height > 0)
72 {
73 RESOLUTION_INFO res(width, height, aspect, folder);
74 res.strId = strAspect; // for skin usage, store aspect string in strId
75 if (defRes)
76 m_defaultRes = res;
77 m_resolutions.push_back(res);
78 }
79 }
80 }
81 else
82 { // no resolutions specified -> backward compatibility
83 std::string defaultWide = CAddonMgr::Get().GetExtValue(ext->configuration, "@defaultwideresolution");
84 if (defaultWide.empty())
85 defaultWide = CAddonMgr::Get().GetExtValue(ext->configuration, "@defaultresolution");
86 TranslateResolution(defaultWide, m_defaultRes);
87 }
88
89 std::string str = CAddonMgr::Get().GetExtValue(ext->configuration, "@effectslowdown");
90 if (!str.empty())
91 m_effectsSlowDown = (float)atof(str.c_str());
92
93 m_debugging = CAddonMgr::Get().GetExtValue(ext->configuration, "@debugging") == "true";
94
95 LoadStartupWindows(ext);
96
97 // figure out the version
98 m_version = GetDependencyVersion("xbmc.gui");
99}
100
101CSkinInfo::~CSkinInfo()
102{
103}
104
105AddonPtr CSkinInfo::Clone() const
106{
107 return AddonPtr(new CSkinInfo(*this));
108}
109
110struct closestRes
111{
112 closestRes(const RESOLUTION_INFO &target) : m_target(target) { };
113 bool operator()(const RESOLUTION_INFO &i, const RESOLUTION_INFO &j)
114 {
115 float diff = fabs(i.DisplayRatio() - m_target.DisplayRatio()) - fabs(j.DisplayRatio() - m_target.DisplayRatio());
116 if (diff < 0) return true;
117 if (diff > 0) return false;
118 diff = fabs((float)i.iHeight - m_target.iHeight) - fabs((float)j.iHeight - m_target.iHeight);
119 if (diff < 0) return true;
120 if (diff > 0) return false;
121 return fabs((float)i.iWidth - m_target.iWidth) < fabs((float)j.iWidth - m_target.iWidth);
122 }
123 RESOLUTION_INFO m_target;
124};
125
126void CSkinInfo::Start()
127{
128 if (!m_resolutions.size())
129 { // try falling back to whatever resolutions exist in the directory
130 CFileItemList items;
131 CDirectory::GetDirectory(Path(), items, "", DIR_FLAG_NO_FILE_DIRS);
132 for (int i = 0; i < items.Size(); i++)
133 {
134 RESOLUTION_INFO res;
135 if (items[i]->m_bIsFolder && TranslateResolution(items[i]->GetLabel(), res))
136 m_resolutions.push_back(res);
137 }
138 }
139
140 if (!m_resolutions.empty())
141 {
142 // find the closest resolution
143 const RESOLUTION_INFO &target = g_graphicsContext.GetResInfo();
144 RESOLUTION_INFO& res = *std::min_element(m_resolutions.begin(), m_resolutions.end(), closestRes(target));
145 m_currentAspect = res.strId;
146 }
147}
148
149std::string CSkinInfo::GetSkinPath(const std::string& strFile, RESOLUTION_INFO *res, const std::string& strBaseDir /* = "" */) const
150{
151 if (m_resolutions.empty())
152 return ""; // invalid skin
153
154 std::string strPathToUse = Path();
155 if (!strBaseDir.empty())
156 strPathToUse = strBaseDir;
157
158 // if the caller doesn't care about the resolution just use a temporary
159 RESOLUTION_INFO tempRes;
160 if (!res)
161 res = &tempRes;
162
163 // find the closest resolution
164 const RESOLUTION_INFO &target = g_graphicsContext.GetResInfo();
165 *res = *std::min_element(m_resolutions.begin(), m_resolutions.end(), closestRes(target));
166
167 std::string strPath = URIUtils::AddFileToFolder(strPathToUse, res->strMode);
168 strPath = URIUtils::AddFileToFolder(strPath, strFile);
169 if (CFile::Exists(strPath))
170 return strPath;
171
172 // use the default resolution
173 *res = m_defaultRes;
174
175 strPath = URIUtils::AddFileToFolder(strPathToUse, res->strMode);
176 strPath = URIUtils::AddFileToFolder(strPath, strFile);
177 return strPath;
178}
179
180bool CSkinInfo::HasSkinFile(const std::string &strFile) const
181{
182 return CFile::Exists(GetSkinPath(strFile));
183}
184
185void CSkinInfo::LoadIncludes()
186{
187 std::string includesPath = CSpecialProtocol::TranslatePathConvertCase(GetSkinPath("includes.xml"));
188 CLog::Log(LOGINFO, "Loading skin includes from %s", includesPath.c_str());
189 m_includes.ClearIncludes();
190 m_includes.LoadIncludes(includesPath);
191}
192
193void CSkinInfo::ResolveIncludes(TiXmlElement *node, std::map<INFO::InfoPtr, bool>* xmlIncludeConditions /* = NULL */)
194{
195 if(xmlIncludeConditions)
196 xmlIncludeConditions->clear();
197
198 m_includes.ResolveIncludes(node, xmlIncludeConditions);
199}
200
201int CSkinInfo::GetStartWindow() const
202{
203 int windowID = CSettings::Get().GetInt("lookandfeel.startupwindow");
204 assert(m_startupWindows.size());
205 for (vector<CStartupWindow>::const_iterator it = m_startupWindows.begin(); it != m_startupWindows.end(); ++it)
206 {
207 if (windowID == (*it).m_id)
208 return windowID;
209 }
210 // return our first one
211 return m_startupWindows[0].m_id;
212}
213
214bool CSkinInfo::LoadStartupWindows(const cp_extension_t *ext)
215{
216 m_startupWindows.clear();
217 m_startupWindows.push_back(CStartupWindow(WINDOW_HOME, "513"));
218 m_startupWindows.push_back(CStartupWindow(WINDOW_TV_CHANNELS, "19180"));
219 m_startupWindows.push_back(CStartupWindow(WINDOW_RADIO_CHANNELS, "19183"));
220 m_startupWindows.push_back(CStartupWindow(WINDOW_PROGRAMS, "0"));
221 m_startupWindows.push_back(CStartupWindow(WINDOW_PICTURES, "1"));
222 m_startupWindows.push_back(CStartupWindow(WINDOW_MUSIC, "2"));
223 m_startupWindows.push_back(CStartupWindow(WINDOW_VIDEOS, "3"));
224 m_startupWindows.push_back(CStartupWindow(WINDOW_FILES, "7"));
225 m_startupWindows.push_back(CStartupWindow(WINDOW_SETTINGS_MENU, "5"));
226 m_startupWindows.push_back(CStartupWindow(WINDOW_WEATHER, "8"));
227 return true;
228}
229
230void CSkinInfo::GetSkinPaths(std::vector<std::string> &paths) const
231{
232 RESOLUTION_INFO res;
233 GetSkinPath("Home.xml", &res);
234 if (!res.strMode.empty())
235 paths.push_back(URIUtils::AddFileToFolder(Path(), res.strMode));
236 if (res.strMode != m_defaultRes.strMode)
237 paths.push_back(URIUtils::AddFileToFolder(Path(), m_defaultRes.strMode));
238}
239
240bool CSkinInfo::TranslateResolution(const std::string &name, RESOLUTION_INFO &res)
241{
242 std::string lower(name); StringUtils::ToLower(lower);
243 if (lower == "pal")
244 res = RESOLUTION_INFO(720, 576, 4.0f/3, "pal");
245 else if (lower == "pal16x9")
246 res = RESOLUTION_INFO(720, 576, 16.0f/9, "pal16x9");
247 else if (lower == "ntsc")
248 res = RESOLUTION_INFO(720, 480, 4.0f/3, "ntsc");
249 else if (lower == "ntsc16x9")
250 res = RESOLUTION_INFO(720, 480, 16.0f/9, "ntsc16x9");
251 else if (lower == "720p")
252 res = RESOLUTION_INFO(1280, 720, 0, "720p");
253 else if (lower == "1080i")
254 res = RESOLUTION_INFO(1920, 1080, 0, "1080i");
255 else
256 return false;
257 return true;
258}
259
260int CSkinInfo::GetFirstWindow() const
261{
262 int startWindow = GetStartWindow();
263 if (HasSkinFile("Startup.xml"))
264 startWindow = WINDOW_STARTUP_ANIM;
265 return startWindow;
266}
267
268bool CSkinInfo::IsInUse() const
269{
270 // Could extend this to prompt for reverting to the standard skin perhaps
271 return CSettings::Get().GetString("lookandfeel.skin") == ID();
272}
273
274const INFO::CSkinVariableString* CSkinInfo::CreateSkinVariable(const std::string& name, int context)
275{
276 return m_includes.CreateSkinVariable(name, context);
277}
278
279bool CSkinInfo::OnPreInstall()
280{
281 // check whether this is an active skin - we need to unload it if so
282 if (IsInUse())
283 {
284 CApplicationMessenger::Get().ExecBuiltIn("UnloadSkin", true);
285 return true;
286 }
287 return false;
288}
289
290void CSkinInfo::OnPostInstall(bool restart, bool update, bool modal)
291{
292 if (restart || (!update && !modal && CGUIDialogYesNo::ShowAndGetInput(Name(), g_localizeStrings.Get(24099),"","")))
293 {
294 CGUIDialogKaiToast *toast = (CGUIDialogKaiToast *)g_windowManager.GetWindow(WINDOW_DIALOG_KAI_TOAST);
295 if (toast)
296 {
297 toast->ResetTimer();
298 toast->Close(true);
299 }
300 if (CSettings::Get().GetString("lookandfeel.skin") == ID())
301 CApplicationMessenger::Get().ExecBuiltIn("ReloadSkin", true);
302 else
303 CSettings::Get().SetString("lookandfeel.skin", ID());
304 }
305}
306
307void CSkinInfo::SettingOptionsSkinColorsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data)
308{
309 std::string settingValue = ((const CSettingString*)setting)->GetValue();
310 // Remove the .xml extension from the Themes
311 if (URIUtils::HasExtension(settingValue, ".xml"))
312 URIUtils::RemoveExtension(settingValue);
313 current = "SKINDEFAULT";
314
315 // There is a default theme (just defaults.xml)
316 // any other *.xml files are additional color themes on top of this one.
317
318 // add the default label
319 list.push_back(make_pair(g_localizeStrings.Get(15109), "SKINDEFAULT")); // the standard defaults.xml will be used!
320
321 // Search for colors in the Current skin!
322 vector<string> vecColors;
323 string strPath = URIUtils::AddFileToFolder(g_SkinInfo->Path(), "colors");
324
325 CFileItemList items;
326 CDirectory::GetDirectory(CSpecialProtocol::TranslatePathConvertCase(strPath), items, ".xml");
327 // Search for Themes in the Current skin!
328 for (int i = 0; i < items.Size(); ++i)
329 {
330 CFileItemPtr pItem = items[i];
331 if (!pItem->m_bIsFolder && !StringUtils::EqualsNoCase(pItem->GetLabel(), "defaults.xml"))
332 { // not the default one
333 vecColors.push_back(pItem->GetLabel().substr(0, pItem->GetLabel().size() - 4));
334 }
335 }
336 sort(vecColors.begin(), vecColors.end(), sortstringbyname());
337 for (int i = 0; i < (int) vecColors.size(); ++i)
338 list.push_back(make_pair(vecColors[i], vecColors[i]));
339
340 // try to find the best matching value
341 for (vector< pair<string, string> >::const_iterator it = list.begin(); it != list.end(); ++it)
342 {
343 if (StringUtils::EqualsNoCase(it->second, settingValue))
344 current = settingValue;
345 }
346}
347
348void CSkinInfo::SettingOptionsSkinFontsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data)
349{
350 std::string settingValue = ((const CSettingString*)setting)->GetValue();
351 bool currentValueSet = false;
352 std::string strPath = g_SkinInfo->GetSkinPath("Font.xml");
353
354 CXBMCTinyXML xmlDoc;
355 if (!xmlDoc.LoadFile(strPath))
356 {
357 CLog::Log(LOGERROR, "FillInSkinFonts: Couldn't load %s", strPath.c_str());
358 return;
359 }
360
361 const TiXmlElement* pRootElement = xmlDoc.RootElement();
362 if (!pRootElement || pRootElement->ValueStr() != "fonts")
363 {
364 CLog::Log(LOGERROR, "FillInSkinFonts: file %s doesn't start with <fonts>", strPath.c_str());
365 return;
366 }
367
368 const TiXmlElement *pChild = pRootElement->FirstChildElement("fontset");
369 while (pChild)
370 {
371 const char* idAttr = pChild->Attribute("id");
372 const char* idLocAttr = pChild->Attribute("idloc");
373 if (idAttr != NULL)
374 {
375 if (idLocAttr)
376 list.push_back(make_pair(g_localizeStrings.Get(atoi(idLocAttr)), idAttr));
377 else
378 list.push_back(make_pair(idAttr, idAttr));
379
380 if (StringUtils::EqualsNoCase(idAttr, settingValue))
381 currentValueSet = true;
382 }
383 pChild = pChild->NextSiblingElement("fontset");
384 }
385
386 if (list.empty())
387 { // Since no fontset is defined, there is no selection of a fontset, so disable the component
388 list.push_back(make_pair(g_localizeStrings.Get(13278), ""));
389 current = "";
390 currentValueSet = true;
391 }
392
393 if (!currentValueSet)
394 current = list[0].second;
395}
396
397void CSkinInfo::SettingOptionsSkinSoundFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data)
398{
399 std::string settingValue = ((const CSettingString*)setting)->GetValue();
400 current = "SKINDEFAULT";
401
402 //find skins...
403 CFileItemList items;
404 CDirectory::GetDirectory("special://xbmc/sounds/", items);
405 CDirectory::GetDirectory("special://home/sounds/", items);
406
407 vector<string> vecSoundSkins;
408 for (int i = 0; i < items.Size(); i++)
409 {
410 CFileItemPtr pItem = items[i];
411 if (pItem->m_bIsFolder)
412 {
413 if (StringUtils::EqualsNoCase(pItem->GetLabel(), ".svn") ||
414 StringUtils::EqualsNoCase(pItem->GetLabel(), "fonts") ||
415 StringUtils::EqualsNoCase(pItem->GetLabel(), "media"))
416 continue;
417
418 vecSoundSkins.push_back(pItem->GetLabel());
419 }
420 }
421
422 list.push_back(make_pair(g_localizeStrings.Get(474), "OFF"));
423 list.push_back(make_pair(g_localizeStrings.Get(15109), "SKINDEFAULT"));
424
425 sort(vecSoundSkins.begin(), vecSoundSkins.end(), sortstringbyname());
426 for (unsigned int i = 0; i < vecSoundSkins.size(); i++)
427 list.push_back(make_pair(vecSoundSkins[i], vecSoundSkins[i]));
428
429 // try to find the best matching value
430 for (vector< pair<string, string> >::const_iterator it = list.begin(); it != list.end(); ++it)
431 {
432 if (StringUtils::EqualsNoCase(it->second, settingValue))
433 current = settingValue;
434 }
435}
436
437void CSkinInfo::SettingOptionsSkinThemesFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data)
438{
439 // get the choosen theme and remove the extension from the current theme (backward compat)
440 std::string settingValue = ((const CSettingString*)setting)->GetValue();
441 URIUtils::RemoveExtension(settingValue);
442 current = "SKINDEFAULT";
443
444 // there is a default theme (just Textures.xpr/xbt)
445 // any other *.xpr|*.xbt files are additional themes on top of this one.
446
447 // add the default Label
448 list.push_back(make_pair(g_localizeStrings.Get(15109), "SKINDEFAULT")); // the standard Textures.xpr/xbt will be used
449
450 // search for themes in the current skin!
451 vector<std::string> vecTheme;
452 CUtil::GetSkinThemes(vecTheme);
453
454 // sort the themes for GUI and list them
455 for (int i = 0; i < (int) vecTheme.size(); ++i)
456 list.push_back(make_pair(vecTheme[i], vecTheme[i]));
457
458 // try to find the best matching value
459 for (vector< pair<string, string> >::const_iterator it = list.begin(); it != list.end(); ++it)
460 {
461 if (StringUtils::EqualsNoCase(it->second, settingValue))
462 current = settingValue;
463 }
464}
465
466void CSkinInfo::SettingOptionsStartupWindowsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current, void *data)
467{
468 int settingValue = ((const CSettingInt *)setting)->GetValue();
469 current = -1;
470
471 const vector<CStartupWindow> &startupWindows = g_SkinInfo->GetStartupWindows();
472
473 for (vector<CStartupWindow>::const_iterator it = startupWindows.begin(); it != startupWindows.end(); ++it)
474 {
475 string windowName = it->m_name;
476 if (StringUtils::IsNaturalNumber(windowName))
477 windowName = g_localizeStrings.Get(atoi(windowName.c_str()));
478 int windowID = it->m_id;
479
480 list.push_back(make_pair(windowName, windowID));
481
482 if (settingValue == windowID)
483 current = settingValue;
484 }
485
486 // if the current value hasn't been properly set, set it to the first window in the list
487 if (current < 0)
488 current = list[0].second;
489}
490
491} /*namespace ADDON*/
diff --git a/xbmc/addons/Skin.h b/xbmc/addons/Skin.h
new file mode 100644
index 0000000..42bddf8
--- /dev/null
+++ b/xbmc/addons/Skin.h
@@ -0,0 +1,155 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <vector>
24
25#include "Addon.h"
26#include "guilib/GraphicContext.h" // needed for the RESOLUTION members
27#include "guilib/GUIIncludes.h" // needed for the GUIInclude member
28#define CREDIT_LINE_LENGTH 50
29
30class CSetting;
31
32namespace ADDON
33{
34
35class CSkinInfo : public CAddon
36{
37public:
38 class CStartupWindow
39 {
40 public:
41 CStartupWindow(int id, const std::string &name):
42 m_id(id), m_name(name)
43 {
44 };
45 int m_id;
46 std::string m_name;
47 };
48
49 //FIXME remove this, kept for current repo handling
50 CSkinInfo(const AddonProps &props, const RESOLUTION_INFO &res = RESOLUTION_INFO());
51 CSkinInfo(const cp_extension_t *ext);
52 virtual ~CSkinInfo();
53 virtual AddonPtr Clone() const;
54
55 /*! \brief Load resultion information from directories in Path().
56 */
57 void Start();
58
59 bool HasSkinFile(const std::string &strFile) const;
60
61 /*! \brief Get the full path to the specified file in the skin
62 We search for XML files in the skin folder that best matches the current resolution.
63 \param file XML file to look for
64 \param res [out] If non-NULL, the resolution that the returned XML file is in is returned. Defaults to NULL.
65 \param baseDir [in] If non-empty, the given directory is searched instead of the skin's directory. Defaults to empty.
66 \return path to the XML file
67 */
68 std::string GetSkinPath(const std::string& file, RESOLUTION_INFO *res = NULL, const std::string& baseDir = "") const;
69
70 AddonVersion APIVersion() const { return m_version; };
71
72 /*! \brief Return whether skin debugging is enabled
73 \return true if skin debugging (set via <debugging>true</debugging> in skin.xml) is enabled.
74 */
75 bool IsDebugging() const { return m_debugging; };
76
77 /*! \brief Get the id of the first window to load
78 The first window is generally Startup.xml unless it doesn't exist or if the skinner
79 has specified which start windows they support and the user is going to somewhere other
80 than the home screen.
81 \return id of the first window to load
82 */
83 int GetFirstWindow() const;
84
85 /*! \brief Get the id of the window the user wants to start in after any skin animation
86 \return id of the start window
87 */
88 int GetStartWindow() const;
89
90 /*! \brief Translate a resolution string
91 \param name the string to translate
92 \param res [out] the resolution structure if name is valid
93 \return true if the resolution is valid, false otherwise
94 */
95 static bool TranslateResolution(const std::string &name, RESOLUTION_INFO &res);
96
97 void ResolveIncludes(TiXmlElement *node, std::map<INFO::InfoPtr, bool>* xmlIncludeConditions = NULL);
98
99 float GetEffectsSlowdown() const { return m_effectsSlowDown; };
100
101 const std::vector<CStartupWindow> &GetStartupWindows() const { return m_startupWindows; };
102
103 /*! \brief Retrieve the skin paths to search for skin XML files
104 \param paths [out] vector of paths to search, in order.
105 */
106 void GetSkinPaths(std::vector<std::string> &paths) const;
107
108 bool IsInUse() const;
109
110 const std::string& GetCurrentAspect() const { return m_currentAspect; }
111
112 void LoadIncludes();
113 const INFO::CSkinVariableString* CreateSkinVariable(const std::string& name, int context);
114
115 static void SettingOptionsSkinColorsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data);
116 static void SettingOptionsSkinFontsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data);
117 static void SettingOptionsSkinSoundFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data);
118 static void SettingOptionsSkinThemesFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, void *data);
119 static void SettingOptionsStartupWindowsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current, void *data);
120
121 virtual bool OnPreInstall();
122 virtual void OnPostInstall(bool restart, bool update, bool modal);
123protected:
124 /*! \brief Given a resolution, retrieve the corresponding directory name
125 \param res RESOLUTION to translate
126 \return directory name for res
127 */
128 std::string GetDirFromRes(RESOLUTION res) const;
129
130 /*! \brief grab a resolution tag from a skin's configuration data
131 \param props passed addoninfo structure to check for resolution
132 \param tag name of the tag to look for
133 \param res resolution to return
134 \return true if we find a valid resolution, false otherwise
135 */
136 void GetDefaultResolution(const cp_extension_t *ext, const char *tag, RESOLUTION &res, const RESOLUTION &def) const;
137
138 bool LoadStartupWindows(const cp_extension_t *ext);
139
140 RESOLUTION_INFO m_defaultRes;
141 std::vector<RESOLUTION_INFO> m_resolutions;
142
143 AddonVersion m_version;
144
145 float m_effectsSlowDown;
146 CGUIIncludes m_includes;
147 std::string m_currentAspect;
148
149 std::vector<CStartupWindow> m_startupWindows;
150 bool m_debugging;
151};
152
153} /*namespace ADDON*/
154
155extern std::shared_ptr<ADDON::CSkinInfo> g_SkinInfo;
diff --git a/xbmc/addons/Visualisation.cpp b/xbmc/addons/Visualisation.cpp
new file mode 100644
index 0000000..a64ee59
--- /dev/null
+++ b/xbmc/addons/Visualisation.cpp
@@ -0,0 +1,486 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#include "system.h"
21#include "Visualisation.h"
22#include "utils/fft.h"
23#include "GUIInfoManager.h"
24#include "Application.h"
25#include "guilib/GraphicContext.h"
26#include "guilib/WindowIDs.h"
27#include "music/tags/MusicInfoTag.h"
28#include "settings/Settings.h"
29#include "settings/AdvancedSettings.h"
30#include "settings/DisplaySettings.h"
31#include "windowing/WindowingFactory.h"
32#include "utils/URIUtils.h"
33#include "utils/StringUtils.h"
34#include "cores/IPlayer.h"
35#include "cores/AudioEngine/AEFactory.h"
36#ifdef TARGET_POSIX
37#include <dlfcn.h>
38#include "filesystem/SpecialProtocol.h"
39#endif
40
41using namespace std;
42using namespace MUSIC_INFO;
43using namespace ADDON;
44
45CAudioBuffer::CAudioBuffer(int iSize)
46{
47 m_iLen = iSize;
48 m_pBuffer = new float[iSize];
49}
50
51CAudioBuffer::~CAudioBuffer()
52{
53 delete [] m_pBuffer;
54}
55
56const float* CAudioBuffer::Get() const
57{
58 return m_pBuffer;
59}
60
61void CAudioBuffer::Set(const float* psBuffer, int iSize)
62{
63 if (iSize<0)
64 return;
65 memcpy(m_pBuffer, psBuffer, iSize * sizeof(float));
66 for (int i = iSize; i < m_iLen; ++i) m_pBuffer[i] = 0;
67}
68
69bool CVisualisation::Create(int x, int y, int w, int h, void *device)
70{
71 m_pInfo = new VIS_PROPS;
72 #ifdef HAS_DX
73 m_pInfo->device = g_Windowing.Get3DDevice();
74#else
75 m_pInfo->device = NULL;
76#endif
77 m_pInfo->x = x;
78 m_pInfo->y = y;
79 m_pInfo->width = w;
80 m_pInfo->height = h;
81 m_pInfo->pixelRatio = g_graphicsContext.GetResInfo().fPixelRatio;
82
83 m_pInfo->name = strdup(Name().c_str());
84 m_pInfo->presets = strdup(CSpecialProtocol::TranslatePath(Path()).c_str());
85 m_pInfo->profile = strdup(CSpecialProtocol::TranslatePath(Profile()).c_str());
86 m_pInfo->submodule = NULL;
87
88 if (CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Create() == ADDON_STATUS_OK)
89 {
90 // Start the visualisation
91 std::string strFile = URIUtils::GetFileName(g_application.CurrentFile());
92 CLog::Log(LOGDEBUG, "Visualisation::Start()\n");
93 try
94 {
95 m_pStruct->Start(m_iChannels, m_iSamplesPerSec, m_iBitsPerSample, strFile.c_str());
96 }
97 catch (std::exception e)
98 {
99 HandleException(e, "m_pStruct->Start() (CVisualisation::Create)");
100 return false;
101 }
102
103 GetPresets();
104
105 if (GetSubModules())
106 m_pInfo->submodule = strdup(CSpecialProtocol::TranslatePath(m_submodules.front()).c_str());
107 else
108 m_pInfo->submodule = NULL;
109
110 CreateBuffers();
111
112 CAEFactory::RegisterAudioCallback(this);
113
114 return true;
115 }
116 return false;
117}
118
119void CVisualisation::Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const std::string &strSongName)
120{
121 // notify visz. that new song has been started
122 // pass it the nr of audio channels, sample rate, bits/sample and offcourse the songname
123 if (Initialized())
124 {
125 try
126 {
127 m_pStruct->Start(iChannels, iSamplesPerSec, iBitsPerSample, strSongName.c_str());
128 }
129 catch (std::exception e)
130 {
131 HandleException(e, "m_pStruct->Start (CVisualisation::Start)");
132 }
133 }
134}
135
136void CVisualisation::AudioData(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
137{
138 // pass audio data to visz.
139 // audio data: is short audiodata [channel][iAudioDataLength] containing the raw audio data
140 // iAudioDataLength = length of audiodata array
141 // pFreqData = fft-ed audio data
142 // iFreqDataLength = length of pFreqData
143 if (Initialized())
144 {
145 try
146 {
147 m_pStruct->AudioData(pAudioData, iAudioDataLength, pFreqData, iFreqDataLength);
148 }
149 catch (std::exception e)
150 {
151 HandleException(e, "m_pStruct->AudioData (CVisualisation::AudioData)");
152 }
153 }
154}
155
156void CVisualisation::Render()
157{
158 // ask visz. to render itself
159 g_graphicsContext.BeginPaint();
160 if (Initialized())
161 {
162 try
163 {
164 m_pStruct->Render();
165 }
166 catch (std::exception e)
167 {
168 HandleException(e, "m_pStruct->Render (CVisualisation::Render)");
169 }
170 }
171 g_graphicsContext.EndPaint();
172}
173
174void CVisualisation::Stop()
175{
176 CAEFactory::UnregisterAudioCallback();
177 if (Initialized())
178 {
179 CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Stop();
180 }
181}
182
183void CVisualisation::GetInfo(VIS_INFO *info)
184{
185 if (Initialized())
186 {
187 try
188 {
189 m_pStruct->GetInfo(info);
190 }
191 catch (std::exception e)
192 {
193 HandleException(e, "m_pStruct->GetInfo (CVisualisation::GetInfo)");
194 }
195 }
196}
197
198bool CVisualisation::OnAction(VIS_ACTION action, void *param)
199{
200 if (!Initialized())
201 return false;
202
203 // see if vis wants to handle the input
204 // returns false if vis doesnt want the input
205 // returns true if vis handled the input
206 try
207 {
208 if (action != VIS_ACTION_NONE && m_pStruct->OnAction)
209 {
210 // if this is a VIS_ACTION_UPDATE_TRACK action, copy relevant
211 // tags from CMusicInfoTag to VisTag
212 if ( action == VIS_ACTION_UPDATE_TRACK && param )
213 {
214 const CMusicInfoTag* tag = (const CMusicInfoTag*)param;
215 std::string artist(StringUtils::Join(tag->GetArtist(), g_advancedSettings.m_musicItemSeparator));
216 std::string albumArtist(StringUtils::Join(tag->GetAlbumArtist(), g_advancedSettings.m_musicItemSeparator));
217 std::string genre(StringUtils::Join(tag->GetGenre(), g_advancedSettings.m_musicItemSeparator));
218
219 VisTrack track;
220 track.title = tag->GetTitle().c_str();
221 track.artist = artist.c_str();
222 track.album = tag->GetAlbum().c_str();
223 track.albumArtist = albumArtist.c_str();
224 track.genre = genre.c_str();
225 track.comment = tag->GetComment().c_str();
226 track.lyrics = tag->GetLyrics().c_str();
227 track.trackNumber = tag->GetTrackNumber();
228 track.discNumber = tag->GetDiscNumber();
229 track.duration = tag->GetDuration();
230 track.year = tag->GetYear();
231 track.rating = tag->GetRating();
232
233 return m_pStruct->OnAction(action, &track);
234 }
235 return m_pStruct->OnAction((int)action, param);
236 }
237 }
238 catch (std::exception e)
239 {
240 HandleException(e, "m_pStruct->OnAction (CVisualisation::OnAction)");
241 }
242 return false;
243}
244
245void CVisualisation::OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample)
246{
247 if (!m_pStruct)
248 return ;
249 CLog::Log(LOGDEBUG, "OnInitialize() started");
250
251 m_iChannels = iChannels;
252 m_iSamplesPerSec = iSamplesPerSec;
253 m_iBitsPerSample = iBitsPerSample;
254 UpdateTrack();
255
256 CLog::Log(LOGDEBUG, "OnInitialize() done");
257}
258
259void CVisualisation::OnAudioData(const float* pAudioData, int iAudioDataLength)
260{
261 if (!m_pStruct)
262 return ;
263
264 // FIXME: iAudioDataLength should never be less than 0
265 if (iAudioDataLength<0)
266 return;
267
268 // Save our audio data in the buffers
269 unique_ptr<CAudioBuffer> pBuffer ( new CAudioBuffer(AUDIO_BUFFER_SIZE) );
270 pBuffer->Set(pAudioData, iAudioDataLength);
271 m_vecBuffers.push_back( pBuffer.release() );
272
273 if ( (int)m_vecBuffers.size() < m_iNumBuffers) return ;
274
275 unique_ptr<CAudioBuffer> ptrAudioBuffer ( m_vecBuffers.front() );
276 m_vecBuffers.pop_front();
277 // Fourier transform the data if the vis wants it...
278 if (m_bWantsFreq)
279 {
280 const float *psAudioData = ptrAudioBuffer->Get();
281 memcpy(m_fFreq, psAudioData, AUDIO_BUFFER_SIZE * sizeof(float));
282
283 // FFT the data
284 twochanwithwindow(m_fFreq, AUDIO_BUFFER_SIZE);
285
286 // Normalize the data
287 float fMinData = (float)AUDIO_BUFFER_SIZE * AUDIO_BUFFER_SIZE * 3 / 8 * 0.5 * 0.5; // 3/8 for the Hann window, 0.5 as minimum amplitude
288 float fInvMinData = 1.0f/fMinData;
289 for (int i = 0; i < AUDIO_BUFFER_SIZE + 2; i++)
290 {
291 m_fFreq[i] *= fInvMinData;
292 }
293
294 // Transfer data to our visualisation
295 AudioData(psAudioData, AUDIO_BUFFER_SIZE, m_fFreq, AUDIO_BUFFER_SIZE);
296 }
297 else
298 { // Transfer data to our visualisation
299 AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, NULL, 0);
300 }
301 return ;
302}
303
304void CVisualisation::CreateBuffers()
305{
306 ClearBuffers();
307
308 // Get the number of buffers from the current vis
309 VIS_INFO info;
310 m_pStruct->GetInfo(&info);
311 m_iNumBuffers = info.iSyncDelay + 1;
312 m_bWantsFreq = (info.bWantsFreq != 0);
313 if (m_iNumBuffers > MAX_AUDIO_BUFFERS)
314 m_iNumBuffers = MAX_AUDIO_BUFFERS;
315 if (m_iNumBuffers < 1)
316 m_iNumBuffers = 1;
317}
318
319void CVisualisation::ClearBuffers()
320{
321 m_bWantsFreq = false;
322 m_iNumBuffers = 0;
323
324 while (!m_vecBuffers.empty())
325 {
326 CAudioBuffer* pAudioBuffer = m_vecBuffers.front();
327 delete pAudioBuffer;
328 m_vecBuffers.pop_front();
329 }
330 for (int j = 0; j < AUDIO_BUFFER_SIZE*2; j++)
331 {
332 m_fFreq[j] = 0.0f;
333 }
334}
335
336bool CVisualisation::UpdateTrack()
337{
338 bool handled = false;
339 if (Initialized())
340 {
341 // get the current album art filename
342 m_AlbumThumb = CSpecialProtocol::TranslatePath(g_infoManager.GetImage(MUSICPLAYER_COVER, WINDOW_INVALID));
343
344 // get the current track tag
345 const CMusicInfoTag* tag = g_infoManager.GetCurrentSongTag();
346
347 if (m_AlbumThumb == "DefaultAlbumCover.png")
348 m_AlbumThumb = "";
349 else
350 CLog::Log(LOGDEBUG,"Updating visualisation albumart: %s", m_AlbumThumb.c_str());
351
352 // inform the visualisation of the current album art
353 if (OnAction( VIS_ACTION_UPDATE_ALBUMART, (void*)( m_AlbumThumb.c_str() ) ) )
354 handled = true;
355
356 // inform the visualisation of the current track's tag information
357 if ( tag && OnAction( VIS_ACTION_UPDATE_TRACK, (void*)tag ) )
358 handled = true;
359 }
360 return handled;
361}
362
363bool CVisualisation::GetPresetList(std::vector<std::string> &vecpresets)
364{
365 vecpresets = m_presets;
366 return !m_presets.empty();
367}
368
369bool CVisualisation::GetPresets()
370{
371 m_presets.clear();
372 char **presets = NULL;
373 unsigned int entries = 0;
374 try
375 {
376 entries = m_pStruct->GetPresets(&presets);
377 }
378 catch (std::exception e)
379 {
380 HandleException(e, "m_pStruct->OnAction (CVisualisation::GetPresets)");
381 return false;
382 }
383 if (presets && entries > 0)
384 {
385 for (unsigned i=0; i < entries; i++)
386 {
387 if (presets[i])
388 {
389 m_presets.push_back(presets[i]);
390 }
391 }
392 }
393 return (!m_presets.empty());
394}
395
396bool CVisualisation::GetSubModuleList(std::vector<std::string> &vecmodules)
397{
398 vecmodules = m_submodules;
399 return !m_submodules.empty();
400}
401
402bool CVisualisation::GetSubModules()
403{
404 m_submodules.clear();
405 char **modules = NULL;
406 unsigned int entries = 0;
407 try
408 {
409 entries = m_pStruct->GetSubModules(&modules);
410 }
411 catch (...)
412 {
413 CLog::Log(LOGERROR, "Exception in Visualisation::GetSubModules()");
414 return false;
415 }
416 if (modules && entries > 0)
417 {
418 for (unsigned i=0; i < entries; i++)
419 {
420 if (modules[i])
421 {
422 m_submodules.push_back(modules[i]);
423 }
424 }
425 }
426 return (!m_submodules.empty());
427}
428
429std::string CVisualisation::GetFriendlyName(const std::string& strVisz,
430 const std::string& strSubModule)
431{
432 // should be of the format "moduleName (visName)"
433 return strSubModule + " (" + strVisz + ")";
434}
435
436bool CVisualisation::IsLocked()
437{
438 if (!m_presets.empty())
439 {
440 if (!m_pStruct)
441 return false;
442
443 return m_pStruct->IsLocked();
444 }
445 return false;
446}
447
448void CVisualisation::Destroy()
449{
450 // Free what was allocated in method CVisualisation::Create
451 if (m_pInfo)
452 {
453 free((void *) m_pInfo->name);
454 free((void *) m_pInfo->presets);
455 free((void *) m_pInfo->profile);
456 free((void *) m_pInfo->submodule);
457
458 delete m_pInfo;
459 m_pInfo = NULL;
460 }
461
462 CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Destroy();
463}
464
465unsigned CVisualisation::GetPreset()
466{
467 unsigned index = 0;
468 try
469 {
470 index = m_pStruct->GetPreset();
471 }
472 catch(...)
473 {
474 return 0;
475 }
476 return index;
477}
478
479std::string CVisualisation::GetPresetName()
480{
481 if (!m_presets.empty())
482 return m_presets[GetPreset()];
483 else
484 return "";
485}
486
diff --git a/xbmc/addons/Visualisation.h b/xbmc/addons/Visualisation.h
new file mode 100644
index 0000000..0a2a1cb
--- /dev/null
+++ b/xbmc/addons/Visualisation.h
@@ -0,0 +1,111 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20#pragma once
21
22#include "AddonDll.h"
23#include "cores/IAudioCallback.h"
24#include "include/xbmc_vis_types.h"
25#include "guilib/IRenderingCallback.h"
26
27#include <map>
28#include <list>
29#include <memory>
30
31#define AUDIO_BUFFER_SIZE 512 // MUST BE A POWER OF 2!!!
32#define MAX_AUDIO_BUFFERS 16
33
34class CCriticalSection;
35
36typedef DllAddon<Visualisation, VIS_PROPS> DllVisualisation;
37
38class CAudioBuffer
39{
40public:
41 CAudioBuffer(int iSize);
42 virtual ~CAudioBuffer();
43 const float* Get() const;
44 void Set(const float* psBuffer, int iSize);
45private:
46 CAudioBuffer();
47 float* m_pBuffer;
48 int m_iLen;
49};
50
51namespace ADDON
52{
53 class CVisualisation : public CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>
54 , public IAudioCallback
55 , public IRenderingCallback
56 {
57 public:
58 CVisualisation(const ADDON::AddonProps &props) : CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>(props) {}
59 CVisualisation(const cp_extension_t *ext) : CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>(ext) {}
60 virtual void OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample);
61 virtual void OnAudioData(const float* pAudioData, int iAudioDataLength);
62 bool Create(int x, int y, int w, int h, void *device);
63 void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const std::string &strSongName);
64 void AudioData(const float *pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength);
65 void Render();
66 void Stop();
67 void GetInfo(VIS_INFO *info);
68 bool OnAction(VIS_ACTION action, void *param = NULL);
69 bool UpdateTrack();
70 bool HasSubModules() { return !m_submodules.empty(); }
71 bool IsLocked();
72 unsigned GetPreset();
73 std::string GetPresetName();
74 bool GetPresetList(std::vector<std::string>& vecpresets);
75 bool GetSubModuleList(std::vector<std::string>& vecmodules);
76 static std::string GetFriendlyName(const std::string& vis, const std::string& module);
77 void Destroy();
78
79 private:
80 void CreateBuffers();
81 void ClearBuffers();
82
83 bool GetPresets();
84 bool GetSubModules();
85
86 // attributes of the viewport we render to
87 int m_xPos;
88 int m_yPos;
89 int m_width;
90 int m_height;
91
92 // cached preset list
93 std::vector<std::string> m_presets;
94 // cached submodule list
95 std::vector<std::string> m_submodules;
96 int m_currentModule;
97
98 // audio properties
99 int m_iChannels;
100 int m_iSamplesPerSec;
101 int m_iBitsPerSample;
102 std::list<CAudioBuffer*> m_vecBuffers;
103 int m_iNumBuffers; // Number of Audio buffers
104 bool m_bWantsFreq;
105 float m_fFreq[2*AUDIO_BUFFER_SIZE]; // Frequency data
106 bool m_bCalculate_Freq; // True if the vis wants freq data
107
108 // track information
109 std::string m_AlbumThumb;
110 };
111}
diff --git a/xbmc/addons/Webinterface.cpp b/xbmc/addons/Webinterface.cpp
new file mode 100644
index 0000000..5745b1c
--- /dev/null
+++ b/xbmc/addons/Webinterface.cpp
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2015 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "Webinterface.h"
22#include "addons/AddonManager.h"
23#include "utils/log.h"
24#include "utils/StringUtils.h"
25#include "utils/URIUtils.h"
26
27using namespace ADDON;
28
29CWebinterface::CWebinterface(const ADDON::AddonProps &props, WebinterfaceType type /* = WebinterfaceTypeStatic */, const std::string &entryPoint /* = "WEBINTERFACE_DEFAULT_ENTRY_POINT" */)
30 : CAddon(props),
31 m_type(type),
32 m_entryPoint(entryPoint)
33{ }
34
35CWebinterface::CWebinterface(const cp_extension_t *ext)
36 : CAddon(ext),
37 m_type(WebinterfaceTypeStatic),
38 m_entryPoint(WEBINTERFACE_DEFAULT_ENTRY_POINT)
39{
40 // determine the type of the webinterface
41 std::string webinterfaceType = CAddonMgr::Get().GetExtValue(ext->configuration, "@type");
42 if (StringUtils::EqualsNoCase(webinterfaceType.c_str(), "wsgi"))
43 m_type = WebinterfaceTypeWsgi;
44 else if (!webinterfaceType.empty() && !StringUtils::EqualsNoCase(webinterfaceType.c_str(), "static") && !StringUtils::EqualsNoCase(webinterfaceType.c_str(), "html"))
45 CLog::Log(LOGWARNING, "Webinterface addon \"%s\" has specified an unsupported type \"%s\"", ID().c_str(), webinterfaceType.c_str());
46
47 // determine the entry point of the webinterface
48 std::string entryPoint = CAddonMgr::Get().GetExtValue(ext->configuration, "@entry");
49 if (!entryPoint.empty())
50 m_entryPoint = entryPoint;
51}
52
53CWebinterface::~CWebinterface()
54{ }
55
56std::string CWebinterface::GetEntryPoint(const std::string &path) const
57{
58 if (m_type == WebinterfaceTypeWsgi)
59 return LibPath();
60
61 return URIUtils::AddFileToFolder(path, m_entryPoint);
62}
63
64std::string CWebinterface::GetBaseLocation() const
65{
66 if (m_type == WebinterfaceTypeWsgi)
67 return "/addons/" + ID();
68
69 return "";
70}
71
72AddonPtr CWebinterface::Clone() const
73{
74 return AddonPtr(new CWebinterface(*this));
75} \ No newline at end of file
diff --git a/xbmc/addons/Webinterface.h b/xbmc/addons/Webinterface.h
new file mode 100644
index 0000000..0a4773f
--- /dev/null
+++ b/xbmc/addons/Webinterface.h
@@ -0,0 +1,54 @@
1#pragma once
2/*
3 * Copyright (C) 2015 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "Addon.h"
23
24#define WEBINTERFACE_DEFAULT_ENTRY_POINT "index.html"
25
26namespace ADDON
27{
28 typedef enum WebinterfaceType
29 {
30 WebinterfaceTypeStatic = 0,
31 WebinterfaceTypeWsgi
32 } WebinterfaceType;
33
34 class CWebinterface : public CAddon
35 {
36 public:
37 explicit CWebinterface(const ADDON::AddonProps &props, WebinterfaceType type = WebinterfaceTypeStatic, const std::string &entryPoint = WEBINTERFACE_DEFAULT_ENTRY_POINT);
38 explicit CWebinterface(const cp_extension_t *ext);
39 virtual ~CWebinterface();
40
41 WebinterfaceType GetType() const { return m_type; }
42 const std::string& EntryPoint() const { return m_entryPoint; }
43
44 std::string GetEntryPoint(const std::string &path) const;
45 std::string GetBaseLocation() const;
46
47 // specializations of CAddon
48 virtual AddonPtr Clone() const;
49
50 private:
51 WebinterfaceType m_type;
52 std::string m_entryPoint;
53 };
54}
diff --git a/xbmc/addons/addon-bindings.mk b/xbmc/addons/addon-bindings.mk
new file mode 100644
index 0000000..50d75bc
--- /dev/null
+++ b/xbmc/addons/addon-bindings.mk
@@ -0,0 +1,20 @@
1BINDINGS =xbmc/addons/include/xbmc_addon_cpp_dll.h
2BINDINGS+=xbmc/addons/include/xbmc_addon_dll.h
3BINDINGS+=xbmc/addons/include/xbmc_addon_types.h
4BINDINGS+=xbmc/addons/include/xbmc_audioenc_dll.h
5BINDINGS+=xbmc/addons/include/xbmc_audioenc_types.h
6BINDINGS+=xbmc/addons/include/xbmc_codec_types.h
7BINDINGS+=xbmc/addons/include/xbmc_epg_types.h
8BINDINGS+=xbmc/addons/include/xbmc_pvr_dll.h
9BINDINGS+=xbmc/addons/include/xbmc_pvr_types.h
10BINDINGS+=xbmc/addons/include/xbmc_scr_dll.h
11BINDINGS+=xbmc/addons/include/xbmc_scr_types.h
12BINDINGS+=xbmc/addons/include/xbmc_vis_dll.h
13BINDINGS+=xbmc/addons/include/xbmc_vis_types.h
14BINDINGS+=xbmc/addons/include/xbmc_stream_utils.hpp
15BINDINGS+=addons/library.xbmc.addon/libXBMC_addon.h
16BINDINGS+=addons/library.xbmc.gui/libXBMC_gui.h
17BINDINGS+=addons/library.xbmc.pvr/libXBMC_pvr.h
18BINDINGS+=addons/library.xbmc.codec/libXBMC_codec.h
19BINDINGS+=xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
20
diff --git a/xbmc/addons/include/NOTE b/xbmc/addons/include/NOTE
new file mode 100644
index 0000000..dbcc329
--- /dev/null
+++ b/xbmc/addons/include/NOTE
@@ -0,0 +1,12 @@
1NOTE:
2
3This directory contains independent Headers to build Add-on's
4without the whole XBMC source tree. The Add-on itself can add
5this headers to his source tree without dependencies to any
6XBMC related classes or functions.
7
8Also this headers are never changed without a API Version
9change.
10
11The current PVR API version can be found in xbmc_pvr_types.h:
12XBMC_PVR_API_VERSION
diff --git a/xbmc/addons/include/xbmc_addon_cpp_dll.h b/xbmc/addons/include/xbmc_addon_cpp_dll.h
new file mode 100644
index 0000000..3944525
--- /dev/null
+++ b/xbmc/addons/include/xbmc_addon_cpp_dll.h
@@ -0,0 +1,191 @@
1#ifndef __XBMC_ADDON_CPP_H__
2#define __XBMC_ADDON_CPP_H__
3
4/*
5 * Copyright (C) 2005-2013 Team XBMC
6 * http://xbmc.org
7 *
8 * This Program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This Program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with XBMC; see the file COPYING. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include "xbmc_addon_types.h"
25
26#include <vector>
27#include <string.h>
28#include <stdlib.h>
29
30class DllSetting
31{
32public:
33 enum SETTING_TYPE { NONE=0, CHECK, SPIN };
34
35 DllSetting(SETTING_TYPE t, const char *n, const char *l)
36 {
37 id = NULL;
38 label = NULL;
39 if (n)
40 {
41 id = new char[strlen(n)+1];
42 strcpy(id, n);
43 }
44 if (l)
45 {
46 label = new char[strlen(l)+1];
47 strcpy(label, l);
48 }
49 current = 0;
50 type = t;
51 }
52
53 DllSetting(const DllSetting &rhs) // copy constructor
54 {
55 id = NULL;
56 label = NULL;
57 if (rhs.id)
58 {
59 id = new char[strlen(rhs.id)+1];
60 strcpy(id, rhs.id);
61 }
62 if (rhs.label)
63 {
64 label = new char[strlen(rhs.label)+1];
65 strcpy(label, rhs.label);
66 }
67 current = rhs.current;
68 type = rhs.type;
69 for (unsigned int i = 0; i < rhs.entry.size(); i++)
70 {
71 char *lab = new char[strlen(rhs.entry[i]) + 1];
72 strcpy(lab, rhs.entry[i]);
73 entry.push_back(lab);
74 }
75 }
76
77 ~DllSetting()
78 {
79 delete[] id;
80 delete[] label;
81 for (unsigned int i=0; i < entry.size(); i++)
82 delete[] entry[i];
83 }
84
85 void AddEntry(const char *label)
86 {
87 if (!label || type != SPIN) return;
88 char *lab = new char[strlen(label) + 1];
89 strcpy(lab, label);
90 entry.push_back(lab);
91 }
92
93 // data members
94 SETTING_TYPE type;
95 char* id;
96 char* label;
97 int current;
98 std::vector<const char *> entry;
99};
100
101class DllUtils
102{
103public:
104
105 static unsigned int VecToStruct(std::vector<DllSetting> &vecSet, ADDON_StructSetting*** sSet)
106 {
107 *sSet = NULL;
108 if(vecSet.size() == 0)
109 return 0;
110
111 unsigned int uiElements=0;
112
113 *sSet = (ADDON_StructSetting**)malloc(vecSet.size()*sizeof(ADDON_StructSetting*));
114 for(unsigned int i=0;i<vecSet.size();i++)
115 {
116 (*sSet)[i] = NULL;
117 (*sSet)[i] = (ADDON_StructSetting*)malloc(sizeof(ADDON_StructSetting));
118 (*sSet)[i]->id = NULL;
119 (*sSet)[i]->label = NULL;
120 uiElements++;
121
122 if (vecSet[i].id && vecSet[i].label)
123 {
124 (*sSet)[i]->id = strdup(vecSet[i].id);
125 (*sSet)[i]->label = strdup(vecSet[i].label);
126 (*sSet)[i]->type = vecSet[i].type;
127 (*sSet)[i]->current = vecSet[i].current;
128 (*sSet)[i]->entry_elements = 0;
129 (*sSet)[i]->entry = NULL;
130 if(vecSet[i].type == DllSetting::SPIN && vecSet[i].entry.size() > 0)
131 {
132 (*sSet)[i]->entry = (char**)malloc(vecSet[i].entry.size()*sizeof(char**));
133 for(unsigned int j=0;j<vecSet[i].entry.size();j++)
134 {
135 if(strlen(vecSet[i].entry[j]) > 0)
136 {
137 (*sSet)[i]->entry[j] = strdup(vecSet[i].entry[j]);
138 (*sSet)[i]->entry_elements++;
139 }
140 }
141 }
142 }
143 }
144 return uiElements;
145 }
146
147 static void StructToVec(unsigned int iElements, ADDON_StructSetting*** sSet, std::vector<DllSetting> *vecSet)
148 {
149 if(iElements == 0)
150 return;
151
152 vecSet->clear();
153 for(unsigned int i=0;i<iElements;i++)
154 {
155 DllSetting vSet((DllSetting::SETTING_TYPE)(*sSet)[i]->type, (*sSet)[i]->id, (*sSet)[i]->label);
156 if((*sSet)[i]->type == DllSetting::SPIN)
157 {
158 for(unsigned int j=0;j<(*sSet)[i]->entry_elements;j++)
159 {
160 vSet.AddEntry((*sSet)[i]->entry[j]);
161 }
162 }
163 vSet.current = (*sSet)[i]->current;
164 vecSet->push_back(vSet);
165 }
166 }
167
168 static void FreeStruct(unsigned int iElements, ADDON_StructSetting*** sSet)
169 {
170 if(iElements == 0)
171 return;
172
173 for(unsigned int i=0;i<iElements;i++)
174 {
175 if((*sSet)[i]->type == DllSetting::SPIN)
176 {
177 for(unsigned int j=0;j<(*sSet)[i]->entry_elements;j++)
178 {
179 free((*sSet)[i]->entry[j]);
180 }
181 free((*sSet)[i]->entry);
182 }
183 free((*sSet)[i]->id);
184 free((*sSet)[i]->label);
185 free((*sSet)[i]);
186 }
187 free(*sSet);
188 }
189};
190
191#endif
diff --git a/xbmc/addons/include/xbmc_addon_dll.h b/xbmc/addons/include/xbmc_addon_dll.h
new file mode 100644
index 0000000..fa6415f
--- /dev/null
+++ b/xbmc/addons/include/xbmc_addon_dll.h
@@ -0,0 +1,55 @@
1#ifndef __XBMC_ADDON_DLL_H__
2#define __XBMC_ADDON_DLL_H__
3
4/*
5 * Copyright (C) 2005-2013 Team XBMC
6 * http://xbmc.org
7 *
8 * This Program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This Program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with XBMC; see the file COPYING. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#ifdef TARGET_WINDOWS
25#include <windows.h>
26#else
27#ifndef __cdecl
28#define __cdecl
29#endif
30#ifndef __declspec
31#define __declspec(X)
32#endif
33#endif
34
35#include "xbmc_addon_types.h"
36
37#ifdef __cplusplus
38extern "C" {
39#endif
40
41 ADDON_STATUS __declspec(dllexport) ADDON_Create(void *callbacks, void* props);
42 void __declspec(dllexport) ADDON_Stop();
43 void __declspec(dllexport) ADDON_Destroy();
44 ADDON_STATUS __declspec(dllexport) ADDON_GetStatus();
45 bool __declspec(dllexport) ADDON_HasSettings();
46 unsigned int __declspec(dllexport) ADDON_GetSettings(ADDON_StructSetting ***sSet);
47 ADDON_STATUS __declspec(dllexport) ADDON_SetSetting(const char *settingName, const void *settingValue);
48 void __declspec(dllexport) ADDON_FreeSettings();
49 void __declspec(dllexport) ADDON_Announce(const char *flag, const char *sender, const char *message, const void *data);
50
51#ifdef __cplusplus
52};
53#endif
54
55#endif
diff --git a/xbmc/addons/include/xbmc_addon_types.h b/xbmc/addons/include/xbmc_addon_types.h
new file mode 100644
index 0000000..bd6cbe8
--- /dev/null
+++ b/xbmc/addons/include/xbmc_addon_types.h
@@ -0,0 +1,64 @@
1#ifndef __XBMC_ADDON_TYPES_H__
2#define __XBMC_ADDON_TYPES_H__
3
4/*
5 * Copyright (C) 2005-2013 Team XBMC
6 * http://xbmc.org
7 *
8 * This Program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This Program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with XBMC; see the file COPYING. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#ifdef __cplusplus
25extern "C" {
26#endif
27
28enum ADDON_STATUS
29{
30 ADDON_STATUS_OK,
31 ADDON_STATUS_LOST_CONNECTION,
32 ADDON_STATUS_NEED_RESTART,
33 ADDON_STATUS_NEED_SETTINGS,
34 ADDON_STATUS_UNKNOWN,
35 ADDON_STATUS_NEED_SAVEDSETTINGS,
36 ADDON_STATUS_PERMANENT_FAILURE /**< permanent failure, like failing to resolve methods */
37};
38
39typedef struct
40{
41 int type;
42 char* id;
43 char* label;
44 int current;
45 char** entry;
46 unsigned int entry_elements;
47} ADDON_StructSetting;
48
49/*!
50 * @brief Handle used to return data from the PVR add-on to CPVRClient
51 */
52struct ADDON_HANDLE_STRUCT
53{
54 void *callerAddress; /*!< address of the caller */
55 void *dataAddress; /*!< address to store data in */
56 int dataIdentifier; /*!< parameter to pass back when calling the callback */
57};
58typedef ADDON_HANDLE_STRUCT *ADDON_HANDLE;
59
60#ifdef __cplusplus
61};
62#endif
63
64#endif
diff --git a/xbmc/addons/include/xbmc_audioenc_dll.h b/xbmc/addons/include/xbmc_audioenc_dll.h
new file mode 100644
index 0000000..01e8d12
--- /dev/null
+++ b/xbmc/addons/include/xbmc_audioenc_dll.h
@@ -0,0 +1,61 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef __XBMC_AUDIOENC_H__
23#define __XBMC_AUDIOENC_H__
24
25#include <stdint.h>
26#include "xbmc_addon_dll.h"
27#include "xbmc_audioenc_types.h"
28
29extern "C"
30{
31 //! \copydoc AudioEncoder::Create
32 void* Create(audioenc_callbacks *callbacks);
33
34 //! \copydoc AudioEncoder::Start
35 bool Start(void* context, int iInChannels, int iInRate, int iInBits,
36 const char* title, const char* artist,
37 const char* albumartist, const char* album,
38 const char* year, const char* track,
39 const char* genre, const char* comment, int iTrackLength);
40
41 //! \copydoc AudioEncoder::Encode
42 int Encode(void* context, int nNumBytesRead, uint8_t* pbtStream);
43
44 //! \copydoc AudioEncoder::Finish
45 bool Finish(void* context);
46
47 //! \copydoc AudioEncoder::Free
48 void Free(void* context);
49
50 // function to export the above structure to XBMC
51 void __declspec(dllexport) get_addon(struct AudioEncoder* pScr)
52 {
53 pScr->Create = Create;
54 pScr->Start = Start;
55 pScr->Encode = Encode;
56 pScr->Finish = Finish;
57 pScr->Free = Free;
58 };
59};
60
61#endif
diff --git a/xbmc/addons/include/xbmc_audioenc_types.h b/xbmc/addons/include/xbmc_audioenc_types.h
new file mode 100644
index 0000000..aa527db
--- /dev/null
+++ b/xbmc/addons/include/xbmc_audioenc_types.h
@@ -0,0 +1,113 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef __AUDIOENC_TYPES_H__
23#define __AUDIOENC_TYPES_H__
24
25#ifdef TARGET_WINDOWS
26#include <windows.h>
27#else
28#ifndef __cdecl
29#define __cdecl
30#endif
31#ifndef __declspec
32#define __declspec(X)
33#endif
34#endif
35
36#include <stdint.h>
37
38extern "C"
39{
40 struct AUDIOENC_INFO
41 {
42 int dummy;
43 };
44
45 struct AUDIOENC_PROPS
46 {
47 int dummy;
48 };
49
50 typedef int (*audioenc_write_callback)(void* opaque, uint8_t* data, int len);
51 typedef int64_t (*audioenc_seek_callback)(void* opaque, int64_t pos, int whence);
52
53 typedef struct
54 {
55 void* opaque;
56 audioenc_write_callback write;
57 audioenc_seek_callback seek;
58 } audioenc_callbacks;
59
60 struct AudioEncoder
61 {
62 /*! \brief Create encoder context
63 \param callbacks Pointer to audioenc_callbacks structure.
64 \return opaque pointer to encoder context, to be passed to other methods.
65 \sa IEncoder::Init
66 */
67 void (*(__cdecl *Create) (audioenc_callbacks* callbacks));
68
69 /*! \brief Start encoder
70 \param context Encoder context from Create.
71 \param iInChannels Number of channels
72 \param iInRate Sample rate of input data
73 \param iInBits Bits per sample in input data
74 \param title The title of the song
75 \param artist The artist of the song
76 \param albumartist The albumartist of the song
77 \param year The year of the song
78 \param track The track number of the song
79 \param genre The genre of the song
80 \param comment A comment to attach to the song
81 \param iTrackLength Total track length in seconds
82 \sa IEncoder::Init
83 */
84 bool (__cdecl* Start) (void* context, int iInChannels, int iInRate, int iInBits,
85 const char* title, const char* artist,
86 const char* albumartist, const char* album,
87 const char* year, const char* track,
88 const char* genre, const char* comment,
89 int iTrackLength);
90
91 /*! \brief Encode a chunk of audio
92 \param context Encoder context from Create.
93 \param nNumBytesRead Number of bytes in input buffer
94 \param pbtStream the input buffer
95 \return Number of bytes consumed
96 \sa IEncoder::Encode
97 */
98 int (__cdecl* Encode) (void* context, int nNumBytesRead, uint8_t* pbtStream);
99
100 /*! \brief Finalize encoding
101 \param context Encoder context from Create.
102 \return True on success, false on failure.
103 */
104 bool (__cdecl* Finish) (void* context);
105
106 /*! \brief Free encoder context
107 \param context Encoder context to free.
108 */
109 void (__cdecl* Free)(void* context);
110 };
111}
112
113#endif
diff --git a/xbmc/addons/include/xbmc_codec_types.h b/xbmc/addons/include/xbmc_codec_types.h
new file mode 100644
index 0000000..98003e0
--- /dev/null
+++ b/xbmc/addons/include/xbmc_codec_types.h
@@ -0,0 +1,55 @@
1#ifndef __XBMC_CODEC_TYPES_H__
2#define __XBMC_CODEC_TYPES_H__
3
4/*
5 * Copyright (C) 2005-2013 Team XBMC
6 * http://xbmc.org
7 *
8 * This Program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This Program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with XBMC; see the file COPYING. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#ifdef __cplusplus
25extern "C" {
26#endif
27
28typedef unsigned int xbmc_codec_id_t;
29
30typedef enum
31{
32 XBMC_CODEC_TYPE_UNKNOWN = -1,
33 XBMC_CODEC_TYPE_VIDEO,
34 XBMC_CODEC_TYPE_AUDIO,
35 XBMC_CODEC_TYPE_DATA,
36 XBMC_CODEC_TYPE_SUBTITLE,
37 XBMC_CODEC_TYPE_RDS,
38 XBMC_CODEC_TYPE_NB
39} xbmc_codec_type_t;
40
41typedef struct
42{
43 xbmc_codec_type_t codec_type;
44 xbmc_codec_id_t codec_id;
45} xbmc_codec_t;
46
47#define XBMC_INVALID_CODEC_ID 0
48#define XBMC_INVALID_CODEC { XBMC_CODEC_TYPE_UNKNOWN, XBMC_INVALID_CODEC_ID }
49
50#ifdef __cplusplus
51};
52#endif
53
54#endif
55
diff --git a/xbmc/addons/include/xbmc_epg_types.h b/xbmc/addons/include/xbmc_epg_types.h
new file mode 100644
index 0000000..97cea40
--- /dev/null
+++ b/xbmc/addons/include/xbmc_epg_types.h
@@ -0,0 +1,96 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <string.h>
23#include <time.h>
24
25#undef ATTRIBUTE_PACKED
26#undef PRAGMA_PACK_BEGIN
27#undef PRAGMA_PACK_END
28
29#if defined(__GNUC__)
30#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
31#define ATTRIBUTE_PACKED __attribute__ ((packed))
32#define PRAGMA_PACK 0
33#endif
34#endif
35
36#if !defined(ATTRIBUTE_PACKED)
37#define ATTRIBUTE_PACKED
38#define PRAGMA_PACK 1
39#endif
40
41/*! @name EPG entry content event types */
42//@{
43/* These IDs come from the DVB-SI EIT table "content descriptor"
44 * Also known under the name "E-book genre assignments"
45 */
46#define EPG_EVENT_CONTENTMASK_UNDEFINED 0x00
47#define EPG_EVENT_CONTENTMASK_MOVIEDRAMA 0x10
48#define EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS 0x20
49#define EPG_EVENT_CONTENTMASK_SHOW 0x30
50#define EPG_EVENT_CONTENTMASK_SPORTS 0x40
51#define EPG_EVENT_CONTENTMASK_CHILDRENYOUTH 0x50
52#define EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE 0x60
53#define EPG_EVENT_CONTENTMASK_ARTSCULTURE 0x70
54#define EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS 0x80
55#define EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE 0x90
56#define EPG_EVENT_CONTENTMASK_LEISUREHOBBIES 0xA0
57#define EPG_EVENT_CONTENTMASK_SPECIAL 0xB0
58#define EPG_EVENT_CONTENTMASK_USERDEFINED 0xF0
59//@}
60
61/* Set EPGTAG.iGenreType to EPG_GENRE_USE_STRING to transfer genre strings to XBMC */
62#define EPG_GENRE_USE_STRING 0x100
63
64#ifdef __cplusplus
65extern "C" {
66#endif
67
68 /*!
69 * @brief Representation of an EPG event.
70 */
71 typedef struct EPG_TAG {
72 unsigned int iUniqueBroadcastId; /*!< @brief (required) identifier for this event */
73 const char * strTitle; /*!< @brief (required) this event's title */
74 unsigned int iChannelNumber; /*!< @brief (required) the number of the channel this event occurs on */
75 time_t startTime; /*!< @brief (required) start time in UTC */
76 time_t endTime; /*!< @brief (required) end time in UTC */
77 const char * strPlotOutline; /*!< @brief (optional) plot outline */
78 const char * strPlot; /*!< @brief (optional) plot */
79 const char * strIconPath; /*!< @brief (optional) icon path */
80 int iGenreType; /*!< @brief (optional) genre type */
81 int iGenreSubType; /*!< @brief (optional) genre sub type */
82 const char * strGenreDescription; /*!< @brief (optional) genre. Will be used only when iGenreType = EPG_GENRE_USE_STRING */
83 time_t firstAired; /*!< @brief (optional) first aired in UTC */
84 int iParentalRating; /*!< @brief (optional) parental rating */
85 int iStarRating; /*!< @brief (optional) star rating */
86 bool bNotify; /*!< @brief (optional) notify the user when this event starts */
87 int iSeriesNumber; /*!< @brief (optional) series number */
88 int iEpisodeNumber; /*!< @brief (optional) episode number */
89 int iEpisodePartNumber; /*!< @brief (optional) episode part number */
90 const char * strEpisodeName; /*!< @brief (optional) episode name */
91 const char * strRecordingId; /*!< @brief (optional) unique id of the recording on the client which represents this event */
92 } ATTRIBUTE_PACKED EPG_TAG;
93
94#ifdef __cplusplus
95}
96#endif
diff --git a/xbmc/addons/include/xbmc_pvr_dll.h b/xbmc/addons/include/xbmc_pvr_dll.h
new file mode 100644
index 0000000..3ad46fc
--- /dev/null
+++ b/xbmc/addons/include/xbmc_pvr_dll.h
@@ -0,0 +1,710 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#ifndef __XBMC_PVR_H__
22#define __XBMC_PVR_H__
23
24#include "xbmc_addon_dll.h"
25#include "xbmc_pvr_types.h"
26
27/*!
28 * Functions that the PVR client add-on must implement, but some can be empty.
29 *
30 * The 'remarks' field indicates which methods should be implemented, and which ones are optional.
31 */
32
33extern "C"
34{
35 /*! @name PVR add-on methods */
36 //@{
37 /*!
38 * Get the XBMC_PVR_API_VERSION that was used to compile this add-on.
39 * Used to check if this add-on is compatible with XBMC.
40 * @return The XBMC_PVR_API_VERSION that was used to compile this add-on.
41 * @remarks Valid implementation required.
42 */
43 const char* GetPVRAPIVersion(void);
44
45 /*!
46 * Get the XBMC_PVR_MIN_API_VERSION that was used to compile this add-on.
47 * Used to check if this add-on is compatible with XBMC.
48 * @return The XBMC_PVR_MIN_API_VERSION that was used to compile this add-on.
49 * @remarks Valid implementation required.
50 */
51 const char* GetMininumPVRAPIVersion(void);
52
53 /*!
54 * Get the XBMC_GUI_API_VERSION that was used to compile this add-on.
55 * Used to check if this add-on is compatible with XBMC.
56 * @return The XBMC_GUI_API_VERSION that was used to compile this add-on.
57 * @remarks Valid implementation required.
58 */
59 const char* GetGUIAPIVersion(void);
60
61 /*!
62 * Get the XBMC_GUI_MIN_API_VERSION that was used to compile this add-on.
63 * Used to check if this add-on is compatible with XBMC.
64 * @return The XBMC_GUI_MIN_API_VERSION that was used to compile this add-on.
65 * @remarks Valid implementation required.
66 */
67 const char* GetMininumGUIAPIVersion(void);
68
69 /*!
70 * Get the list of features that this add-on provides.
71 * Called by XBMC to query the add-on's capabilities.
72 * Used to check which options should be presented in the UI, which methods to call, etc.
73 * All capabilities that the add-on supports should be set to true.
74 * @param pCapabilities The add-on's capabilities.
75 * @return PVR_ERROR_NO_ERROR if the properties were fetched successfully.
76 * @remarks Valid implementation required.
77 */
78 PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES *pCapabilities);
79
80 /*!
81 * @return The name reported by the backend that will be displayed in the UI.
82 * @remarks Valid implementation required.
83 */
84 const char* GetBackendName(void);
85
86 /*!
87 * @return The version string reported by the backend that will be displayed in the UI.
88 * @remarks Valid implementation required.
89 */
90 const char* GetBackendVersion(void);
91
92 /*!
93 * @return The connection string reported by the backend that will be displayed in the UI.
94 * @remarks Valid implementation required.
95 */
96 const char* GetConnectionString(void);
97
98 /*!
99 * Get the disk space reported by the backend (if supported).
100 * @param iTotal The total disk space in bytes.
101 * @param iUsed The used disk space in bytes.
102 * @return PVR_ERROR_NO_ERROR if the drive space has been fetched successfully.
103 * @remarks Optional. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
104 */
105 PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed);
106
107 /*!
108 * Call one of the menu hooks (if supported).
109 * Supported PVR_MENUHOOK instances have to be added in ADDON_Create(), by calling AddMenuHook() on the callback.
110 * @param menuhook The hook to call.
111 * @param item The selected item for which the hook was called.
112 * @return PVR_ERROR_NO_ERROR if the hook was called successfully.
113 * @remarks Optional. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
114 */
115 PVR_ERROR CallMenuHook(const PVR_MENUHOOK& menuhook, const PVR_MENUHOOK_DATA &item);
116 //@}
117
118 /*! @name PVR EPG methods
119 * @remarks Only used by XBMC if bSupportsEPG is set to true.
120 */
121 //@{
122 /*!
123 * Request the EPG for a channel from the backend.
124 * EPG entries are added to XBMC by calling TransferEpgEntry() on the callback.
125 * @param handle Handle to pass to the callback method.
126 * @param channel The channel to get the EPG table for.
127 * @param iStart Get events after this time (UTC).
128 * @param iEnd Get events before this time (UTC).
129 * @return PVR_ERROR_NO_ERROR if the table has been fetched successfully.
130 * @remarks Required if bSupportsEPG is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
131 */
132 PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL& channel, time_t iStart, time_t iEnd);
133 //@}
134
135 /*! @name PVR channel group methods
136 * @remarks Only used by XBMC is bSupportsChannelGroups is set to true.
137 * If a group or one of the group members changes after the initial import, or if a new one was added, then the add-on
138 * should call TriggerChannelGroupsUpdate()
139 */
140 //@{
141 /*!
142 * Get the total amount of channel groups on the backend if it supports channel groups.
143 * @return The amount of channels, or -1 on error.
144 * @remarks Required if bSupportsChannelGroups is set to true. Return -1 if this add-on won't provide this function.
145 */
146 int GetChannelGroupsAmount(void);
147
148 /*!
149 * Request the list of all channel groups from the backend if it supports channel groups.
150 * Channel group entries are added to XBMC by calling TransferChannelGroup() on the callback.
151 * @param handle Handle to pass to the callback method.
152 * @param bRadio True to get the radio channel groups, false to get the TV channel groups.
153 * @return PVR_ERROR_NO_ERROR if the list has been fetched successfully.
154 * @remarks Required if bSupportsChannelGroups is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
155 */
156 PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio);
157
158 /*!
159 * Request the list of all group members of a group from the backend if it supports channel groups.
160 * Member entries are added to XBMC by calling TransferChannelGroupMember() on the callback.
161 * @param handle Handle to pass to the callback method.
162 * @param group The group to get the members for.
163 * @return PVR_ERROR_NO_ERROR if the list has been fetched successfully.
164 * @remarks Required if bSupportsChannelGroups is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
165 */
166 PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group);
167 //@}
168
169 /** @name PVR channel methods
170 * @remarks Either bSupportsTV or bSupportsRadio is required to be set to true.
171 * If a channel changes after the initial import, or if a new one was added, then the add-on
172 * should call TriggerChannelUpdate()
173 */
174 //@{
175 /*!
176 * Show the channel scan dialog if this backend supports it.
177 * @return PVR_ERROR_NO_ERROR if the dialog was displayed successfully.
178 * @remarks Required if bSupportsChannelScan is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
179 * @note see libXBMC_gui.h about related parts
180 */
181 PVR_ERROR OpenDialogChannelScan(void);
182
183 /*!
184 * @return The total amount of channels on the backend, or -1 on error.
185 * @remarks Valid implementation required.
186 */
187 int GetChannelsAmount(void);
188
189 /*!
190 * Request the list of all channels from the backend.
191 * Channel entries are added to XBMC by calling TransferChannelEntry() on the callback.
192 * @param handle Handle to pass to the callback method.
193 * @param bRadio True to get the radio channels, false to get the TV channels.
194 * @return PVR_ERROR_NO_ERROR if the list has been fetched successfully.
195 * @remarks If bSupportsTV is set to true, a valid result set needs to be provided for bRadio = false.
196 * If bSupportsRadio is set to true, a valid result set needs to be provided for bRadio = true.
197 * At least one of these two must provide a valid result set.
198 */
199 PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio);
200
201 /*!
202 * Delete a channel from the backend.
203 * @param channel The channel to delete.
204 * @return PVR_ERROR_NO_ERROR if the channel has been deleted successfully.
205 * @remarks Required if bSupportsChannelSettings is set to true.
206 */
207 PVR_ERROR DeleteChannel(const PVR_CHANNEL& channel);
208
209 /*!
210 * Rename a channel on the backend.
211 * @param channel The channel to rename, containing the new channel name.
212 * @return PVR_ERROR_NO_ERROR if the channel has been renamed successfully.
213 * @remarks Optional, and only used if bSupportsChannelSettings is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
214 */
215 PVR_ERROR RenameChannel(const PVR_CHANNEL& channel);
216
217 /*!
218 * Move a channel to another channel number on the backend.
219 * @param channel The channel to move, containing the new channel number.
220 * @return PVR_ERROR_NO_ERROR if the channel has been moved successfully.
221 * @remarks Optional, and only used if bSupportsChannelSettings is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
222 */
223 PVR_ERROR MoveChannel(const PVR_CHANNEL& channel);
224
225 /*!
226 * Show the channel settings dialog, if supported by the backend.
227 * @param channel The channel to show the dialog for.
228 * @return PVR_ERROR_NO_ERROR if the dialog has been displayed successfully.
229 * @remarks Required if bSupportsChannelSettings is set to true.
230 * @note see libXBMC_gui.h about related parts
231 */
232 PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL& channel);
233
234 /*!
235 * Show the dialog to add a channel on the backend, if supported by the backend.
236 * @param channel The channel to add.
237 * @return PVR_ERROR_NO_ERROR if the channel has been added successfully.
238 * @remarks Required if bSupportsChannelSettings is set to true.
239 * @note see libXBMC_gui.h about related parts
240 */
241 PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL& channel);
242 //@}
243
244 /** @name PVR recording methods
245 * @remarks Only used by XBMC is bSupportsRecordings is set to true.
246 * If a recording changes after the initial import, or if a new one was added,
247 * then the add-on should call TriggerRecordingUpdate()
248 */
249 //@{
250 /*!
251 * @return The total amount of recordings on the backend or -1 on error.
252 * @param deleted if set return deleted recording (called if bSupportsRecordingsUndelete set to true)
253 * @remarks Required if bSupportsRecordings is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
254 */
255 int GetRecordingsAmount(bool deleted);
256
257 /*!
258 * Request the list of all recordings from the backend, if supported.
259 * Recording entries are added to XBMC by calling TransferRecordingEntry() on the callback.
260 * @param handle Handle to pass to the callback method.
261 * @param deleted if set return deleted recording (called if bSupportsRecordingsUndelete set to true)
262 * @return PVR_ERROR_NO_ERROR if the recordings have been fetched successfully.
263 * @remarks Required if bSupportsRecordings is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
264 */
265 PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted);
266
267 /*!
268 * Delete a recording on the backend.
269 * @param recording The recording to delete.
270 * @return PVR_ERROR_NO_ERROR if the recording has been deleted successfully.
271 * @remarks Optional, and only used if bSupportsRecordings is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
272 */
273 PVR_ERROR DeleteRecording(const PVR_RECORDING& recording);
274
275 /*!
276 * Undelete a recording on the backend.
277 * @param recording The recording to undelete.
278 * @return PVR_ERROR_NO_ERROR if the recording has been undeleted successfully.
279 * @remarks Optional, and only used if bSupportsRecordingsUndelete is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
280 */
281 PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording);
282
283 /*!
284 * @brief Delete all recordings permanent which in the deleted folder on the backend.
285 * @return PVR_ERROR_NO_ERROR if the recordings has been deleted successfully.
286 */
287 PVR_ERROR DeleteAllRecordingsFromTrash();
288
289 /*!
290 * Rename a recording on the backend.
291 * @param recording The recording to rename, containing the new name.
292 * @return PVR_ERROR_NO_ERROR if the recording has been renamed successfully.
293 * @remarks Optional, and only used if bSupportsRecordings is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
294 */
295 PVR_ERROR RenameRecording(const PVR_RECORDING& recording);
296
297 /*!
298 * Set the play count of a recording on the backend.
299 * @param recording The recording to change the play count.
300 * @param count Play count.
301 * @return PVR_ERROR_NO_ERROR if the recording's play count has been set successfully.
302 * @remarks Required if bSupportsRecordingPlayCount is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
303 */
304 PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING& recording, int count);
305
306 /*!
307 * Set the last watched position of a recording on the backend.
308 * @param recording The recording.
309 * @param position The last watched position in seconds
310 * @return PVR_ERROR_NO_ERROR if the position has been stored successfully.
311 * @remarks Required if bSupportsLastPlayedPosition is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
312 */
313 PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastplayedposition);
314
315 /*!
316 * Retrieve the last watched position of a recording on the backend.
317 * @param recording The recording.
318 * @return The last watched position in seconds or -1 on error
319 * @remarks Required if bSupportsRecordingPlayCount is set to true. Return -1 if this add-on won't provide this function.
320 */
321 int GetRecordingLastPlayedPosition(const PVR_RECORDING& recording);
322
323 /*!
324 * Retrieve the edit decision list (EDL) of a recording on the backend.
325 * @param recording The recording.
326 * @param edl out: The function has to write the EDL list into this array.
327 * @param size in: The maximum size of the EDL, out: the actual size of the EDL.
328 * @return PVR_ERROR_NO_ERROR if the EDL was successfully read.
329 * @remarks Required if bSupportsRecordingEdl is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
330 */
331 PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY edl[], int *size);
332
333 //@}
334 /** @name PVR timer methods
335 * @remarks Only used by XBMC is bSupportsTimers is set to true.
336 * If a timer changes after the initial import, or if a new one was added,
337 * then the add-on should call TriggerTimerUpdate()
338 */
339 //@{
340 /*!
341 * @return The total amount of timers on the backend or -1 on error.
342 * @remarks Required if bSupportsTimers is set to true. Return -1 if this add-on won't provide this function.
343 */
344 int GetTimersAmount(void);
345
346 /*!
347 * Request the list of all timers from the backend if supported.
348 * Timer entries are added to XBMC by calling TransferTimerEntry() on the callback.
349 * @param handle Handle to pass to the callback method.
350 * @return PVR_ERROR_NO_ERROR if the list has been fetched successfully.
351 * @remarks Required if bSupportsTimers is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
352 */
353 PVR_ERROR GetTimers(ADDON_HANDLE handle);
354
355 /*!
356 * Add a timer on the backend.
357 * @param timer The timer to add.
358 * @return PVR_ERROR_NO_ERROR if the timer has been added successfully.
359 * @remarks Required if bSupportsTimers is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
360 */
361 PVR_ERROR AddTimer(const PVR_TIMER& timer);
362
363 /*!
364 * Delete a timer on the backend.
365 * @param timer The timer to delete.
366 * @param bForceDelete Set to true to delete a timer that is currently recording a program.
367 * @return PVR_ERROR_NO_ERROR if the timer has been deleted successfully.
368 * @remarks Required if bSupportsTimers is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
369 */
370 PVR_ERROR DeleteTimer(const PVR_TIMER& timer, bool bForceDelete);
371
372 /*!
373 * Update the timer information on the backend.
374 * @param timer The timer to update.
375 * @return PVR_ERROR_NO_ERROR if the timer has been updated successfully.
376 * @remarks Required if bSupportsTimers is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
377 */
378 PVR_ERROR UpdateTimer(const PVR_TIMER& timer);
379
380 //@}
381
382 /** @name PVR live stream methods, used to open and close a stream to a channel, and optionally perform read operations on the stream */
383 //@{
384 /*!
385 * Open a live stream on the backend.
386 * @param channel The channel to stream.
387 * @return True if the stream has been opened successfully, false otherwise.
388 * @remarks Required if bHandlesInputStream or bHandlesDemuxing is set to true. Return false if this add-on won't provide this function.
389 */
390 bool OpenLiveStream(const PVR_CHANNEL& channel);
391
392 /*!
393 * Close an open live stream.
394 * @remarks Required if bHandlesInputStream or bHandlesDemuxing is set to true.
395 */
396 void CloseLiveStream(void);
397
398 /*!
399 * Read from an open live stream.
400 * @param pBuffer The buffer to store the data in.
401 * @param iBufferSize The amount of bytes to read.
402 * @return The amount of bytes that were actually read from the stream.
403 * @remarks Required if bHandlesInputStream is set to true. Return -1 if this add-on won't provide this function.
404 */
405 int ReadLiveStream(unsigned char* pBuffer, unsigned int iBufferSize);
406
407 /*!
408 * Seek in a live stream on a backend that supports timeshifting.
409 * @param iPosition The position to seek to.
410 * @param iWhence ?
411 * @return The new position.
412 * @remarks Optional, and only used if bHandlesInputStream is set to true. Return -1 if this add-on won't provide this function.
413 */
414 long long SeekLiveStream(long long iPosition, int iWhence = SEEK_SET);
415
416 /*!
417 * @return The position in the stream that's currently being read.
418 * @remarks Optional, and only used if bHandlesInputStream is set to true. Return -1 if this add-on won't provide this function.
419 */
420 long long PositionLiveStream(void);
421
422 /*!
423 * @return The total length of the stream that's currently being read.
424 * @remarks Optional, and only used if bHandlesInputStream is set to true. Return -1 if this add-on won't provide this function.
425 */
426 long long LengthLiveStream(void);
427
428 /*!
429 * @return The channel number on the backend of the live stream that's currently being read.
430 * @remarks Required if bHandlesInputStream or bHandlesDemuxing is set to true. Return -1 if this add-on won't provide this function.
431 */
432 int GetCurrentClientChannel(void);
433
434 /*!
435 * Switch to another channel. Only to be called when a live stream has already been opened.
436 * @param channel The channel to switch to.
437 * @return True if the switch was successful, false otherwise.
438 * @remarks Required if bHandlesInputStream or bHandlesDemuxing is set to true. Return false if this add-on won't provide this function.
439 */
440 bool SwitchChannel(const PVR_CHANNEL& channel);
441
442 /*!
443 * Get the signal status of the stream that's currently open.
444 * @param signalStatus The signal status.
445 * @return True if the signal status has been read successfully, false otherwise.
446 * @remarks Optional, and only used if bHandlesInputStream or bHandlesDemuxing is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
447 */
448 PVR_ERROR SignalStatus(PVR_SIGNAL_STATUS& signalStatus);
449
450 /*!
451 * Get the stream URL for a channel from the backend. Used by the MediaPortal add-on.
452 * @param channel The channel to get the stream URL for.
453 * @return The requested URL.
454 * @remarks Optional, and only used if bHandlesInputStream is set to true. Return NULL if this add-on won't provide this function.
455 */
456 const char* GetLiveStreamURL(const PVR_CHANNEL& channel);
457
458 /*!
459 * Get the stream properties of the stream that's currently being read.
460 * @param pProperties The properties of the currently playing stream.
461 * @return PVR_ERROR_NO_ERROR if the properties have been fetched successfully.
462 * @remarks Required if bHandlesInputStream or bHandlesDemuxing is set to true. Return PVR_ERROR_NOT_IMPLEMENTED if this add-on won't provide this function.
463 */
464 PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES* pProperties);
465 //@}
466
467 /** @name PVR recording stream methods, used to open and close a stream to a recording, and perform read operations on the stream.
468 * @remarks This will only be used if the backend doesn't provide a direct URL in the recording tag.
469 */
470 //@{
471 /*!
472 * Open a stream to a recording on the backend.
473 * @param recording The recording to open.
474 * @return True if the stream has been opened successfully, false otherwise.
475 * @remarks Optional, and only used if bSupportsRecordings is set to true. Return false if this add-on won't provide this function.
476 */
477 bool OpenRecordedStream(const PVR_RECORDING& recording);
478
479 /*!
480 * Close an open stream from a recording.
481 * @remarks Optional, and only used if bSupportsRecordings is set to true.
482 */
483 void CloseRecordedStream(void);
484
485 /*!
486 * Read from a recording.
487 * @param pBuffer The buffer to store the data in.
488 * @param iBufferSize The amount of bytes to read.
489 * @return The amount of bytes that were actually read from the stream.
490 * @remarks Optional, and only used if bSupportsRecordings is set to true, but required if OpenRecordedStream() is implemented. Return -1 if this add-on won't provide this function.
491 */
492 int ReadRecordedStream(unsigned char* pBuffer, unsigned int iBufferSize);
493
494 /*!
495 * Seek in a recorded stream.
496 * @param iPosition The position to seek to.
497 * @param iWhence ?
498 * @return The new position.
499 * @remarks Optional, and only used if bSupportsRecordings is set to true. Return -1 if this add-on won't provide this function.
500 */
501 long long SeekRecordedStream(long long iPosition, int iWhence = SEEK_SET);
502
503 /*!
504 * @return The position in the stream that's currently being read.
505 * @remarks Optional, and only used if bSupportsRecordings is set to true. Return -1 if this add-on won't provide this function.
506 */
507 long long PositionRecordedStream(void);
508
509 /*!
510 * @return The total length of the stream that's currently being read.
511 * @remarks Optional, and only used if bSupportsRecordings is set to true. Return -1 if this add-on won't provide this function.
512 */
513 long long LengthRecordedStream(void);
514 //@}
515
516 /** @name PVR demultiplexer methods
517 * @remarks Only used by XBMC is bHandlesDemuxing is set to true.
518 */
519 //@{
520 /*!
521 * Reset the demultiplexer in the add-on.
522 * @remarks Required if bHandlesDemuxing is set to true.
523 */
524 void DemuxReset(void);
525
526 /*!
527 * Abort the demultiplexer thread in the add-on.
528 * @remarks Required if bHandlesDemuxing is set to true.
529 */
530 void DemuxAbort(void);
531
532 /*!
533 * Flush all data that's currently in the demultiplexer buffer in the add-on.
534 * @remarks Required if bHandlesDemuxing is set to true.
535 */
536 void DemuxFlush(void);
537
538 /*!
539 * Read the next packet from the demultiplexer, if there is one.
540 * @return The next packet.
541 * If there is no next packet, then the add-on should return the
542 * packet created by calling AllocateDemuxPacket(0) on the callback.
543 * If the stream changed and XBMC's player needs to be reinitialised,
544 * then, the add-on should call AllocateDemuxPacket(0) on the
545 * callback, and set the streamid to DMX_SPECIALID_STREAMCHANGE and
546 * return the value.
547 * The add-on should return NULL if an error occured.
548 * @remarks Required if bHandlesDemuxing is set to true. Return NULL if this add-on won't provide this function.
549 */
550 DemuxPacket* DemuxRead(void);
551 //@}
552
553 /*!
554 * Delay to use when using switching channels for add-ons not providing an input stream.
555 * If the add-on does provide an input stream, then this method will not be called.
556 * Those add-ons can do that in OpenLiveStream() if needed.
557 * @return The delay in milliseconds.
558 */
559 unsigned int GetChannelSwitchDelay(void);
560
561 /*!
562 * Check if the backend support pausing the currently playing stream
563 * This will enable/disable the pause button in XBMC based on the return value
564 * @return false if the PVR addon/backend does not support pausing, true if possible
565 */
566 bool CanPauseStream();
567
568 /*!
569 * Check if the backend supports seeking for the currently playing stream
570 * This will enable/disable the rewind/forward buttons in XBMC based on the return value
571 * @return false if the PVR addon/backend does not support seeking, true if possible
572 */
573 bool CanSeekStream();
574
575 /*!
576 * @brief Notify the pvr addon that XBMC (un)paused the currently playing stream
577 */
578 void PauseStream(bool bPaused);
579
580 /*!
581 * Notify the pvr addon/demuxer that XBMC wishes to seek the stream by time
582 * @param time The absolute time since stream start
583 * @param backwards True to seek to keyframe BEFORE time, else AFTER
584 * @param startpts can be updated to point to where display should start
585 * @return True if the seek operation was possible
586 * @remarks Optional, and only used if addon has its own demuxer. Return False if this add-on won't provide this function.
587 */
588 bool SeekTime(int time, bool backwards, double *startpts);
589
590 /*!
591 * Notify the pvr addon/demuxer that XBMC wishes to change playback speed
592 * @param speed The requested playback speed
593 * @remarks Optional, and only used if addon has its own demuxer.
594 */
595 void SetSpeed(int speed);
596
597 /*!
598 * Get actual playing time from addon. With timeshift enabled this is
599 * different to live.
600 * @return time as UTC
601 */
602 time_t GetPlayingTime();
603
604 /*!
605 * Get time of oldest packet in timeshift buffer
606 * @return time as UTC
607 */
608 time_t GetBufferTimeStart();
609
610 /*!
611 * Get time of latest packet in timeshift buffer
612 * @return time as UTC
613 */
614 time_t GetBufferTimeEnd();
615
616 /*!
617 * Get the hostname of the pvr backend server
618 * @return hostname as ip address or alias. If backend does not
619 * utilize a server, return empty string.
620 */
621 const char* GetBackendHostname();
622
623 /*!
624 * Called by XBMC to assign the function pointers of this add-on to pClient.
625 * @param pClient The struct to assign the function pointers to.
626 */
627 void __declspec(dllexport) get_addon(struct PVRClient* pClient)
628 {
629 pClient->GetPVRAPIVersion = GetPVRAPIVersion;
630 pClient->GetMininumPVRAPIVersion = GetMininumPVRAPIVersion;
631 pClient->GetGUIAPIVersion = GetGUIAPIVersion;
632 pClient->GetMininumGUIAPIVersion = GetMininumGUIAPIVersion;
633 pClient->GetAddonCapabilities = GetAddonCapabilities;
634 pClient->GetStreamProperties = GetStreamProperties;
635 pClient->GetConnectionString = GetConnectionString;
636 pClient->GetBackendName = GetBackendName;
637 pClient->GetBackendVersion = GetBackendVersion;
638 pClient->GetDriveSpace = GetDriveSpace;
639 pClient->OpenDialogChannelScan = OpenDialogChannelScan;
640 pClient->MenuHook = CallMenuHook;
641
642 pClient->GetEpg = GetEPGForChannel;
643
644 pClient->GetChannelGroupsAmount = GetChannelGroupsAmount;
645 pClient->GetChannelGroups = GetChannelGroups;
646 pClient->GetChannelGroupMembers = GetChannelGroupMembers;
647
648 pClient->GetChannelsAmount = GetChannelsAmount;
649 pClient->GetChannels = GetChannels;
650 pClient->DeleteChannel = DeleteChannel;
651 pClient->RenameChannel = RenameChannel;
652 pClient->MoveChannel = MoveChannel;
653 pClient->OpenDialogChannelSettings = OpenDialogChannelSettings;
654 pClient->OpenDialogChannelAdd = OpenDialogChannelAdd;
655
656 pClient->GetRecordingsAmount = GetRecordingsAmount;
657 pClient->GetRecordings = GetRecordings;
658 pClient->DeleteRecording = DeleteRecording;
659 pClient->UndeleteRecording = UndeleteRecording;
660 pClient->DeleteAllRecordingsFromTrash = DeleteAllRecordingsFromTrash;
661 pClient->RenameRecording = RenameRecording;
662 pClient->SetRecordingPlayCount = SetRecordingPlayCount;
663 pClient->SetRecordingLastPlayedPosition = SetRecordingLastPlayedPosition;
664 pClient->GetRecordingLastPlayedPosition = GetRecordingLastPlayedPosition;
665 pClient->GetRecordingEdl = GetRecordingEdl;
666
667 pClient->GetTimersAmount = GetTimersAmount;
668 pClient->GetTimers = GetTimers;
669 pClient->AddTimer = AddTimer;
670 pClient->DeleteTimer = DeleteTimer;
671 pClient->UpdateTimer = UpdateTimer;
672
673 pClient->OpenLiveStream = OpenLiveStream;
674 pClient->CloseLiveStream = CloseLiveStream;
675 pClient->ReadLiveStream = ReadLiveStream;
676 pClient->SeekLiveStream = SeekLiveStream;
677 pClient->PositionLiveStream = PositionLiveStream;
678 pClient->LengthLiveStream = LengthLiveStream;
679 pClient->GetCurrentClientChannel = GetCurrentClientChannel;
680 pClient->SwitchChannel = SwitchChannel;
681 pClient->SignalStatus = SignalStatus;
682 pClient->GetLiveStreamURL = GetLiveStreamURL;
683 pClient->GetChannelSwitchDelay = GetChannelSwitchDelay;
684 pClient->CanPauseStream = CanPauseStream;
685 pClient->PauseStream = PauseStream;
686 pClient->CanSeekStream = CanSeekStream;
687 pClient->SeekTime = SeekTime;
688 pClient->SetSpeed = SetSpeed;
689
690 pClient->OpenRecordedStream = OpenRecordedStream;
691 pClient->CloseRecordedStream = CloseRecordedStream;
692 pClient->ReadRecordedStream = ReadRecordedStream;
693 pClient->SeekRecordedStream = SeekRecordedStream;
694 pClient->PositionRecordedStream = PositionRecordedStream;
695 pClient->LengthRecordedStream = LengthRecordedStream;
696
697 pClient->DemuxReset = DemuxReset;
698 pClient->DemuxAbort = DemuxAbort;
699 pClient->DemuxFlush = DemuxFlush;
700 pClient->DemuxRead = DemuxRead;
701
702 pClient->GetPlayingTime = GetPlayingTime;
703 pClient->GetBufferTimeStart = GetBufferTimeStart;
704 pClient->GetBufferTimeEnd = GetBufferTimeEnd;
705
706 pClient->GetBackendHostname = GetBackendHostname;
707 };
708};
709
710#endif
diff --git a/xbmc/addons/include/xbmc_pvr_types.h b/xbmc/addons/include/xbmc_pvr_types.h
new file mode 100644
index 0000000..5285bd1
--- /dev/null
+++ b/xbmc/addons/include/xbmc_pvr_types.h
@@ -0,0 +1,415 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef __PVRCLIENT_TYPES_H__
23#define __PVRCLIENT_TYPES_H__
24
25#ifdef TARGET_WINDOWS
26#include <windows.h>
27#else
28#ifndef __cdecl
29#define __cdecl
30#endif
31#ifndef __declspec
32#define __declspec(X)
33#endif
34#endif
35#include <string.h>
36#include <stdint.h>
37
38#include "xbmc_addon_types.h"
39#include "xbmc_epg_types.h"
40#include "xbmc_codec_types.h"
41
42/*! @note Define "USE_DEMUX" at compile time if demuxing in the PVR add-on is used.
43 * Also XBMC's "DVDDemuxPacket.h" file must be in the include path of the add-on,
44 * and the add-on should set bHandlesDemuxing to true.
45 */
46#ifdef USE_DEMUX
47#include "DVDDemuxPacket.h"
48#else
49struct DemuxPacket;
50#endif
51
52#undef ATTRIBUTE_PACKED
53#undef PRAGMA_PACK_BEGIN
54#undef PRAGMA_PACK_END
55
56#if defined(__GNUC__)
57#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
58#define ATTRIBUTE_PACKED __attribute__ ((packed))
59#define PRAGMA_PACK 0
60#endif
61#endif
62
63#if !defined(ATTRIBUTE_PACKED)
64#define ATTRIBUTE_PACKED
65#define PRAGMA_PACK 1
66#endif
67
68#define PVR_ADDON_NAME_STRING_LENGTH 1024
69#define PVR_ADDON_URL_STRING_LENGTH 1024
70#define PVR_ADDON_DESC_STRING_LENGTH 1024
71#define PVR_ADDON_INPUT_FORMAT_STRING_LENGTH 32
72#define PVR_ADDON_EDL_LENGTH 32
73
74/* using the default avformat's MAX_STREAMS value to be safe */
75#define PVR_STREAM_MAX_STREAMS 20
76
77/* current PVR API version */
78#define XBMC_PVR_API_VERSION "1.9.4"
79
80/* min. PVR API version */
81#define XBMC_PVR_MIN_API_VERSION "1.9.4"
82
83#ifdef __cplusplus
84extern "C" {
85#endif
86
87 /*!
88 * @brief PVR add-on error codes
89 */
90 typedef enum
91 {
92 PVR_ERROR_NO_ERROR = 0, /*!< @brief no error occurred */
93 PVR_ERROR_UNKNOWN = -1, /*!< @brief an unknown error occurred */
94 PVR_ERROR_NOT_IMPLEMENTED = -2, /*!< @brief the method that XBMC called is not implemented by the add-on */
95 PVR_ERROR_SERVER_ERROR = -3, /*!< @brief the backend reported an error, or the add-on isn't connected */
96 PVR_ERROR_SERVER_TIMEOUT = -4, /*!< @brief the command was sent to the backend, but the response timed out */
97 PVR_ERROR_REJECTED = -5, /*!< @brief the command was rejected by the backend */
98 PVR_ERROR_ALREADY_PRESENT = -6, /*!< @brief the requested item can not be added, because it's already present */
99 PVR_ERROR_INVALID_PARAMETERS = -7, /*!< @brief the parameters of the method that was called are invalid for this operation */
100 PVR_ERROR_RECORDING_RUNNING = -8, /*!< @brief a recording is running, so the timer can't be deleted without doing a forced delete */
101 PVR_ERROR_FAILED = -9, /*!< @brief the command failed */
102 } PVR_ERROR;
103
104 /*!
105 * @brief PVR timer states
106 */
107 typedef enum
108 {
109 PVR_TIMER_STATE_NEW = 0, /*!< @brief a new, unsaved timer */
110 PVR_TIMER_STATE_SCHEDULED = 1, /*!< @brief the timer is scheduled for recording */
111 PVR_TIMER_STATE_RECORDING = 2, /*!< @brief the timer is currently recordings */
112 PVR_TIMER_STATE_COMPLETED = 3, /*!< @brief the recording completed successfully */
113 PVR_TIMER_STATE_ABORTED = 4, /*!< @brief recording started, but was aborted */
114 PVR_TIMER_STATE_CANCELLED = 5, /*!< @brief the timer was scheduled, but was canceled */
115 PVR_TIMER_STATE_CONFLICT_OK = 6, /*!< @brief the scheduled timer conflicts with another one, but will be recorded */
116 PVR_TIMER_STATE_CONFLICT_NOK = 7, /*!< @brief the scheduled timer conflicts with another one and won't be recorded */
117 PVR_TIMER_STATE_ERROR = 8 /*!< @brief the timer is scheduled, but can't be recorded for some reason */
118 } PVR_TIMER_STATE;
119
120 /*!
121 * @brief PVR menu hook categories
122 */
123 typedef enum
124 {
125 PVR_MENUHOOK_UNKNOWN =-1, /*!< @brief unknown menu hook */
126 PVR_MENUHOOK_ALL = 0, /*!< @brief all categories */
127 PVR_MENUHOOK_CHANNEL = 1, /*!< @brief for channels */
128 PVR_MENUHOOK_TIMER = 2, /*!< @brief for timers */
129 PVR_MENUHOOK_EPG = 3, /*!< @brief for EPG */
130 PVR_MENUHOOK_RECORDING = 4, /*!< @brief for recordings */
131 PVR_MENUHOOK_DELETED_RECORDING = 5, /*!< @brief for deleted recordings */
132 PVR_MENUHOOK_SETTING = 6, /*!< @brief for settings */
133 } PVR_MENUHOOK_CAT;
134
135 /*!
136 * @brief Properties passed to the Create() method of an add-on.
137 */
138 typedef struct PVR_PROPERTIES
139 {
140 const char* strUserPath; /*!< @brief path to the user profile */
141 const char* strClientPath; /*!< @brief path to this add-on */
142 } PVR_PROPERTIES;
143
144 /*!
145 * @brief PVR add-on capabilities. All capabilities are set to "false" as default.
146 * If a capabilty is set to true, then the corresponding methods from xbmc_pvr_dll.h need to be implemented.
147 */
148 typedef struct PVR_ADDON_CAPABILITIES
149 {
150 bool bSupportsEPG; /*!< @brief true if the add-on provides EPG information */
151 bool bSupportsTV; /*!< @brief true if this add-on provides TV channels */
152 bool bSupportsRadio; /*!< @brief true if this add-on supports radio channels */
153 bool bSupportsRecordings; /*!< @brief true if this add-on supports playback of recordings stored on the backend */
154 bool bSupportsRecordingsUndelete; /*!< @brief true if this add-on supports undelete of recordings stored on the backend */
155 bool bSupportsTimers; /*!< @brief true if this add-on supports the creation and editing of timers */
156 bool bSupportsChannelGroups; /*!< @brief true if this add-on supports channel groups */
157 bool bSupportsChannelScan; /*!< @brief true if this add-on support scanning for new channels on the backend */
158 bool bSupportsChannelSettings; /*!< @brief true if this add-on supports the following functions: DeleteChannel, RenameChannel, MoveChannel, DialogChannelSettings and DialogAddChannel */
159 bool bHandlesInputStream; /*!< @brief true if this add-on provides an input stream. false if XBMC handles the stream. */
160 bool bHandlesDemuxing; /*!< @brief true if this add-on demultiplexes packets. */
161 bool bSupportsRecordingFolders; /*!< @brief true if the backend supports timers / recordings in folders. */
162 bool bSupportsRecordingPlayCount; /*!< @brief true if the backend supports play count for recordings. */
163 bool bSupportsLastPlayedPosition; /*!< @brief true if the backend supports store/retrieve of last played position for recordings. */
164 bool bSupportsRecordingEdl; /*!< @brief true if the backend supports retrieving an edit decision list for recordings. */
165 } ATTRIBUTE_PACKED PVR_ADDON_CAPABILITIES;
166
167 /*!
168 * @brief PVR stream properties
169 */
170 typedef struct PVR_STREAM_PROPERTIES
171 {
172 unsigned int iStreamCount;
173 struct PVR_STREAM
174 {
175 unsigned int iPhysicalId; /*!< @brief (required) physical index */
176 xbmc_codec_type_t iCodecType; /*!< @brief (required) codec type this stream */
177 xbmc_codec_id_t iCodecId; /*!< @brief (required) codec id of this stream */
178 char strLanguage[4]; /*!< @brief (required) language id */
179 int iIdentifier; /*!< @brief (required) stream id */
180 int iFPSScale; /*!< @brief (required) scale of 1000 and a rate of 29970 will result in 29.97 fps */
181 int iFPSRate; /*!< @brief (required) FPS rate */
182 int iHeight; /*!< @brief (required) height of the stream reported by the demuxer */
183 int iWidth; /*!< @brief (required) width of the stream reported by the demuxer */
184 float fAspect; /*!< @brief (required) display aspect ratio of the stream */
185 int iChannels; /*!< @brief (required) amount of channels */
186 int iSampleRate; /*!< @brief (required) sample rate */
187 int iBlockAlign; /*!< @brief (required) block alignment */
188 int iBitRate; /*!< @brief (required) bit rate */
189 int iBitsPerSample; /*!< @brief (required) bits per sample */
190 } stream[PVR_STREAM_MAX_STREAMS]; /*!< @brief (required) the streams */
191 } ATTRIBUTE_PACKED PVR_STREAM_PROPERTIES;
192
193 /*!
194 * @brief Signal status information
195 */
196 typedef struct PVR_SIGNAL_STATUS
197 {
198 char strAdapterName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) name of the adapter that's being used */
199 char strAdapterStatus[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) status of the adapter that's being used */
200 char strServiceName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) name of the current service */
201 char strProviderName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) name of the current service's provider */
202 char strMuxName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) name of the current mux */
203 int iSNR; /*!< @brief (optional) signal/noise ratio */
204 int iSignal; /*!< @brief (optional) signal strength */
205 long iBER; /*!< @brief (optional) bit error rate */
206 long iUNC; /*!< @brief (optional) uncorrected blocks */
207 double dVideoBitrate; /*!< @brief (optional) video bitrate */
208 double dAudioBitrate; /*!< @brief (optional) audio bitrate */
209 double dDolbyBitrate; /*!< @brief (optional) dolby bitrate */
210 } ATTRIBUTE_PACKED PVR_SIGNAL_STATUS;
211
212 /*!
213 * @brief Menu hooks that are available in the context menus while playing a stream via this add-on.
214 * And in the Live TV settings dialog
215 */
216 typedef struct PVR_MENUHOOK
217 {
218 unsigned int iHookId; /*!< @brief (required) this hook's identifier */
219 unsigned int iLocalizedStringId; /*!< @brief (required) the id of the label for this hook in g_localizeStrings */
220 PVR_MENUHOOK_CAT category; /*!< @brief (required) category of menu hook */
221 } ATTRIBUTE_PACKED PVR_MENUHOOK;
222
223 /*!
224 * @brief Representation of a TV or radio channel.
225 */
226 typedef struct PVR_CHANNEL
227 {
228 unsigned int iUniqueId; /*!< @brief (required) unique identifier for this channel */
229 bool bIsRadio; /*!< @brief (required) true if this is a radio channel, false if it's a TV channel */
230 unsigned int iChannelNumber; /*!< @brief (optional) channel number of this channel on the backend */
231 unsigned int iSubChannelNumber; /*!< @brief (optional) sub channel number of this channel on the backend (ATSC) */
232 char strChannelName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) channel name given to this channel */
233 char strInputFormat[PVR_ADDON_INPUT_FORMAT_STRING_LENGTH]; /*!< @brief (optional) input format type. types can be found in ffmpeg/libavformat/allformats.c
234 leave empty if unknown */
235 char strStreamURL[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) the URL to use to access this channel.
236 leave empty to use this add-on to access the stream.
237 set to a path that's supported by XBMC otherwise. */
238 unsigned int iEncryptionSystem; /*!< @brief (optional) the encryption ID or CaID of this channel */
239 char strIconPath[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) path to the channel icon (if present) */
240 bool bIsHidden; /*!< @brief (optional) true if this channel is marked as hidden */
241 } ATTRIBUTE_PACKED PVR_CHANNEL;
242
243 typedef struct PVR_CHANNEL_GROUP
244 {
245 char strGroupName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (required) name of this channel group */
246 bool bIsRadio; /*!< @brief (required) true if this is a radio channel group, false otherwise. */
247 } ATTRIBUTE_PACKED PVR_CHANNEL_GROUP;
248
249 typedef struct PVR_CHANNEL_GROUP_MEMBER
250 {
251 char strGroupName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (required) name of the channel group to add the channel to */
252 unsigned int iChannelUniqueId; /*!< @brief (required) unique id of the member */
253 unsigned int iChannelNumber; /*!< @brief (optional) channel number within the group */
254 } ATTRIBUTE_PACKED PVR_CHANNEL_GROUP_MEMBER;
255
256 /*!
257 * @brief Representation of a timer event.
258 */
259 typedef struct PVR_TIMER {
260 unsigned int iClientIndex; /*!< @brief (required) the index of this timer given by the client */
261 int iClientChannelUid; /*!< @brief (required) unique identifier of the channel to record on */
262 time_t startTime; /*!< @brief (required) start time of the recording in UTC. instant timers that are sent to the add-on by xbmc will have this value set to 0 */
263 time_t endTime; /*!< @brief (required) end time of the recording in UTC */
264 PVR_TIMER_STATE state; /*!< @brief (required) the state of this timer */
265 char strTitle[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) title of this timer */
266 char strDirectory[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) the directory where the recording will be stored in */
267 char strSummary[PVR_ADDON_DESC_STRING_LENGTH]; /*!< @brief (optional) the summary for this timer */
268 int iPriority; /*!< @brief (optional) the priority of this timer */
269 int iLifetime; /*!< @brief (optional) lifetimer of this timer in days */
270 bool bIsRepeating; /*!< @brief (optional) true if this is a recurring timer */
271 time_t firstDay; /*!< @brief (optional) the first day this recording is active in case of a repeating event */
272 int iWeekdays; /*!< @brief (optional) weekday mask */
273 int iEpgUid; /*!< @brief (optional) epg event id */
274 unsigned int iMarginStart; /*!< @brief (optional) if set, the backend starts the recording iMarginStart minutes before startTime. */
275 unsigned int iMarginEnd; /*!< @brief (optional) if set, the backend ends the recording iMarginEnd minutes after endTime. */
276 int iGenreType; /*!< @brief (optional) genre type */
277 int iGenreSubType; /*!< @brief (optional) genre sub type */
278 } ATTRIBUTE_PACKED PVR_TIMER;
279 /*!
280 * @brief Representation of a recording.
281 */
282 typedef struct PVR_RECORDING {
283 char strRecordingId[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (required) unique id of the recording on the client. */
284 char strTitle[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (required) the title of this recording */
285 char strStreamURL[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (required) stream URL to access this recording */
286 char strDirectory[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) directory of this recording on the client */
287 char strPlotOutline[PVR_ADDON_DESC_STRING_LENGTH]; /*!< @brief (optional) plot outline */
288 char strPlot[PVR_ADDON_DESC_STRING_LENGTH]; /*!< @brief (optional) plot */
289 char strChannelName[PVR_ADDON_NAME_STRING_LENGTH]; /*!< @brief (optional) channel name */
290 char strIconPath[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) icon path */
291 char strThumbnailPath[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) thumbnail path */
292 char strFanartPath[PVR_ADDON_URL_STRING_LENGTH]; /*!< @brief (optional) fanart path */
293 time_t recordingTime; /*!< @brief (optional) start time of the recording */
294 int iDuration; /*!< @brief (optional) duration of the recording in seconds */
295 int iPriority; /*!< @brief (optional) priority of this recording (from 0 - 100) */
296 int iLifetime; /*!< @brief (optional) life time in days of this recording */
297 int iGenreType; /*!< @brief (optional) genre type */
298 int iGenreSubType; /*!< @brief (optional) genre sub type */
299 int iPlayCount; /*!< @brief (optional) play count of this recording on the client */
300 int iLastPlayedPosition; /*!< @brief (optional) last played position of this recording on the client */
301 bool bIsDeleted; /*!< @brief (optional) shows this recording is deleted and can be undelete */
302 } ATTRIBUTE_PACKED PVR_RECORDING;
303
304 /*!
305 * @brief Edit definition list (EDL)
306 */
307 typedef enum
308 {
309 PVR_EDL_TYPE_CUT = 0, /*!< @brief cut (completly remove content) */
310 PVR_EDL_TYPE_MUTE = 1, /*!< @brief mute audio */
311 PVR_EDL_TYPE_SCENE = 2, /*!< @brief scene markers (chapter seeking) */
312 PVR_EDL_TYPE_COMBREAK = 3 /*!< @brief commercial breaks */
313 } PVR_EDL_TYPE;
314
315 typedef struct PVR_EDL_ENTRY
316 {
317 int64_t start; // ms
318 int64_t end; // ms
319 PVR_EDL_TYPE type;
320 } ATTRIBUTE_PACKED PVR_EDL_ENTRY;
321
322 /*!
323 * @brief PVR menu hook data
324 */
325 typedef struct PVR_MENUHOOK_DATA
326 {
327 PVR_MENUHOOK_CAT cat;
328 union data {
329 int iEpgUid;
330 PVR_CHANNEL channel;
331 PVR_TIMER timer;
332 PVR_RECORDING recording;
333 } data;
334 } ATTRIBUTE_PACKED PVR_MENUHOOK_DATA;
335
336 /*!
337 * @brief Structure to transfer the methods from xbmc_pvr_dll.h to XBMC
338 */
339 typedef struct PVRClient
340 {
341 const char* (__cdecl* GetPVRAPIVersion)(void);
342 const char* (__cdecl* GetMininumPVRAPIVersion)(void);
343 const char* (__cdecl* GetGUIAPIVersion)(void);
344 const char* (__cdecl* GetMininumGUIAPIVersion)(void);
345 PVR_ERROR (__cdecl* GetAddonCapabilities)(PVR_ADDON_CAPABILITIES*);
346 PVR_ERROR (__cdecl* GetStreamProperties)(PVR_STREAM_PROPERTIES*);
347 const char* (__cdecl* GetBackendName)(void);
348 const char* (__cdecl* GetBackendVersion)(void);
349 const char* (__cdecl* GetConnectionString)(void);
350 PVR_ERROR (__cdecl* GetDriveSpace)(long long*, long long*);
351 PVR_ERROR (__cdecl* MenuHook)(const PVR_MENUHOOK&, const PVR_MENUHOOK_DATA&);
352 PVR_ERROR (__cdecl* GetEpg)(ADDON_HANDLE, const PVR_CHANNEL&, time_t, time_t);
353 int (__cdecl* GetChannelGroupsAmount)(void);
354 PVR_ERROR (__cdecl* GetChannelGroups)(ADDON_HANDLE, bool);
355 PVR_ERROR (__cdecl* GetChannelGroupMembers)(ADDON_HANDLE, const PVR_CHANNEL_GROUP&);
356 PVR_ERROR (__cdecl* OpenDialogChannelScan)(void);
357 int (__cdecl* GetChannelsAmount)(void);
358 PVR_ERROR (__cdecl* GetChannels)(ADDON_HANDLE, bool);
359 PVR_ERROR (__cdecl* DeleteChannel)(const PVR_CHANNEL&);
360 PVR_ERROR (__cdecl* RenameChannel)(const PVR_CHANNEL&);
361 PVR_ERROR (__cdecl* MoveChannel)(const PVR_CHANNEL&);
362 PVR_ERROR (__cdecl* OpenDialogChannelSettings)(const PVR_CHANNEL&);
363 PVR_ERROR (__cdecl* OpenDialogChannelAdd)(const PVR_CHANNEL&);
364 int (__cdecl* GetRecordingsAmount)(bool);
365 PVR_ERROR (__cdecl* GetRecordings)(ADDON_HANDLE, bool);
366 PVR_ERROR (__cdecl* DeleteRecording)(const PVR_RECORDING&);
367 PVR_ERROR (__cdecl* UndeleteRecording)(const PVR_RECORDING&);
368 PVR_ERROR (__cdecl* DeleteAllRecordingsFromTrash)(void);
369 PVR_ERROR (__cdecl* RenameRecording)(const PVR_RECORDING&);
370 PVR_ERROR (__cdecl* SetRecordingPlayCount)(const PVR_RECORDING&, int);
371 PVR_ERROR (__cdecl* SetRecordingLastPlayedPosition)(const PVR_RECORDING&, int);
372 int (__cdecl* GetRecordingLastPlayedPosition)(const PVR_RECORDING&);
373 PVR_ERROR (__cdecl* GetRecordingEdl)(const PVR_RECORDING&, PVR_EDL_ENTRY[], int*);
374 int (__cdecl* GetTimersAmount)(void);
375 PVR_ERROR (__cdecl* GetTimers)(ADDON_HANDLE);
376 PVR_ERROR (__cdecl* AddTimer)(const PVR_TIMER&);
377 PVR_ERROR (__cdecl* DeleteTimer)(const PVR_TIMER&, bool);
378 PVR_ERROR (__cdecl* UpdateTimer)(const PVR_TIMER&);
379 bool (__cdecl* OpenLiveStream)(const PVR_CHANNEL&);
380 void (__cdecl* CloseLiveStream)(void);
381 int (__cdecl* ReadLiveStream)(unsigned char*, unsigned int);
382 long long (__cdecl* SeekLiveStream)(long long, int);
383 long long (__cdecl* PositionLiveStream)(void);
384 long long (__cdecl* LengthLiveStream)(void);
385 int (__cdecl* GetCurrentClientChannel)(void);
386 bool (__cdecl* SwitchChannel)(const PVR_CHANNEL&);
387 PVR_ERROR (__cdecl* SignalStatus)(PVR_SIGNAL_STATUS&);
388 const char* (__cdecl* GetLiveStreamURL)(const PVR_CHANNEL&);
389 bool (__cdecl* OpenRecordedStream)(const PVR_RECORDING&);
390 void (__cdecl* CloseRecordedStream)(void);
391 int (__cdecl* ReadRecordedStream)(unsigned char*, unsigned int);
392 long long (__cdecl* SeekRecordedStream)(long long, int);
393 long long (__cdecl* PositionRecordedStream)(void);
394 long long (__cdecl* LengthRecordedStream)(void);
395 void (__cdecl* DemuxReset)(void);
396 void (__cdecl* DemuxAbort)(void);
397 void (__cdecl* DemuxFlush)(void);
398 DemuxPacket* (__cdecl* DemuxRead)(void);
399 unsigned int (__cdecl* GetChannelSwitchDelay)(void);
400 bool (__cdecl* CanPauseStream)(void);
401 void (__cdecl* PauseStream)(bool);
402 bool (__cdecl* CanSeekStream)(void);
403 bool (__cdecl* SeekTime)(int, bool, double*);
404 void (__cdecl* SetSpeed)(int);
405 time_t (__cdecl* GetPlayingTime)(void);
406 time_t (__cdecl* GetBufferTimeStart)(void);
407 time_t (__cdecl* GetBufferTimeEnd)(void);
408 const char* (__cdecl* GetBackendHostname)(void);
409 } PVRClient;
410
411#ifdef __cplusplus
412}
413#endif
414
415#endif //__PVRCLIENT_TYPES_H__
diff --git a/xbmc/addons/include/xbmc_scr_dll.h b/xbmc/addons/include/xbmc_scr_dll.h
new file mode 100644
index 0000000..c4257b4
--- /dev/null
+++ b/xbmc/addons/include/xbmc_scr_dll.h
@@ -0,0 +1,45 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef __XBMC_SCR_H__
23#define __XBMC_SCR_H__
24
25#include "xbmc_addon_dll.h"
26#include "xbmc_scr_types.h"
27
28extern "C"
29{
30
31 // Functions that your visualisation must implement
32 void Start();
33 void Render();
34 void GetInfo(SCR_INFO* pInfo);
35
36 // function to export the above structure to XBMC
37 void __declspec(dllexport) get_addon(struct ScreenSaver* pScr)
38 {
39 pScr->Start = Start;
40 pScr->Render = Render;
41 pScr->GetInfo = GetInfo;
42 };
43};
44
45#endif
diff --git a/xbmc/addons/include/xbmc_scr_types.h b/xbmc/addons/include/xbmc_scr_types.h
new file mode 100644
index 0000000..fec3040
--- /dev/null
+++ b/xbmc/addons/include/xbmc_scr_types.h
@@ -0,0 +1,53 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef __SCREENSAVER_TYPES_H__
23#define __SCREENSAVER_TYPES_H__
24
25extern "C"
26{
27 struct SCR_INFO
28 {
29 int dummy;
30 };
31
32 struct SCR_PROPS
33 {
34 void *device;
35 int x;
36 int y;
37 int width;
38 int height;
39 float pixelRatio;
40 const char *name;
41 const char *presets;
42 const char *profile;
43 };
44
45 struct ScreenSaver
46 {
47 void (__cdecl* Start) ();
48 void (__cdecl* Render) ();
49 void (__cdecl* GetInfo)(SCR_INFO *info);
50 };
51}
52
53#endif // __SCREENSAVER_TYPES_H__
diff --git a/xbmc/addons/include/xbmc_stream_utils.hpp b/xbmc/addons/include/xbmc_stream_utils.hpp
new file mode 100644
index 0000000..927fe33
--- /dev/null
+++ b/xbmc/addons/include/xbmc_stream_utils.hpp
@@ -0,0 +1,264 @@
1#pragma once
2/*
3 * Copyright (C) 2005-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "xbmc_pvr_types.h"
23#include <algorithm>
24#include <map>
25
26namespace ADDON
27{
28 /**
29 * Represents a single stream. It extends the PODS to provide some operators
30 * overloads.
31 */
32 class XbmcPvrStream : public PVR_STREAM_PROPERTIES::PVR_STREAM
33 {
34 public:
35 XbmcPvrStream()
36 {
37 Clear();
38 }
39
40 XbmcPvrStream(const XbmcPvrStream &other)
41 {
42 memcpy(this, &other, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM));
43 }
44
45 XbmcPvrStream& operator=(const XbmcPvrStream &other)
46 {
47 memcpy(this, &other, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM));
48 return *this;
49 }
50
51 /**
52 * Compares this stream based on another stream
53 * @param other
54 * @return
55 */
56 inline bool operator==(const XbmcPvrStream &other) const
57 {
58 return iPhysicalId == other.iPhysicalId && iCodecId == other.iCodecId;
59 }
60
61 /**
62 * Compares this stream with another one so that video streams are sorted
63 * before any other streams and the others are sorted by the physical ID
64 * @param other
65 * @return
66 */
67 bool operator<(const XbmcPvrStream &other) const
68 {
69 if (iCodecType == XBMC_CODEC_TYPE_VIDEO)
70 return true;
71 else if (other.iCodecType != XBMC_CODEC_TYPE_VIDEO)
72 return iPhysicalId < other.iPhysicalId;
73 else
74 return false;
75 }
76
77 /**
78 * Clears the stream
79 */
80 void Clear()
81 {
82 memset(this, 0, sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM));
83 iCodecId = XBMC_INVALID_CODEC_ID;
84 iCodecType = XBMC_CODEC_TYPE_UNKNOWN;
85 }
86
87 /**
88 * Checks whether the stream has been cleared
89 * @return
90 */
91 inline bool IsCleared() const
92 {
93 return iCodecId == XBMC_INVALID_CODEC_ID &&
94 iCodecType == XBMC_CODEC_TYPE_UNKNOWN;
95 }
96 };
97
98 class XbmcStreamProperties
99 {
100 public:
101 typedef std::vector<XbmcPvrStream> stream_vector;
102
103 XbmcStreamProperties(void)
104 {
105 // make sure the vector won't have to resize itself later
106 m_streamVector = new stream_vector();
107 m_streamVector->reserve(PVR_STREAM_MAX_STREAMS);
108 }
109
110 virtual ~XbmcStreamProperties(void)
111 {
112 delete m_streamVector;
113 }
114
115 /**
116 * Resets the streams
117 */
118 void Clear(void)
119 {
120 m_streamVector->clear();
121 m_streamIndex.clear();
122 }
123
124 /**
125 * Returns the index of the stream with the specified physical ID, or -1 if
126 * there no stream is found. This method is called very often which is why
127 * we keep a separate map for this.
128 * @param iPhysicalId
129 * @return
130 */
131 int GetStreamId(unsigned int iPhysicalId) const
132 {
133 std::map<unsigned int, int>::const_iterator it = m_streamIndex.find(iPhysicalId);
134 if (it != m_streamIndex.end())
135 return it->second;
136
137 return -1;
138 }
139
140 /**
141 * Returns the stream with the specified physical ID, or null if no such
142 * stream exists
143 * @param iPhysicalId
144 * @return
145 */
146 XbmcPvrStream* GetStreamById(unsigned int iPhysicalId) const
147 {
148 int position = GetStreamId(iPhysicalId);
149 return position != -1 ? &m_streamVector->at(position) : NULL;
150 }
151
152 /**
153 * Populates the specified stream with the stream having the specified
154 * physical ID. If the stream is not found only target stream's physical ID
155 * will be populated.
156 * @param iPhysicalId
157 * @param stream
158 */
159 void GetStreamData(unsigned int iPhysicalId, XbmcPvrStream* stream)
160 {
161 XbmcPvrStream *foundStream = GetStreamById(iPhysicalId);
162 if (foundStream)
163 stream = foundStream;
164 else
165 {
166 stream->iIdentifier = -1;
167 stream->iPhysicalId = iPhysicalId;
168 }
169 }
170
171 /**
172 * Populates props with the current streams and returns whether there are
173 * any streams at the moment or not.
174 * @param props
175 * @return
176 */
177 bool GetProperties(PVR_STREAM_PROPERTIES* props)
178 {
179 unsigned int i = 0;
180 for (stream_vector::const_iterator it = m_streamVector->begin();
181 it != m_streamVector->end(); ++it, ++i)
182 {
183 memcpy(&props->stream[i], &(*it), sizeof(PVR_STREAM_PROPERTIES::PVR_STREAM));
184 }
185
186 props->iStreamCount = m_streamVector->size();
187 return (props->iStreamCount > 0);
188 }
189
190 /**
191 * Merges new streams into the current list of streams. Identical streams
192 * will retain their respective indexes and new streams will replace unused
193 * indexes or be appended.
194 * @param newStreams
195 */
196 void UpdateStreams(stream_vector &newStreams)
197 {
198 // sort the new streams
199 std::sort(newStreams.begin(), newStreams.end());
200
201 // ensure we never have more than PVR_STREAMS_MAX_STREAMS streams
202 if (newStreams.size() > PVR_STREAM_MAX_STREAMS)
203 {
204 while (newStreams.size() > PVR_STREAM_MAX_STREAMS)
205 newStreams.pop_back();
206
207 XBMC->Log(LOG_ERROR, "%s - max amount of streams reached", __FUNCTION__);
208 }
209
210 stream_vector::iterator newStreamPosition;
211 for (stream_vector::iterator it = m_streamVector->begin(); it != m_streamVector->end(); ++it)
212 {
213 newStreamPosition = std::find(newStreams.begin(), newStreams.end(), *it);
214
215 // if the current stream no longer exists we clear it, otherwise we
216 // copy it and remove it from newStreams
217 if (newStreamPosition == newStreams.end())
218 it->Clear();
219 else
220 {
221 *it = *newStreamPosition;
222 newStreams.erase(newStreamPosition);
223 }
224 }
225
226 // replace cleared streams with new streams
227 for (stream_vector::iterator it = m_streamVector->begin();
228 it != m_streamVector->end() && !newStreams.empty(); ++it)
229 {
230 if (it->IsCleared())
231 {
232 *it = newStreams.front();
233 newStreams.erase(newStreams.begin());
234 }
235 }
236
237 // append any remaining new streams
238 m_streamVector->insert(m_streamVector->end(), newStreams.begin(), newStreams.end());
239
240 // remove trailing cleared streams
241 while (m_streamVector->back().IsCleared())
242 m_streamVector->pop_back();
243
244 // update the index
245 UpdateIndex();
246 }
247
248 private:
249 stream_vector *m_streamVector;
250 std::map<unsigned int, int> m_streamIndex;
251
252 /**
253 * Updates the stream index
254 */
255 void UpdateIndex()
256 {
257 m_streamIndex.clear();
258
259 int i = 0;
260 for (stream_vector::const_iterator it = m_streamVector->begin(); it != m_streamVector->end(); ++it, ++i)
261 m_streamIndex[it->iPhysicalId] = i;
262 }
263 };
264}
diff --git a/xbmc/addons/include/xbmc_vis_dll.h b/xbmc/addons/include/xbmc_vis_dll.h
new file mode 100644
index 0000000..c65f844
--- /dev/null
+++ b/xbmc/addons/include/xbmc_vis_dll.h
@@ -0,0 +1,55 @@
1#ifndef __XBMC_VIS_H__
2#define __XBMC_VIS_H__
3
4/*
5 * Copyright (C) 2005-2013 Team XBMC
6 * http://xbmc.org
7 *
8 * This Program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This Program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with XBMC; see the file COPYING. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include "xbmc_addon_dll.h"
25#include "xbmc_vis_types.h"
26
27extern "C"
28{
29 // Functions that your visualisation must implement
30 void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName);
31 void AudioData(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength);
32 void Render();
33 bool OnAction(long action, const void *param);
34 void GetInfo(VIS_INFO* pInfo);
35 unsigned int GetPresets(char ***presets);
36 unsigned GetPreset();
37 unsigned int GetSubModules(char ***presets);
38 bool IsLocked();
39
40 // function to export the above structure to XBMC
41 void __declspec(dllexport) get_addon(struct Visualisation* pVisz)
42 {
43 pVisz->Start = Start;
44 pVisz->AudioData = AudioData;
45 pVisz->Render = Render;
46 pVisz->OnAction = OnAction;
47 pVisz->GetInfo = GetInfo;
48 pVisz->GetPresets = GetPresets;
49 pVisz->GetPreset = GetPreset;
50 pVisz->GetSubModules = GetSubModules;
51 pVisz->IsLocked = IsLocked;
52 };
53};
54
55#endif
diff --git a/xbmc/addons/include/xbmc_vis_types.h b/xbmc/addons/include/xbmc_vis_types.h
new file mode 100644
index 0000000..e6b0ccd
--- /dev/null
+++ b/xbmc/addons/include/xbmc_vis_types.h
@@ -0,0 +1,111 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21/*
22 Common data structures shared between XBMC and XBMC's visualisations
23 */
24
25#ifndef __VISUALISATION_TYPES_H__
26#define __VISUALISATION_TYPES_H__
27#include <cstddef>
28
29extern "C"
30{
31 struct VIS_INFO
32 {
33 int bWantsFreq;
34 int iSyncDelay;
35 };
36
37 struct VIS_PROPS
38 {
39 void *device;
40 int x;
41 int y;
42 int width;
43 int height;
44 float pixelRatio;
45 const char *name;
46 const char *presets;
47 const char *profile;
48 const char *submodule;
49 };
50
51 enum VIS_ACTION
52 {
53 VIS_ACTION_NONE = 0,
54 VIS_ACTION_NEXT_PRESET,
55 VIS_ACTION_PREV_PRESET,
56 VIS_ACTION_LOAD_PRESET,
57 VIS_ACTION_RANDOM_PRESET,
58 VIS_ACTION_LOCK_PRESET,
59 VIS_ACTION_RATE_PRESET_PLUS,
60 VIS_ACTION_RATE_PRESET_MINUS,
61 VIS_ACTION_UPDATE_ALBUMART,
62 VIS_ACTION_UPDATE_TRACK
63 };
64
65 class VisTrack
66 {
67 public:
68 VisTrack()
69 {
70 title = artist = album = albumArtist = NULL;
71 genre = comment = lyrics = reserved1 = reserved2 = NULL;
72 trackNumber = discNumber = duration = year = 0;
73 rating = 0;
74 reserved3 = reserved4 = 0;
75 }
76
77 const char *title;
78 const char *artist;
79 const char *album;
80 const char *albumArtist;
81 const char *genre;
82 const char *comment;
83 const char *lyrics;
84 const char *reserved1;
85 const char *reserved2;
86
87 int trackNumber;
88 int discNumber;
89 int duration;
90 int year;
91 char rating;
92 int reserved3;
93 int reserved4;
94 };
95
96 struct Visualisation
97 {
98 void (__cdecl* Start)(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName);
99 void (__cdecl* AudioData)(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength);
100 void (__cdecl* Render) ();
101 void (__cdecl* GetInfo)(VIS_INFO *info);
102 bool (__cdecl* OnAction)(long flags, const void *param);
103 int (__cdecl* HasPresets)();
104 unsigned int (__cdecl *GetPresets)(char ***presets);
105 unsigned int (__cdecl *GetPreset)();
106 unsigned int (__cdecl *GetSubModules)(char ***modules);
107 bool (__cdecl* IsLocked)();
108 };
109}
110
111#endif //__VISUALISATION_TYPES_H__
diff --git a/xbmc/addons/test/Makefile b/xbmc/addons/test/Makefile
new file mode 100644
index 0000000..bf74bd6
--- /dev/null
+++ b/xbmc/addons/test/Makefile
@@ -0,0 +1,9 @@
1SRCS= \
2 TestAddonVersion.cpp
3
4LIB=addonsTest.a
5
6INCLUDES += -I../../../lib/gtest/include
7
8include ../../../Makefile.include
9-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
diff --git a/xbmc/addons/test/TestAddonVersion.cpp b/xbmc/addons/test/TestAddonVersion.cpp
new file mode 100644
index 0000000..41e71a4
--- /dev/null
+++ b/xbmc/addons/test/TestAddonVersion.cpp
@@ -0,0 +1,254 @@
1/*
2 * Copyright (C) 2005-2014 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "addons/AddonVersion.h"
22
23#include "gtest/gtest.h"
24
25using namespace ADDON;
26
27class TestAddonVersion : public testing::Test
28{
29public:
30 TestAddonVersion()
31 : v1_0("1.0"),
32 v1_00("1.00"),
33 v1_0_0("1.0.0"),
34 v1_1("1.1"),
35 v1_01("1.01"),
36 v1_0_1("1.0.1"),
37 e1_v1_0_0("1:1.0.0"),
38 e1_v1_0_1("1:1.0.1"),
39 e2_v1_0_0("2:1.0.0"),
40 e1_v1_0_0_r1("1:1.0.0-1"),
41 e1_v1_0_1_r1("1:1.0.1-1"),
42 e1_v1_0_0_r2("1:1.0.0-2"),
43 v1_0_0_beta("1.0.0~beta"),
44 v1_0_0_alpha("1.0.0~alpha"),
45 v1_0_0_alpha2("1.0.0~alpha2"),
46 v1_0_0_alpha3("1.0.0~alpha3"),
47 v1_0_0_alpha10("1.0.0~alpha10")
48 {
49 }
50
51 AddonVersion v1_0;
52 AddonVersion v1_00;
53 AddonVersion v1_0_0;
54 AddonVersion v1_1;
55 AddonVersion v1_01;
56 AddonVersion v1_0_1;
57 AddonVersion e1_v1_0_0;
58 AddonVersion e1_v1_0_1;
59 AddonVersion e2_v1_0_0;
60 AddonVersion e1_v1_0_0_r1;
61 AddonVersion e1_v1_0_1_r1;
62 AddonVersion e1_v1_0_0_r2;
63 AddonVersion v1_0_0_beta;
64 AddonVersion v1_0_0_alpha;
65 AddonVersion v1_0_0_alpha2;
66 AddonVersion v1_0_0_alpha3;
67 AddonVersion v1_0_0_alpha10;
68};
69
70TEST_F(TestAddonVersion, Constructor)
71{
72 EXPECT_EQ(v1_0.Upstream(), "1.0");
73 EXPECT_EQ(v1_0.Epoch(), 0);
74 EXPECT_TRUE(v1_0.Revision().empty());
75
76 EXPECT_EQ(v1_00.Upstream(), "1.00");
77 EXPECT_EQ(v1_00.Epoch(), 0);
78 EXPECT_TRUE(v1_00.Revision().empty());
79
80 EXPECT_EQ(v1_0_0.Upstream(), "1.0.0");
81 EXPECT_EQ(v1_0_0.Epoch(), 0);
82 EXPECT_TRUE(v1_0_0.Revision().empty());
83
84 EXPECT_EQ(v1_1.Upstream(), "1.1");
85 EXPECT_EQ(v1_1.Epoch(), 0);
86 EXPECT_TRUE(v1_1.Revision().empty());
87
88 EXPECT_EQ(v1_01.Upstream(), "1.01");
89 EXPECT_EQ(v1_01.Epoch(), 0);
90 EXPECT_TRUE(v1_01.Revision().empty());
91
92 EXPECT_EQ(v1_0_1.Upstream(), "1.0.1");
93 EXPECT_EQ(v1_0_1.Epoch(), 0);
94 EXPECT_TRUE(v1_0_1.Revision().empty());
95
96 EXPECT_EQ(e1_v1_0_0.Upstream(), "1.0.0");
97 EXPECT_EQ(e1_v1_0_0.Epoch(), 1);
98 EXPECT_TRUE(e1_v1_0_0.Revision().empty());
99
100 EXPECT_EQ(e1_v1_0_1.Upstream(), "1.0.1");
101 EXPECT_EQ(e1_v1_0_1.Epoch(), 1);
102 EXPECT_TRUE(e1_v1_0_1.Revision().empty());
103
104 EXPECT_EQ(e2_v1_0_0.Upstream(), "1.0.0");
105 EXPECT_EQ(e2_v1_0_0.Epoch(), 2);
106 EXPECT_TRUE(e2_v1_0_0.Revision().empty());
107
108 EXPECT_EQ(e1_v1_0_0_r1.Upstream(), "1.0.0");
109 EXPECT_EQ(e1_v1_0_0_r1.Epoch(), 1);
110 EXPECT_EQ(e1_v1_0_0_r1.Revision(), "1");
111
112 EXPECT_EQ(e1_v1_0_1_r1.Upstream(), "1.0.1");
113 EXPECT_EQ(e1_v1_0_1_r1.Epoch(), 1);
114 EXPECT_EQ(e1_v1_0_1_r1.Revision(), "1");
115
116 EXPECT_EQ(e1_v1_0_0_r2.Upstream(), "1.0.0");
117 EXPECT_EQ(e1_v1_0_0_r2.Epoch(), 1);
118 EXPECT_EQ(e1_v1_0_0_r2.Revision(), "2");
119
120 EXPECT_EQ(v1_0_0_beta.Upstream(), "1.0.0~beta");
121 EXPECT_EQ(v1_0_0_beta.Epoch(), 0);
122 EXPECT_TRUE(v1_0_0_beta.Revision().empty());
123
124 EXPECT_EQ(v1_0_0_alpha.Upstream(), "1.0.0~alpha");
125 EXPECT_EQ(v1_0_0_alpha.Epoch(), 0);
126 EXPECT_TRUE(v1_0_0_alpha.Revision().empty());
127
128 EXPECT_EQ(v1_0_0_alpha2.Upstream(), "1.0.0~alpha2");
129 EXPECT_EQ(v1_0_0_alpha2.Epoch(), 0);
130 EXPECT_TRUE(v1_0_0_alpha2.Revision().empty());
131
132 EXPECT_EQ(v1_0_0_alpha3.Upstream(), "1.0.0~alpha3");
133 EXPECT_EQ(v1_0_0_alpha3.Epoch(), 0);
134 EXPECT_TRUE(v1_0_0_alpha3.Revision().empty());
135
136 EXPECT_EQ(v1_0_0_alpha10.Upstream(), "1.0.0~alpha10");
137 EXPECT_EQ(v1_0_0_alpha10.Epoch(), 0);
138 EXPECT_TRUE(v1_0_0_alpha10.Revision().empty());
139}
140
141TEST_F(TestAddonVersion, asString)
142{
143 EXPECT_EQ(v1_0.asString(), "1.0");
144 EXPECT_EQ(v1_00.asString(), "1.00");
145 EXPECT_EQ(v1_0_0.asString(), "1.0.0");
146 EXPECT_EQ(v1_1.asString(), "1.1");
147 EXPECT_EQ(v1_01.asString(), "1.01");
148 EXPECT_EQ(v1_0_1.asString(), "1.0.1");
149 EXPECT_EQ(e1_v1_0_0.asString(), "1:1.0.0");
150 EXPECT_EQ(e1_v1_0_1.asString(), "1:1.0.1");
151 EXPECT_EQ(e2_v1_0_0.asString(), "2:1.0.0");
152 EXPECT_EQ(e1_v1_0_0_r1.asString(), "1:1.0.0-1");
153 EXPECT_EQ(e1_v1_0_1_r1.asString(), "1:1.0.1-1");
154 EXPECT_EQ(e1_v1_0_0_r2.asString(), "1:1.0.0-2");
155 EXPECT_EQ(v1_0_0_beta.asString(), "1.0.0~beta");
156 EXPECT_EQ(v1_0_0_alpha.asString(), "1.0.0~alpha");
157 EXPECT_EQ(v1_0_0_alpha2.asString(), "1.0.0~alpha2");
158 EXPECT_EQ(v1_0_0_alpha3.asString(), "1.0.0~alpha3");
159 EXPECT_EQ(v1_0_0_alpha10.asString(), "1.0.0~alpha10");
160}
161
162TEST_F(TestAddonVersion, Equals)
163{
164 EXPECT_EQ(v1_0, AddonVersion("1.0"));
165 EXPECT_EQ(v1_00, AddonVersion("1.00"));
166 EXPECT_EQ(v1_0_0, AddonVersion("1.0.0"));
167 EXPECT_EQ(v1_1, AddonVersion("1.1"));
168 EXPECT_EQ(v1_01, AddonVersion("1.01"));
169 EXPECT_EQ(v1_0_1, AddonVersion("1.0.1"));
170 EXPECT_EQ(e1_v1_0_0, AddonVersion("1:1.0.0"));
171 EXPECT_EQ(e1_v1_0_1, AddonVersion("1:1.0.1"));
172 EXPECT_EQ(e2_v1_0_0, AddonVersion("2:1.0.0"));
173 EXPECT_EQ(e1_v1_0_0_r1, AddonVersion("1:1.0.0-1"));
174 EXPECT_EQ(e1_v1_0_1_r1, AddonVersion("1:1.0.1-1"));
175 EXPECT_EQ(e1_v1_0_0_r2, AddonVersion("1:1.0.0-2"));
176 EXPECT_EQ(v1_0_0_beta, AddonVersion("1.0.0~beta"));
177 EXPECT_EQ(v1_0_0_alpha, AddonVersion("1.0.0~alpha"));
178 EXPECT_EQ(v1_0_0_alpha2, AddonVersion("1.0.0~alpha2"));
179 EXPECT_EQ(v1_0_0_alpha3, AddonVersion("1.0.0~alpha3"));
180 EXPECT_EQ(v1_0_0_alpha10, AddonVersion("1.0.0~alpha10"));
181}
182
183TEST_F(TestAddonVersion, Equivalent)
184{
185 EXPECT_FALSE(v1_0 != v1_00);
186 EXPECT_FALSE(v1_0 < v1_00);
187 EXPECT_FALSE(v1_0 > v1_00);
188 EXPECT_TRUE(v1_0 == v1_00);
189
190 EXPECT_FALSE(v1_01 != v1_1);
191 EXPECT_FALSE(v1_01 < v1_1);
192 EXPECT_FALSE(v1_01 > v1_1);
193 EXPECT_TRUE(v1_01 == v1_1);
194}
195
196TEST_F(TestAddonVersion, LessThan)
197{
198 EXPECT_LT(v1_0, v1_0_0);
199 EXPECT_LT(v1_0, v1_1);
200 EXPECT_LT(v1_0, v1_01);
201 EXPECT_LT(v1_0, v1_0_1);
202
203 EXPECT_LT(v1_00, v1_0_0);
204 EXPECT_LT(v1_00, v1_1);
205 EXPECT_LT(v1_00, v1_01);
206 EXPECT_LT(v1_00, v1_0_1);
207
208 EXPECT_LT(v1_0_0, v1_1);
209 EXPECT_LT(v1_0_0, v1_01);
210 EXPECT_LT(v1_0_0, v1_0_1);
211
212 EXPECT_LT(v1_0_1, v1_01);
213 EXPECT_LT(v1_0_1, v1_1);
214
215 // epochs
216 EXPECT_LT(v1_0_0, e1_v1_0_0);
217 EXPECT_LT(v1_0_0, e1_v1_0_1);
218 EXPECT_LT(v1_0_0, e2_v1_0_0);
219 EXPECT_LT(v1_0_1, e1_v1_0_1);
220 EXPECT_LT(v1_0_1, e2_v1_0_0);
221
222 EXPECT_LT(e1_v1_0_0, e1_v1_0_1);
223 EXPECT_LT(e1_v1_0_0, e2_v1_0_0);
224 EXPECT_LT(e1_v1_0_1, e2_v1_0_0);
225
226 // revisions
227 EXPECT_LT(e1_v1_0_0, e1_v1_0_0_r1);
228 EXPECT_LT(e1_v1_0_0, e1_v1_0_1_r1);
229 EXPECT_LT(e1_v1_0_0, e1_v1_0_0_r2);
230 EXPECT_LT(e1_v1_0_1, e1_v1_0_1_r1);
231 EXPECT_LT(e1_v1_0_0_r1, e1_v1_0_1);
232 EXPECT_LT(e1_v1_0_0_r1, e1_v1_0_1_r1);
233 EXPECT_LT(e1_v1_0_0_r1, e1_v1_0_0_r2);
234 EXPECT_LT(e1_v1_0_0_r2, e1_v1_0_1);
235 EXPECT_LT(e1_v1_0_0_r2, e1_v1_0_1_r1);
236 EXPECT_LT(e1_v1_0_1_r1, e2_v1_0_0);
237
238 // alpha, beta
239 EXPECT_LT(v1_0_0_beta, v1_0_0);
240 EXPECT_LT(v1_0_0_alpha, v1_0_0);
241 EXPECT_LT(v1_0_0_alpha, v1_0_0_beta);
242 EXPECT_LT(v1_0_0_alpha, v1_0_0_alpha2);
243 EXPECT_LT(v1_0_0_alpha, v1_0_0_alpha3);
244 EXPECT_LT(v1_0_0_alpha, v1_0_0_alpha10);
245 EXPECT_LT(v1_0_0_alpha2, v1_0_0);
246 EXPECT_LT(v1_0_0_alpha2, v1_0_0_beta);
247 EXPECT_LT(v1_0_0_alpha2, v1_0_0_alpha3);
248 EXPECT_LT(v1_0_0_alpha2, v1_0_0_alpha10);
249 EXPECT_LT(v1_0_0_alpha3, v1_0_0);
250 EXPECT_LT(v1_0_0_alpha3, v1_0_0_beta);
251 EXPECT_LT(v1_0_0_alpha3, v1_0_0_alpha10);
252 EXPECT_LT(v1_0_0_alpha10, v1_0_0);
253 EXPECT_LT(v1_0_0_alpha10, v1_0_0_beta);
254}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp
new file mode 100644
index 0000000..2f833c5
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp
@@ -0,0 +1,184 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDDemux.h"
22#include "DVDCodecs/DVDCodecs.h"
23
24void CDemuxStreamTeletext::GetStreamInfo(std::string& strInfo)
25{
26 strInfo = "Teletext Data Stream";
27}
28
29void CDemuxStreamAudio::GetStreamType(std::string& strInfo)
30{
31 char sInfo[64];
32
33 if (codec == AV_CODEC_ID_AC3) strcpy(sInfo, "AC3 ");
34 else if (codec == AV_CODEC_ID_DTS)
35 {
36#ifdef FF_PROFILE_DTS_HD_MA
37 if (profile == FF_PROFILE_DTS_HD_MA)
38 strcpy(sInfo, "DTS-HD MA ");
39 else if (profile == FF_PROFILE_DTS_HD_HRA)
40 strcpy(sInfo, "DTS-HD HRA ");
41 else
42#endif
43 strcpy(sInfo, "DTS ");
44 }
45 else if (codec == AV_CODEC_ID_MP2) strcpy(sInfo, "MP2 ");
46 else if (codec == AV_CODEC_ID_TRUEHD) strcpy(sInfo, "Dolby TrueHD ");
47 else strcpy(sInfo, "");
48
49 if (iChannels == 1) strcat(sInfo, "Mono");
50 else if (iChannels == 2) strcat(sInfo, "Stereo");
51 else if (iChannels == 6) strcat(sInfo, "5.1");
52 else if (iChannels == 8) strcat(sInfo, "7.1");
53 else if (iChannels != 0)
54 {
55 char temp[32];
56 sprintf(temp, " %d%s", iChannels, "-chs");
57 strcat(sInfo, temp);
58 }
59 strInfo = sInfo;
60}
61
62int CDVDDemux::GetNrOfAudioStreams()
63{
64 int iCounter = 0;
65
66 for (int i = 0; i < GetNrOfStreams(); i++)
67 {
68 CDemuxStream* pStream = GetStream(i);
69 if (pStream->type == STREAM_AUDIO) iCounter++;
70 }
71
72 return iCounter;
73}
74
75int CDVDDemux::GetNrOfVideoStreams()
76{
77 int iCounter = 0;
78
79 for (int i = 0; i < GetNrOfStreams(); i++)
80 {
81 CDemuxStream* pStream = GetStream(i);
82 if (pStream->type == STREAM_VIDEO) iCounter++;
83 }
84
85 return iCounter;
86}
87
88int CDVDDemux::GetNrOfSubtitleStreams()
89{
90 int iCounter = 0;
91
92 for (int i = 0; i < GetNrOfStreams(); i++)
93 {
94 CDemuxStream* pStream = GetStream(i);
95 if (pStream->type == STREAM_SUBTITLE) iCounter++;
96 }
97
98 return iCounter;
99}
100
101int CDVDDemux::GetNrOfTeletextStreams()
102{
103 int iCounter = 0;
104
105 for (int i = 0; i < GetNrOfStreams(); i++)
106 {
107 CDemuxStream* pStream = GetStream(i);
108 if (pStream->type == STREAM_TELETEXT) iCounter++;
109 }
110
111 return iCounter;
112}
113
114CDemuxStreamAudio* CDVDDemux::GetStreamFromAudioId(int iAudioIndex)
115{
116 int counter = -1;
117 for (int i = 0; i < GetNrOfStreams(); i++)
118 {
119 CDemuxStream* pStream = GetStream(i);
120
121 if (pStream->type == STREAM_AUDIO) counter++;
122 if (iAudioIndex == counter)
123 return (CDemuxStreamAudio*)pStream;
124 }
125 return NULL;
126}
127
128CDemuxStreamVideo* CDVDDemux::GetStreamFromVideoId(int iVideoIndex)
129{
130 int counter = -1;
131 for (int i = 0; i < GetNrOfStreams(); i++)
132 {
133 CDemuxStream* pStream = GetStream(i);
134
135 if (pStream->type == STREAM_VIDEO) counter++;
136 if (iVideoIndex == counter)
137 return (CDemuxStreamVideo*)pStream;
138 }
139 return NULL;
140}
141
142CDemuxStreamSubtitle* CDVDDemux::GetStreamFromSubtitleId(int iSubtitleIndex)
143{
144 int counter = -1;
145 for (int i = 0; i < GetNrOfStreams(); i++)
146 {
147 CDemuxStream* pStream = GetStream(i);
148
149 if (pStream->type == STREAM_SUBTITLE) counter++;
150 if (iSubtitleIndex == counter)
151 return (CDemuxStreamSubtitle*)pStream;
152 }
153 return NULL;
154}
155
156CDemuxStreamTeletext* CDVDDemux::GetStreamFromTeletextId(int iTeletextIndex)
157{
158 int counter = -1;
159 for (int i = 0; i < GetNrOfStreams(); i++)
160 {
161 CDemuxStream* pStream = GetStream(i);
162
163 if (pStream->type == STREAM_TELETEXT) counter++;
164 if (iTeletextIndex == counter)
165 return (CDemuxStreamTeletext*)pStream;
166 }
167 return NULL;
168}
169
170void CDemuxStream::GetStreamName( std::string& strInfo )
171{
172 strInfo = "";
173}
174
175AVDiscard CDemuxStream::GetDiscard()
176{
177 return AVDISCARD_NONE;
178}
179
180void CDemuxStream::SetDiscard(AVDiscard discard)
181{
182 return;
183}
184
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
new file mode 100644
index 0000000..fca164d
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
@@ -0,0 +1,359 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <string>
24#include "system.h"
25#include "DVDDemuxPacket.h"
26
27class CDVDInputStream;
28
29#ifndef __GNUC__
30#pragma warning(push)
31#pragma warning(disable:4244)
32#endif
33
34#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
35 #include "config.h"
36#endif
37
38extern "C" {
39#include "libavcodec/avcodec.h"
40}
41
42#ifndef __GNUC__
43#pragma warning(pop)
44#endif
45
46enum AVDiscard;
47
48enum StreamType
49{
50 STREAM_NONE = 0,// if unknown
51 STREAM_AUDIO, // audio stream
52 STREAM_VIDEO, // video stream
53 STREAM_DATA, // data stream
54 STREAM_SUBTITLE,// subtitle stream
55 STREAM_TELETEXT // Teletext data stream
56};
57
58enum StreamSource {
59 STREAM_SOURCE_NONE = 0x000,
60 STREAM_SOURCE_DEMUX = 0x100,
61 STREAM_SOURCE_NAV = 0x200,
62 STREAM_SOURCE_DEMUX_SUB = 0x300,
63 STREAM_SOURCE_TEXT = 0x400,
64 STREAM_SOURCE_VIDEOMUX = 0x500
65};
66
67#define STREAM_SOURCE_MASK(a) ((a) & 0xf00)
68
69/*
70 * CDemuxStream
71 * Base class for all demuxer streams
72 */
73class CDemuxStream
74{
75public:
76 CDemuxStream()
77 {
78 iId = 0;
79 iPhysicalId = 0;
80 codec = (AVCodecID)0; // AV_CODEC_ID_NONE
81 codec_fourcc = 0;
82 profile = FF_PROFILE_UNKNOWN;
83 level = FF_LEVEL_UNKNOWN;
84 type = STREAM_NONE;
85 source = STREAM_SOURCE_NONE;
86 iDuration = 0;
87 pPrivate = NULL;
88 ExtraData = NULL;
89 ExtraSize = 0;
90 memset(language, 0, sizeof(language));
91 disabled = false;
92 changes = 0;
93 flags = FLAG_NONE;
94 orig_type = 0;
95 }
96
97 virtual ~CDemuxStream()
98 {
99 delete [] ExtraData;
100 }
101
102 virtual void GetStreamInfo(std::string& strInfo)
103 {
104 strInfo = "";
105 }
106
107 virtual void GetStreamName(std::string& strInfo);
108
109 virtual void SetDiscard(AVDiscard discard);
110 virtual AVDiscard GetDiscard();
111
112 int iId; // most of the time starting from 0
113 int iPhysicalId; // id
114 AVCodecID codec;
115 unsigned int codec_fourcc; // if available
116 int profile; // encoder profile of the stream reported by the decoder. used to qualify hw decoders.
117 int level; // encoder level of the stream reported by the decoder. used to qualify hw decoders.
118 StreamType type;
119 int source;
120
121 int iDuration; // in mseconds
122 void* pPrivate; // private pointer for the demuxer
123 uint8_t* ExtraData; // extra data for codec to use
124 unsigned int ExtraSize; // size of extra data
125
126 char language[4]; // ISO 639 3-letter language code (empty string if undefined)
127 bool disabled; // set when stream is disabled. (when no decoder exists)
128
129 int changes; // increment on change which player may need to know about
130
131 int orig_type; // type of original source
132
133 enum EFlags
134 { FLAG_NONE = 0x0000
135 , FLAG_DEFAULT = 0x0001
136 , FLAG_DUB = 0x0002
137 , FLAG_ORIGINAL = 0x0004
138 , FLAG_COMMENT = 0x0008
139 , FLAG_LYRICS = 0x0010
140 , FLAG_KARAOKE = 0x0020
141 , FLAG_FORCED = 0x0040
142 , FLAG_HEARING_IMPAIRED = 0x0080
143 , FLAG_VISUAL_IMPAIRED = 0x0100
144 } flags;
145};
146
147class CDemuxStreamVideo : public CDemuxStream
148{
149public:
150 CDemuxStreamVideo() : CDemuxStream()
151 {
152 iFpsScale = 0;
153 iFpsRate = 0;
154 irFpsScale = 0;
155 irFpsRate = 0;
156 iHeight = 0;
157 iWidth = 0;
158 fAspect = 0.0;
159 bVFR = false;
160 bPTSInvalid = false;
161 bForcedAspect = false;
162 type = STREAM_VIDEO;
163 iOrientation = 0;
164 iBitsPerPixel = 0;
165 }
166
167 virtual ~CDemuxStreamVideo() {}
168 int iFpsScale; // scale of 1000 and a rate of 29970 will result in 29.97 fps
169 int iFpsRate;
170 int irFpsScale;
171 int irFpsRate;
172 int iHeight; // height of the stream reported by the demuxer
173 int iWidth; // width of the stream reported by the demuxer
174 float fAspect; // display aspect of stream
175 bool bVFR; // variable framerate
176 bool bPTSInvalid; // pts cannot be trusted (avi's).
177 bool bForcedAspect; // aspect is forced from container
178 int iOrientation; // orientation of the video in degress counter clockwise
179 int iBitsPerPixel;
180 std::string stereo_mode; // expected stereo mode
181};
182
183class CDemuxStreamAudio : public CDemuxStream
184{
185public:
186 CDemuxStreamAudio() : CDemuxStream()
187 {
188 iChannels = 0;
189 iSampleRate = 0;
190 iBlockAlign = 0;
191 iBitRate = 0;
192 iBitsPerSample = 0;
193 type = STREAM_AUDIO;
194 }
195
196 virtual ~CDemuxStreamAudio() {}
197
198 void GetStreamType(std::string& strInfo);
199
200 int iChannels;
201 int iSampleRate;
202 int iBlockAlign;
203 int iBitRate;
204 int iBitsPerSample;
205};
206
207class CDemuxStreamSubtitle : public CDemuxStream
208{
209public:
210 CDemuxStreamSubtitle() : CDemuxStream()
211 {
212 type = STREAM_SUBTITLE;
213 }
214};
215
216class CDemuxStreamTeletext : public CDemuxStream
217{
218public:
219 CDemuxStreamTeletext() : CDemuxStream()
220 {
221 type = STREAM_TELETEXT;
222 }
223 virtual void GetStreamInfo(std::string& strInfo);
224};
225
226class CDVDDemux
227{
228public:
229
230 CDVDDemux() {}
231 virtual ~CDVDDemux() {}
232
233
234 /*
235 * Reset the entire demuxer (same result as closing and opening it)
236 */
237 virtual void Reset() = 0;
238
239 /*
240 * Aborts any internal reading that might be stalling main thread
241 * NOTICE - this can be called from another thread
242 */
243 virtual void Abort() = 0;
244
245 /*
246 * Flush the demuxer, if any data is kept in buffers, this should be freed now
247 */
248 virtual void Flush() = 0;
249
250 /*
251 * Read a packet, returns NULL on error
252 *
253 */
254 virtual DemuxPacket* Read() = 0;
255
256 /*
257 * Seek, time in msec calculated from stream start
258 */
259 virtual bool SeekTime(int time, bool backwords = false, double* startpts = NULL) = 0;
260
261 /*
262 * Seek to a specified chapter.
263 * startpts can be updated to the point where display should start
264 */
265 virtual bool SeekChapter(int chapter, double* startpts = NULL) { return false; }
266
267 /*
268 * Get the number of chapters available
269 */
270 virtual int GetChapterCount() { return 0; }
271
272 /*
273 * Get current chapter
274 */
275 virtual int GetChapter() { return 0; }
276
277 /*
278 * Get the name of a chapter
279 * \param strChapterName[out] Name of chapter
280 * \param chapterIdx -1 for current chapter, else a chapter index
281 */
282 virtual void GetChapterName(std::string& strChapterName, int chapterIdx=-1) {}
283
284 /*
285 * Get the position of a chapter
286 * \param chapterIdx -1 for current chapter, else a chapter index
287 */
288 virtual int64_t GetChapterPos(int chapterIdx=-1) { return 0; }
289
290 /*
291 * Set the playspeed, if demuxer can handle different
292 * speeds of playback
293 */
294 virtual void SetSpeed(int iSpeed) = 0;
295
296 /*
297 * returns the total time in msec
298 */
299 virtual int GetStreamLength() = 0;
300
301 /*
302 * returns the stream or NULL on error, starting from 0
303 */
304 virtual CDemuxStream* GetStream(int iStreamId) = 0;
305
306 /*
307 * return nr of streams, 0 if none
308 */
309 virtual int GetNrOfStreams() = 0;
310
311 /*
312 * returns opened filename
313 */
314 virtual std::string GetFileName() = 0;
315 /*
316 * return nr of audio streams, 0 if none
317 */
318 int GetNrOfAudioStreams();
319
320 /*
321 * return nr of video streams, 0 if none
322 */
323 int GetNrOfVideoStreams();
324
325 /*
326 * return nr of subtitle streams, 0 if none
327 */
328 int GetNrOfSubtitleStreams();
329
330 /*
331 * return nr of teletext streams, 0 if none
332 */
333 int GetNrOfTeletextStreams();
334
335 /*
336 * return the audio stream, or NULL if it does not exist
337 */
338 CDemuxStreamAudio* GetStreamFromAudioId(int iAudioIndex);
339
340 /*
341 * return the video stream, or NULL if it does not exist
342 */
343 CDemuxStreamVideo* GetStreamFromVideoId(int iVideoIndex);
344
345 /*
346 * return the subtitle stream, or NULL if it does not exist
347 */
348 CDemuxStreamSubtitle* GetStreamFromSubtitleId(int iSubtitleIndex);
349
350 /*
351 * return the teletext stream, or NULL if it does not exist
352 */
353 CDemuxStreamTeletext* GetStreamFromTeletextId(int iTeletextIndex);
354
355 /*
356 * return a user-presentable codec name of the given stream
357 */
358 virtual void GetStreamCodecName(int iStreamId, std::string &strName) {};
359};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp
new file mode 100644
index 0000000..9786983
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp
@@ -0,0 +1,193 @@
1/*
2 * Copyright (C) 2012-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDInputStreams/DVDInputStream.h"
22#include "DVDDemuxBXA.h"
23#include "DVDDemuxUtils.h"
24#include "utils/log.h"
25#include "utils/StringUtils.h"
26#include "../DVDClock.h"
27
28// AirTunes audio Demuxer.
29
30using namespace std;
31
32class CDemuxStreamAudioBXA
33 : public CDemuxStreamAudio
34{
35 CDVDDemuxBXA *m_parent;
36 string m_codec;
37public:
38 CDemuxStreamAudioBXA(CDVDDemuxBXA *parent, const string& codec)
39 : m_parent(parent)
40 , m_codec(codec)
41
42 {}
43 void GetStreamInfo(string& strInfo)
44 {
45 strInfo = StringUtils::Format("%s", m_codec.c_str());
46 }
47};
48
49CDVDDemuxBXA::CDVDDemuxBXA() : CDVDDemux()
50{
51 m_pInput = NULL;
52 m_stream = NULL;
53 m_bytes = 0;
54 memset(&m_header, 0x0, sizeof(Demux_BXA_FmtHeader));
55}
56
57CDVDDemuxBXA::~CDVDDemuxBXA()
58{
59 Dispose();
60}
61
62bool CDVDDemuxBXA::Open(CDVDInputStream* pInput)
63{
64 Abort();
65
66 Dispose();
67
68 if(!pInput || !pInput->IsStreamType(DVDSTREAM_TYPE_FILE))
69 return false;
70
71 if(pInput->Read((uint8_t *)&m_header, sizeof(Demux_BXA_FmtHeader)) < 1)
72 return false;
73
74 // file valid?
75 if (strncmp(m_header.fourcc, "BXA ", 4) != 0 || m_header.type != BXA_PACKET_TYPE_FMT_DEMUX)
76 {
77 pInput->Seek(0, SEEK_SET);
78 return false;
79 }
80
81 m_pInput = pInput;
82
83 m_stream = new CDemuxStreamAudioBXA(this, "BXA");
84
85 if(!m_stream)
86 return false;
87
88 m_stream->iSampleRate = m_header.sampleRate;
89 m_stream->iBitsPerSample = m_header.bitsPerSample;
90 m_stream->iBitRate = m_header.sampleRate * m_header.channels * m_header.bitsPerSample;
91 m_stream->iChannels = m_header.channels;
92 m_stream->type = STREAM_AUDIO;
93 m_stream->codec = AV_CODEC_ID_PCM_S16LE;
94
95 return true;
96}
97
98void CDVDDemuxBXA::Dispose()
99{
100 delete m_stream;
101 m_stream = NULL;
102
103 m_pInput = NULL;
104 m_bytes = 0;
105
106 memset(&m_header, 0x0, sizeof(Demux_BXA_FmtHeader));
107}
108
109void CDVDDemuxBXA::Reset()
110{
111 CDVDInputStream* pInputStream = m_pInput;
112 Dispose();
113 Open(pInputStream);
114}
115
116void CDVDDemuxBXA::Abort()
117{
118 if(m_pInput)
119 return m_pInput->Abort();
120}
121
122void CDVDDemuxBXA::Flush()
123{
124}
125
126#define BXA_READ_SIZE 4096
127DemuxPacket* CDVDDemuxBXA::Read()
128{
129 if(!m_pInput)
130 return NULL;
131
132 DemuxPacket* pPacket = CDVDDemuxUtils::AllocateDemuxPacket(BXA_READ_SIZE);
133
134 if (!pPacket)
135 {
136 if (m_pInput)
137 m_pInput->Close();
138 return NULL;
139 }
140
141 pPacket->iSize = m_pInput->Read(pPacket->pData, BXA_READ_SIZE);
142 pPacket->iStreamId = 0;
143
144 if(pPacket->iSize < 1)
145 {
146 delete pPacket;
147 pPacket = NULL;
148 }
149 else
150 {
151 int n = (m_header.channels * m_header.bitsPerSample * m_header.sampleRate)>>3;
152 if (n > 0)
153 {
154 m_bytes += pPacket->iSize;
155 pPacket->dts = (double)m_bytes * DVD_TIME_BASE / n;
156 pPacket->pts = pPacket->dts;
157 }
158 else
159 {
160 pPacket->dts = DVD_NOPTS_VALUE;
161 pPacket->pts = DVD_NOPTS_VALUE;
162 }
163 }
164
165 return pPacket;
166}
167
168CDemuxStream* CDVDDemuxBXA::GetStream(int iStreamId)
169{
170 if(iStreamId != 0)
171 return NULL;
172
173 return m_stream;
174}
175
176int CDVDDemuxBXA::GetNrOfStreams()
177{
178 return (m_stream == NULL ? 0 : 1);
179}
180
181std::string CDVDDemuxBXA::GetFileName()
182{
183 if(m_pInput)
184 return m_pInput->GetFileName();
185 else
186 return "";
187}
188
189void CDVDDemuxBXA::GetStreamCodecName(int iStreamId, std::string &strName)
190{
191 if (m_stream && iStreamId == 0)
192 strName = "BXA";
193}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h
new file mode 100644
index 0000000..bdb65b4
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h
@@ -0,0 +1,85 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DVDDemux.h"
23
24#ifdef TARGET_WINDOWS
25#define __attribute__(dummy_val)
26#else
27#include <config.h>
28#endif
29
30#ifdef TARGET_WINDOWS
31#pragma pack(push)
32#pragma pack(1)
33#endif
34
35typedef struct
36{
37 char fourcc[4];
38 uint32_t type;
39 uint32_t channels;
40 uint32_t sampleRate;
41 uint32_t bitsPerSample;
42 uint64_t durationMs;
43} __attribute__((__packed__)) Demux_BXA_FmtHeader;
44
45#ifdef TARGET_WINDOWS
46#pragma pack(pop)
47#endif
48
49#include <vector>
50
51#define BXA_PACKET_TYPE_FMT_DEMUX 1
52
53class CDemuxStreamAudioBXA;
54
55class CDVDDemuxBXA : public CDVDDemux
56{
57public:
58
59 CDVDDemuxBXA();
60 ~CDVDDemuxBXA();
61
62 bool Open(CDVDInputStream* pInput);
63 void Dispose();
64 void Reset();
65 void Abort();
66 void Flush();
67 DemuxPacket* Read();
68 bool SeekTime(int time, bool backwords = false, double* startpts = NULL) { return false; }
69 void SetSpeed(int iSpeed) {};
70 int GetStreamLength() { return (int)m_header.durationMs; }
71 CDemuxStream* GetStream(int iStreamId);
72 int GetNrOfStreams();
73 std::string GetFileName();
74 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
75
76protected:
77 friend class CDemuxStreamAudioBXA;
78 CDVDInputStream* m_pInput;
79 int64_t m_bytes;
80
81 CDemuxStreamAudioBXA *m_stream;
82
83 Demux_BXA_FmtHeader m_header;
84};
85
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp
new file mode 100644
index 0000000..24d56da
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp
@@ -0,0 +1,404 @@
1/*
2 * Copyright (C) 2005-2014 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDDemuxUtils.h"
22#include "DVDClock.h"
23#include "DVDDemuxCC.h"
24#include "cores/dvdplayer/DVDCodecs/Overlay/contrib/cc_decoder708.h"
25#include "utils/log.h"
26
27#include <algorithm>
28
29class CBitstream
30{
31public:
32 CBitstream(uint8_t *data, int bits)
33 {
34 m_data = data;
35 m_offset = 0;
36 m_len = bits;
37 m_error = false;
38 }
39 unsigned int readBits(int num)
40 {
41 int r = 0;
42 while (num > 0)
43 {
44 if (m_offset >= m_len)
45 {
46 m_error = true;
47 return 0;
48 }
49 num--;
50 if (m_data[m_offset / 8] & (1 << (7 - (m_offset & 7))))
51 r |= 1 << num;
52 m_offset++;
53 }
54 return r;
55 }
56 unsigned int readGolombUE(int maxbits = 32)
57 {
58 int lzb = -1;
59 int bits = 0;
60 for (int b = 0; !b; lzb++, bits++)
61 {
62 if (bits > maxbits)
63 return 0;
64 b = readBits(1);
65 }
66 return (1 << lzb) - 1 + readBits(lzb);
67 }
68
69private:
70 uint8_t *m_data;
71 int m_offset;
72 int m_len;
73 bool m_error;
74};
75
76class CCaptionBlock
77{
78public:
79 CCaptionBlock(int size)
80 {
81 m_data = (uint8_t*)malloc(size);
82 m_size = size;
83 }
84 virtual ~CCaptionBlock()
85 {
86 free(m_data);
87 }
88 double m_pts;
89 uint8_t *m_data;
90 int m_size;
91};
92
93bool reorder_sort (CCaptionBlock *lhs, CCaptionBlock *rhs)
94{
95 return (lhs->m_pts > rhs->m_pts);
96}
97
98CDVDDemuxCC::CDVDDemuxCC(AVCodecID codec)
99{
100 m_hasData = false;
101 m_curPts = 0;
102 m_ccDecoder = NULL;
103 m_codec = codec;
104}
105
106CDVDDemuxCC::~CDVDDemuxCC()
107{
108 Dispose();
109}
110
111CDemuxStream* CDVDDemuxCC::GetStream(int iStreamId)
112{
113 return &m_streams[iStreamId];
114}
115
116int CDVDDemuxCC::GetNrOfStreams()
117{
118 return m_streams.size();
119}
120
121DemuxPacket* CDVDDemuxCC::Read(DemuxPacket *pSrcPacket)
122{
123 DemuxPacket *pPacket = NULL;
124 uint32_t startcode = 0xffffffff;
125 int picType = 0;
126 int p = 0;
127 int len;
128
129 if (!pSrcPacket)
130 {
131 pPacket = Decode();
132 return pPacket;
133 }
134 if (pSrcPacket->pts == DVD_NOPTS_VALUE)
135 {
136 return pPacket;
137 }
138
139 while (!m_ccTempBuffer.empty())
140 {
141 m_ccReorderBuffer.push_back(m_ccTempBuffer.back());
142 m_ccTempBuffer.pop_back();
143 }
144
145 while ((len = pSrcPacket->iSize - p) > 3)
146 {
147 if ((startcode & 0xffffff00) == 0x00000100)
148 {
149 if (m_codec == AV_CODEC_ID_MPEG2VIDEO)
150 {
151 int scode = startcode & 0xFF;
152 if (scode == 0x00)
153 {
154 if (len > 4)
155 {
156 uint8_t *buf = pSrcPacket->pData + p;
157 picType = (buf[1] & 0x38) >> 3;
158 }
159 }
160 else if (scode == 0xb2) // user data
161 {
162 uint8_t *buf = pSrcPacket->pData + p;
163 if (len >= 6 &&
164 buf[0] == 'G' && buf[1] == 'A' && buf[2] == '9' && buf[3] == '4' &&
165 buf[4] == 3 && (buf[5] & 0x40))
166 {
167 int cc_count = buf[5] & 0x1f;
168 if (cc_count > 0 && len >= 7 + cc_count * 3)
169 {
170 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
171 memcpy(cc->m_data, buf + 7, cc_count * 3);
172 cc->m_pts = pSrcPacket->pts;
173 if (picType == 1 || picType == 2)
174 m_ccTempBuffer.push_back(cc);
175 else
176 m_ccReorderBuffer.push_back(cc);
177 }
178 }
179 else if (len >= 6 &&
180 buf[0] == 'C' && buf[1] == 'C' && buf[2] == 1)
181 {
182 int oddidx = (buf[4] & 0x80) ? 0 : 1;
183 int cc_count = (buf[4] & 0x3e) >> 1;
184 int extrafield = buf[4] & 0x01;
185 if (extrafield)
186 cc_count++;
187
188 if (cc_count > 0 && len >= 5 + cc_count * 3 * 2)
189 {
190 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
191 uint8_t *src = buf + 5;
192 uint8_t *dst = cc->m_data;
193
194 for (int i = 0; i < cc_count; i++)
195 {
196 for (int j = 0; j < 2; j++)
197 {
198 if (i == cc_count - 1 && extrafield && j == 1)
199 break;
200
201 if ((oddidx == j) && (src[0] == 0xFF))
202 {
203 dst[0] = 0x04;
204 dst[1] = src[1];
205 dst[2] = src[2];
206 dst += 3;
207 }
208 src += 3;
209 }
210 }
211 cc->m_pts = pSrcPacket->pts;
212 m_ccReorderBuffer.push_back(cc);
213 picType = 1;
214 }
215 }
216 }
217 }
218 else if (m_codec == AV_CODEC_ID_H264)
219 {
220 int scode = startcode & 0x9F;
221 // slice data comes after SEI
222 if (scode >= 1 && scode <= 5)
223 {
224 uint8_t *buf = pSrcPacket->pData + p;
225 CBitstream bs(buf, len * 8);
226 bs.readGolombUE();
227 int sliceType = bs.readGolombUE();
228 if (sliceType == 2 || sliceType == 7) // I slice
229 picType = 1;
230 else if (sliceType == 0 || sliceType == 5) // P slice
231 picType = 2;
232 if (picType == 0)
233 {
234 while (!m_ccTempBuffer.empty())
235 {
236 m_ccReorderBuffer.push_back(m_ccTempBuffer.back());
237 m_ccTempBuffer.pop_back();
238 }
239 }
240 }
241 if (scode == 0x06) // SEI
242 {
243 uint8_t *buf = pSrcPacket->pData + p;
244 if (len >= 12 &&
245 buf[3] == 0 && buf[4] == 49 &&
246 buf[5] == 'G' && buf[6] == 'A' && buf[7] == '9' && buf[8] == '4' && buf[9] == 3)
247 {
248 uint8_t *userdata = buf + 10;
249 int cc_count = userdata[0] & 0x1f;
250 if (len >= cc_count * 3 + 10)
251 {
252 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
253 memcpy(cc->m_data, userdata + 2, cc_count * 3);
254 cc->m_pts = pSrcPacket->pts;
255 m_ccTempBuffer.push_back(cc);
256 }
257 }
258 }
259 }
260 }
261 startcode = startcode << 8 | pSrcPacket->pData[p++];
262 }
263
264 if ((picType == 1 || picType == 2) && !m_ccReorderBuffer.empty())
265 {
266 if (!m_ccDecoder)
267 {
268 if (!OpenDecoder())
269 return NULL;
270 }
271 std::sort(m_ccReorderBuffer.begin(), m_ccReorderBuffer.end(), reorder_sort);
272 pPacket = Decode();
273 }
274 return pPacket;
275}
276
277void CDVDDemuxCC::Handler(int service, void *userdata)
278{
279 CDVDDemuxCC *ctx = (CDVDDemuxCC*)userdata;
280
281 unsigned int idx;
282
283 // switch back from 608 fallback if we got 708
284 if (ctx->m_ccDecoder->m_seen608 && ctx->m_ccDecoder->m_seen708)
285 {
286 for (idx = 0; idx < ctx->m_streamdata.size(); idx++)
287 {
288 if (ctx->m_streamdata[idx].service == 0)
289 break;
290 }
291 if (idx < ctx->m_streamdata.size())
292 {
293 ctx->m_streamdata.erase(ctx->m_streamdata.begin() + idx);
294 ctx->m_ccDecoder->m_seen608 = false;
295 }
296 if (service == 0)
297 return;
298 }
299
300 for (idx = 0; idx < ctx->m_streamdata.size(); idx++)
301 {
302 if (ctx->m_streamdata[idx].service == service)
303 break;
304 }
305 if (idx >= ctx->m_streamdata.size())
306 {
307 CDemuxStreamSubtitle stream;
308 strcpy(stream.language, "cc");
309 stream.codec = AV_CODEC_ID_TEXT;
310 stream.iPhysicalId = service;
311 stream.iId = idx;
312 ctx->m_streams.push_back(stream);
313
314 streamdata data;
315 data.streamIdx = idx;
316 data.service = service;
317 ctx->m_streamdata.push_back(data);
318
319 if (service == 0)
320 ctx->m_ccDecoder->m_seen608 = true;
321 else
322 ctx->m_ccDecoder->m_seen708 = true;
323 }
324
325 ctx->m_streamdata[idx].pts = ctx->m_curPts;
326 ctx->m_streamdata[idx].hasData = true;
327 ctx->m_hasData = true;
328}
329
330bool CDVDDemuxCC::OpenDecoder()
331{
332 m_ccDecoder = new CDecoderCC708();
333 m_ccDecoder->Init(Handler, this);
334 return true;
335}
336
337void CDVDDemuxCC::Dispose()
338{
339 m_streams.clear();
340 m_streamdata.clear();
341 delete m_ccDecoder;
342 m_ccDecoder = NULL;
343
344 while (!m_ccReorderBuffer.empty())
345 {
346 delete m_ccReorderBuffer.back();
347 m_ccReorderBuffer.pop_back();
348 }
349 while (!m_ccTempBuffer.empty())
350 {
351 delete m_ccTempBuffer.back();
352 m_ccTempBuffer.pop_back();
353 }
354}
355
356DemuxPacket* CDVDDemuxCC::Decode()
357{
358 DemuxPacket *pPacket = NULL;
359
360 while(!m_hasData && !m_ccReorderBuffer.empty())
361 {
362 CCaptionBlock *cc = m_ccReorderBuffer.back();
363 m_ccReorderBuffer.pop_back();
364 m_curPts = cc->m_pts;
365 m_ccDecoder->Decode(cc->m_data, cc->m_size);
366 delete cc;
367 }
368
369 if (m_hasData)
370 {
371 for (unsigned int i=0; i<m_streamdata.size(); i++)
372 {
373 if (m_streamdata[i].hasData)
374 {
375 int service = m_streamdata[i].service;
376
377 char *data;
378 int len;
379 if (service == 0)
380 {
381 data = m_ccDecoder->m_cc608decoder->text;
382 len = m_ccDecoder->m_cc608decoder->textlen;
383 }
384 else
385 {
386 data = m_ccDecoder->m_cc708decoders[service].text;
387 len = m_ccDecoder->m_cc708decoders[service].textlen;
388 }
389
390 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(len);
391 pPacket->iSize = len;
392 memcpy(pPacket->pData, data, pPacket->iSize);
393
394 pPacket->iStreamId = i;
395 pPacket->pts = m_streamdata[i].pts;
396 pPacket->duration = 0;
397 m_streamdata[i].hasData = false;
398 break;
399 }
400 m_hasData = false;
401 }
402 }
403 return pPacket;
404}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h
new file mode 100644
index 0000000..ae78298
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2005-2014 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#pragma once
22#include "DVDDemux.h"
23#include <vector>
24
25class CCaptionBlock;
26class CDecoderCC708;
27
28class CDVDDemuxCC : public CDVDDemux
29{
30public:
31 CDVDDemuxCC(AVCodecID codec);
32 virtual ~CDVDDemuxCC();
33
34 virtual void Reset() {};
35 virtual void Abort() {};
36 virtual void Flush() {};
37 virtual DemuxPacket* Read() { return NULL; };
38 virtual bool SeekTime(int time, bool backwords = false, double* startpts = NULL) {return true;};
39 virtual void SetSpeed(int iSpeed) {};
40 virtual int GetStreamLength() {return 0;};
41 virtual CDemuxStream* GetStream(int iStreamId);
42 virtual int GetNrOfStreams();
43 virtual std::string GetFileName() {return "";};
44
45 DemuxPacket* Read(DemuxPacket *packet);
46 static void Handler(int service, void *userdata);
47
48protected:
49 bool OpenDecoder();
50 void Dispose();
51 DemuxPacket* Decode();
52
53 struct streamdata
54 {
55 int streamIdx;
56 int service;
57 bool hasData ;
58 double pts;
59 };
60 std::vector<streamdata> m_streamdata;
61 std::vector<CDemuxStreamSubtitle> m_streams;
62 bool m_hasData;
63 double m_curPts;
64 std::vector<CCaptionBlock*> m_ccReorderBuffer;
65 std::vector<CCaptionBlock*> m_ccTempBuffer;
66 CDecoderCC708 *m_ccDecoder;
67 AVCodecID m_codec;
68};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp
new file mode 100644
index 0000000..72067da
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDInputStreams/DVDInputStream.h"
22#include "DVDDemuxCDDA.h"
23#include "DVDDemuxUtils.h"
24#include "utils/log.h"
25#include "../DVDClock.h"
26
27// CDDA audio demuxer based on AirTunes audio Demuxer.
28
29using namespace std;
30
31class CDemuxStreamAudioCDDA
32 : public CDemuxStreamAudio
33{
34public:
35 void GetStreamInfo(string& strInfo)
36 {
37 strInfo = "pcm";
38 }
39};
40
41CDVDDemuxCDDA::CDVDDemuxCDDA() : CDVDDemux()
42{
43 m_pInput = NULL;
44 m_stream = NULL;
45 m_bytes = 0;
46}
47
48CDVDDemuxCDDA::~CDVDDemuxCDDA()
49{
50 Dispose();
51}
52
53bool CDVDDemuxCDDA::Open(CDVDInputStream* pInput)
54{
55 Abort();
56
57 Dispose();
58
59 if(!pInput || !pInput->IsStreamType(DVDSTREAM_TYPE_FILE))
60 return false;
61
62 m_pInput = pInput;
63
64 m_stream = new CDemuxStreamAudioCDDA();
65
66 if(!m_stream)
67 return false;
68
69 m_stream->iSampleRate = 44100;
70 m_stream->iBitsPerSample = 16;
71 m_stream->iBitRate = 44100 * 2 * 16;
72 m_stream->iChannels = 2;
73 m_stream->type = STREAM_AUDIO;
74 m_stream->codec = AV_CODEC_ID_PCM_S16LE;
75
76 return true;
77}
78
79void CDVDDemuxCDDA::Dispose()
80{
81 delete m_stream;
82 m_stream = NULL;
83
84 m_pInput = NULL;
85 m_bytes = 0;
86}
87
88void CDVDDemuxCDDA::Reset()
89{
90 CDVDInputStream* pInputStream = m_pInput;
91 Dispose();
92 Open(pInputStream);
93}
94
95void CDVDDemuxCDDA::Abort()
96{
97 if(m_pInput)
98 return m_pInput->Abort();
99}
100
101void CDVDDemuxCDDA::Flush()
102{
103}
104
105#define CDDA_READ_SIZE 4096
106DemuxPacket* CDVDDemuxCDDA::Read()
107{
108 if(!m_pInput)
109 return NULL;
110
111 DemuxPacket* pPacket = CDVDDemuxUtils::AllocateDemuxPacket(CDDA_READ_SIZE);
112
113 if (!pPacket)
114 {
115 if (m_pInput)
116 m_pInput->Close();
117 return NULL;
118 }
119
120 pPacket->iSize = m_pInput->Read(pPacket->pData, CDDA_READ_SIZE);
121 pPacket->iStreamId = 0;
122
123 if(pPacket->iSize < 1)
124 {
125 delete pPacket;
126 pPacket = NULL;
127 }
128 else
129 {
130 int n = m_stream->iBitRate>>3;
131 if (n > 0)
132 {
133 m_bytes += pPacket->iSize;
134 pPacket->dts = (double)m_bytes * DVD_TIME_BASE / n;
135 pPacket->pts = pPacket->dts;
136 }
137 else
138 {
139 pPacket->dts = DVD_NOPTS_VALUE;
140 pPacket->pts = DVD_NOPTS_VALUE;
141 }
142 }
143
144 return pPacket;
145}
146
147bool CDVDDemuxCDDA::SeekTime(int time, bool backwords, double* startpts)
148{
149 int bytes_per_second = m_stream->iBitRate>>3;
150 // clamp seeks to bytes per full sample
151 int clamp_bytes = (m_stream->iBitsPerSample>>3) * m_stream->iChannels;
152
153 // time is in milliseconds
154 int64_t seekPos = m_pInput->Seek((((int64_t)time * bytes_per_second / 1000) / clamp_bytes ) * clamp_bytes, SEEK_SET) > 0;
155 if (seekPos > 0)
156 m_bytes = seekPos;
157
158 if (startpts)
159 *startpts = (double)m_bytes * DVD_TIME_BASE / bytes_per_second;
160
161 return seekPos > 0;
162};
163
164int CDVDDemuxCDDA::GetStreamLength()
165{
166 int64_t num_track_bytes = m_pInput->GetLength();
167 int bytes_per_second = (m_stream->iBitRate>>3);
168 int64_t track_mseconds = num_track_bytes*1000 / bytes_per_second;
169 return (int)track_mseconds;
170}
171
172CDemuxStream* CDVDDemuxCDDA::GetStream(int iStreamId)
173{
174 if(iStreamId != 0)
175 return NULL;
176
177 return m_stream;
178}
179
180int CDVDDemuxCDDA::GetNrOfStreams()
181{
182 return (m_stream == NULL ? 0 : 1);
183}
184
185std::string CDVDDemuxCDDA::GetFileName()
186{
187 if(m_pInput)
188 return m_pInput->GetFileName();
189 else
190 return "";
191}
192
193void CDVDDemuxCDDA::GetStreamCodecName(int iStreamId, std::string &strName)
194{
195 if (m_stream && iStreamId == 0)
196 strName = "pcm";
197}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h
new file mode 100644
index 0000000..6a3c50a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h
@@ -0,0 +1,60 @@
1#pragma once
2/*
3 * Copyright (C) 2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DVDDemux.h"
23#include "utils/log.h"
24
25#ifdef TARGET_WINDOWS
26#define __attribute__(dummy_val)
27#else
28#include <config.h>
29#endif
30
31class CDemuxStreamAudioCDDA;
32
33class CDVDDemuxCDDA : public CDVDDemux
34{
35public:
36
37 CDVDDemuxCDDA();
38 ~CDVDDemuxCDDA();
39
40 bool Open(CDVDInputStream* pInput);
41 void Dispose();
42 void Reset();
43 void Abort();
44 void Flush();
45 DemuxPacket* Read();
46 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
47 void SetSpeed(int iSpeed) {};
48 int GetStreamLength() ;
49 CDemuxStream* GetStream(int iStreamId);
50 int GetNrOfStreams();
51 std::string GetFileName();
52 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
53
54protected:
55 friend class CDemuxStreamAudioCDDA;
56 CDVDInputStream* m_pInput;
57 int64_t m_bytes;
58
59 CDemuxStreamAudioCDDA *m_stream;
60};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
new file mode 100644
index 0000000..f58472f
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -0,0 +1,1767 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "system.h"
22#ifndef __STDC_CONSTANT_MACROS
23#define __STDC_CONSTANT_MACROS
24#endif
25#ifndef __STDC_LIMIT_MACROS
26#define __STDC_LIMIT_MACROS
27#endif
28#ifdef TARGET_POSIX
29#include "stdint.h"
30#endif
31#include "DVDDemuxFFmpeg.h"
32#include "DVDInputStreams/DVDInputStream.h"
33#include "DVDInputStreams/DVDInputStreamNavigator.h"
34#ifdef HAVE_LIBBLURAY
35#include "DVDInputStreams/DVDInputStreamBluray.h"
36#endif
37#include "DVDInputStreams/DVDInputStreamPVRManager.h"
38#include "DVDInputStreams/DVDInputStreamFFmpeg.h"
39#include "DVDDemuxUtils.h"
40#include "DVDClock.h" // for DVD_TIME_BASE
41#include "commons/Exception.h"
42#include "settings/AdvancedSettings.h"
43#include "settings/Settings.h"
44#include "filesystem/File.h"
45#include "filesystem/CurlFile.h"
46#include "filesystem/Directory.h"
47#include "utils/log.h"
48#include "threads/Thread.h"
49#include "threads/SystemClock.h"
50#include "utils/TimeUtils.h"
51#include "utils/StringUtils.h"
52#include "URL.h"
53#include "cores/FFmpeg.h"
54
55extern "C" {
56#include "libavutil/opt.h"
57}
58
59struct StereoModeConversionMap
60{
61 const char* name;
62 const char* mode;
63};
64
65// we internally use the matroska string representation of stereoscopic modes.
66// This struct is a conversion map to convert stereoscopic mode values
67// from asf/wmv to the internally used matroska ones
68static const struct StereoModeConversionMap WmvToInternalStereoModeMap[] =
69{
70 { "SideBySideRF", "right_left" },
71 { "SideBySideLF", "left_right" },
72 { "OverUnderRT", "bottom_top" },
73 { "OverUnderLT", "top_bottom" },
74 {}
75};
76
77#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
78
79void CDemuxStreamAudioFFmpeg::GetStreamInfo(std::string& strInfo)
80{
81 if(!m_stream) return;
82 char temp[128];
83 avcodec_string(temp, 128, m_stream->codec, 0);
84 strInfo = temp;
85}
86
87void CDemuxStreamAudioFFmpeg::GetStreamName(std::string& strInfo)
88{
89 if(!m_stream) return;
90 if(!m_description.empty())
91 strInfo = m_description;
92 else
93 CDemuxStream::GetStreamName(strInfo);
94}
95
96void CDemuxStreamSubtitleFFmpeg::GetStreamName(std::string& strInfo)
97{
98 if(!m_stream) return;
99 if(!m_description.empty())
100 strInfo = m_description;
101 else
102 CDemuxStream::GetStreamName(strInfo);
103}
104
105void CDemuxStreamVideoFFmpeg::GetStreamInfo(std::string& strInfo)
106{
107 if(!m_stream) return;
108 char temp[128];
109 avcodec_string(temp, 128, m_stream->codec, 0);
110 strInfo = temp;
111}
112
113void CDemuxStreamSubtitleFFmpeg::GetStreamInfo(std::string& strInfo)
114{
115 if(!m_stream) return;
116 char temp[128];
117 avcodec_string(temp, 128, m_stream->codec, 0);
118 strInfo = temp;
119}
120
121static int interrupt_cb(void* ctx)
122{
123 CDVDDemuxFFmpeg* demuxer = static_cast<CDVDDemuxFFmpeg*>(ctx);
124 if(demuxer && demuxer->Aborted())
125 return 1;
126 return 0;
127}
128
129
130////////////////////////////////////////////////////////////////////////////////////////////////
131////////////////////////////////////////////////////////////////////////////////////////////////
132/*
133static int dvd_file_open(URLContext *h, const char *filename, int flags)
134{
135 return -1;
136}
137*/
138
139static int dvd_file_read(void *h, uint8_t* buf, int size)
140{
141 if(interrupt_cb(h))
142 return AVERROR_EXIT;
143
144 CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
145 return pInputStream->Read(buf, size);
146}
147/*
148static int dvd_file_write(URLContext *h, uint8_t* buf, int size)
149{
150 return -1;
151}
152*/
153static int64_t dvd_file_seek(void *h, int64_t pos, int whence)
154{
155 if(interrupt_cb(h))
156 return AVERROR_EXIT;
157
158 CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
159 if(whence == AVSEEK_SIZE)
160 return pInputStream->GetLength();
161 else
162 return pInputStream->Seek(pos, whence & ~AVSEEK_FORCE);
163}
164
165////////////////////////////////////////////////////////////////////////////////////////////////
166////////////////////////////////////////////////////////////////////////////////////////////////
167
168CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux()
169{
170 m_pFormatContext = NULL;
171 m_pInput = NULL;
172 m_ioContext = NULL;
173 m_currentPts = DVD_NOPTS_VALUE;
174 m_bMatroska = false;
175 m_bAVI = false;
176 m_speed = DVD_PLAYSPEED_NORMAL;
177 m_program = UINT_MAX;
178 m_pkt.result = -1;
179 memset(&m_pkt.pkt, 0, sizeof(AVPacket));
180 m_streaminfo = true; /* set to true if we want to look for streams before playback */
181 m_checkvideo = false;
182}
183
184CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg()
185{
186 Dispose();
187 ff_flush_avutil_log_buffers();
188}
189
190bool CDVDDemuxFFmpeg::Aborted()
191{
192 if(m_timeout.IsTimePast())
193 return true;
194
195 CDVDInputStreamFFmpeg * input = dynamic_cast<CDVDInputStreamFFmpeg*>(m_pInput);
196 if(input && input->Aborted())
197 return true;
198
199 return false;
200}
201
202bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo, bool fileinfo)
203{
204 AVInputFormat* iformat = NULL;
205 std::string strFile;
206 m_streaminfo = streaminfo;
207 m_currentPts = DVD_NOPTS_VALUE;
208 m_speed = DVD_PLAYSPEED_NORMAL;
209 m_program = UINT_MAX;
210 const AVIOInterruptCB int_cb = { interrupt_cb, this };
211
212 if (!pInput) return false;
213
214 m_pInput = pInput;
215 strFile = m_pInput->GetFileName();
216
217 if( m_pInput->GetContent().length() > 0 )
218 {
219 std::string content = m_pInput->GetContent();
220 StringUtils::ToLower(content);
221
222 /* check if we can get a hint from content */
223 if ( content.compare("video/x-vobsub") == 0 )
224 iformat = av_find_input_format("mpeg");
225 else if( content.compare("video/x-dvd-mpeg") == 0 )
226 iformat = av_find_input_format("mpeg");
227 else if( content.compare("video/mp2t") == 0 )
228 iformat = av_find_input_format("mpegts");
229 else if( content.compare("multipart/x-mixed-replace") == 0 )
230 iformat = av_find_input_format("mjpeg");
231 }
232
233 // open the demuxer
234 m_pFormatContext = avformat_alloc_context();
235 m_pFormatContext->interrupt_callback = int_cb;
236
237 // try to abort after 30 seconds
238 m_timeout.Set(30000);
239
240 if( m_pInput->IsStreamType(DVDSTREAM_TYPE_FFMPEG) )
241 {
242 // special stream type that makes avformat handle file opening
243 // allows internal ffmpeg protocols to be used
244 CURL url = m_pInput->GetURL();
245
246 AVDictionary *options = GetFFMpegOptionsFromURL(url);
247
248 int result=-1;
249 if (url.IsProtocol("mms"))
250 {
251 // try mmsh, then mmst
252 url.SetProtocol("mmsh");
253 url.SetProtocolOptions("");
254 result = avformat_open_input(&m_pFormatContext, url.Get().c_str(), iformat, &options);
255 if (result < 0)
256 {
257 url.SetProtocol("mmst");
258 strFile = url.Get();
259 }
260 }
261 if (result < 0 && avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0 )
262 {
263 CLog::Log(LOGDEBUG, "Error, could not open file %s", CURL::GetRedacted(strFile).c_str());
264 Dispose();
265 av_dict_free(&options);
266 return false;
267 }
268 av_dict_free(&options);
269 }
270 else
271 {
272 unsigned char* buffer = (unsigned char*)av_malloc(FFMPEG_FILE_BUFFER_SIZE);
273 m_ioContext = avio_alloc_context(buffer, FFMPEG_FILE_BUFFER_SIZE, 0, this, dvd_file_read, NULL, dvd_file_seek);
274 m_ioContext->max_packet_size = m_pInput->GetBlockSize();
275 if(m_ioContext->max_packet_size)
276 m_ioContext->max_packet_size *= FFMPEG_FILE_BUFFER_SIZE / m_ioContext->max_packet_size;
277
278 if(m_pInput->Seek(0, SEEK_POSSIBLE) == 0)
279 m_ioContext->seekable = 0;
280
281 std::string content = m_pInput->GetContent();
282 StringUtils::ToLower(content);
283 if (StringUtils::StartsWith(content, "audio/l16"))
284 iformat = av_find_input_format("s16be");
285
286 if( iformat == NULL )
287 {
288 // let ffmpeg decide which demuxer we have to open
289
290 bool trySPDIFonly = (m_pInput->GetContent() == "audio/x-spdif-compressed");
291
292 if (!trySPDIFonly)
293 av_probe_input_buffer(m_ioContext, &iformat, strFile.c_str(), NULL, 0, 0);
294
295 // Use the more low-level code in case we have been built against an old
296 // FFmpeg without the above av_probe_input_buffer(), or in case we only
297 // want to probe for spdif (DTS or IEC 61937) compressed audio
298 // specifically, or in case the file is a wav which may contain DTS or
299 // IEC 61937 (e.g. ac3-in-wav) and we want to check for those formats.
300 if (trySPDIFonly || (iformat && strcmp(iformat->name, "wav") == 0))
301 {
302 AVProbeData pd;
303 uint8_t probe_buffer[FFMPEG_FILE_BUFFER_SIZE + AVPROBE_PADDING_SIZE];
304
305 // init probe data
306 pd.buf = probe_buffer;
307 pd.filename = strFile.c_str();
308
309 // av_probe_input_buffer might have changed the buffer_size beyond our allocated amount
310 int buffer_size = std::min((int) FFMPEG_FILE_BUFFER_SIZE, m_ioContext->buffer_size);
311 // read data using avformat's buffers
312 pd.buf_size = avio_read(m_ioContext, pd.buf, m_ioContext->max_packet_size ? m_ioContext->max_packet_size : buffer_size);
313 if (pd.buf_size <= 0)
314 {
315 CLog::Log(LOGERROR, "%s - error reading from input stream, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
316 return false;
317 }
318 memset(pd.buf+pd.buf_size, 0, AVPROBE_PADDING_SIZE);
319
320 // restore position again
321 avio_seek(m_ioContext , 0, SEEK_SET);
322
323 // the advancedsetting is for allowing the user to force outputting the
324 // 44.1 kHz DTS wav file as PCM, so that an A/V receiver can decode
325 // it (this is temporary until we handle 44.1 kHz passthrough properly)
326 if (trySPDIFonly || (iformat && strcmp(iformat->name, "wav") == 0 && !g_advancedSettings.m_dvdplayerIgnoreDTSinWAV))
327 {
328 // check for spdif and dts
329 // This is used with wav files and audio CDs that may contain
330 // a DTS or AC3 track padded for S/PDIF playback. If neither of those
331 // is present, we assume it is PCM audio.
332 // AC3 is always wrapped in iec61937 (ffmpeg "spdif"), while DTS
333 // may be just padded.
334 AVInputFormat *iformat2;
335 iformat2 = av_find_input_format("spdif");
336
337 if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4)
338 {
339 iformat = iformat2;
340 }
341 else
342 {
343 // not spdif or no spdif demuxer, try dts
344 iformat2 = av_find_input_format("dts");
345
346 if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4)
347 {
348 iformat = iformat2;
349 }
350 else if (trySPDIFonly)
351 {
352 // not dts either, return false in case we were explicitely
353 // requested to only check for S/PDIF padded compressed audio
354 CLog::Log(LOGDEBUG, "%s - not spdif or dts file, fallbacking", __FUNCTION__);
355 return false;
356 }
357 }
358 }
359 }
360
361 if(!iformat)
362 {
363 std::string content = m_pInput->GetContent();
364
365 /* check if we can get a hint from content */
366 if( content.compare("audio/aacp") == 0 )
367 iformat = av_find_input_format("aac");
368 else if( content.compare("audio/aac") == 0 )
369 iformat = av_find_input_format("aac");
370 else if( content.compare("video/flv") == 0 )
371 iformat = av_find_input_format("flv");
372 else if( content.compare("video/x-flv") == 0 )
373 iformat = av_find_input_format("flv");
374 }
375
376 if (!iformat)
377 {
378 CLog::Log(LOGERROR, "%s - error probing input format, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
379 return false;
380 }
381 else
382 {
383 if (iformat->name)
384 CLog::Log(LOGDEBUG, "%s - probing detected format [%s]", __FUNCTION__, iformat->name);
385 else
386 CLog::Log(LOGDEBUG, "%s - probing detected unnamed format", __FUNCTION__);
387 }
388 }
389
390
391 m_pFormatContext->pb = m_ioContext;
392
393 AVDictionary *options = NULL;
394 if (iformat->name && (strcmp(iformat->name, "mp3") == 0 || strcmp(iformat->name, "mp2") == 0))
395 {
396 CLog::Log(LOGDEBUG, "%s - setting usetoc to 0 for accurate VBR MP3 seek", __FUNCTION__);
397 av_dict_set(&options, "usetoc", "0", 0);
398 }
399
400 if (StringUtils::StartsWith(content, "audio/l16"))
401 {
402 int channels = 2;
403 int samplerate = 44100;
404 GetL16Parameters(channels, samplerate);
405 av_dict_set_int(&options, "channels", channels, 0);
406 av_dict_set_int(&options, "sample_rate", samplerate, 0);
407 }
408
409 if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0)
410 {
411 CLog::Log(LOGERROR, "%s - Error, could not open file %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
412 Dispose();
413 av_dict_free(&options);
414 return false;
415 }
416 av_dict_free(&options);
417 }
418
419 // Avoid detecting framerate if advancedsettings.xml says so
420 if (g_advancedSettings.m_videoFpsDetect == 0)
421 m_pFormatContext->fps_probe_size = 0;
422
423 // analyse very short to speed up mjpeg playback start
424 if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0)
425 av_opt_set_int(m_pFormatContext, "analyzeduration", 500000, 0);
426
427 bool skipCreateStreams = false;
428 bool isBluray = pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY);
429 if (iformat && (strcmp(iformat->name, "mpegts") == 0) && !fileinfo && !isBluray)
430 {
431 av_opt_set_int(m_pFormatContext, "analyzeduration", 500000, 0);
432 m_checkvideo = true;
433 skipCreateStreams = true;
434 }
435 else if (!iformat || (strcmp(iformat->name, "mpegts") != 0))
436 {
437 m_streaminfo = true;
438 }
439
440 // we need to know if this is matroska or avi later
441 m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm"
442 m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0;
443
444 if (m_streaminfo)
445 {
446 /* to speed up dvd switches, only analyse very short */
447 if(m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
448 av_opt_set_int(m_pFormatContext, "analyzeduration", 500000, 0);
449
450 CLog::Log(LOGDEBUG, "%s - avformat_find_stream_info starting", __FUNCTION__);
451 int iErr = avformat_find_stream_info(m_pFormatContext, NULL);
452 if (iErr < 0)
453 {
454 CLog::Log(LOGWARNING,"could not find codec parameters for %s", CURL::GetRedacted(strFile).c_str());
455 if (m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)
456 || m_pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY)
457 || (m_pFormatContext->nb_streams == 1 && m_pFormatContext->streams[0]->codec->codec_id == AV_CODEC_ID_AC3))
458 {
459 // special case, our codecs can still handle it.
460 }
461 else
462 {
463 Dispose();
464 return false;
465 }
466 }
467 CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__);
468
469 if (m_checkvideo)
470 {
471 // make sure we start video with an i-frame
472 ResetVideoStreams();
473 }
474 }
475 else
476 {
477 m_program = 0;
478 m_checkvideo = true;
479 skipCreateStreams = true;
480 }
481
482 // reset any timeout
483 m_timeout.SetInfinite();
484
485 // if format can be nonblocking, let's use that
486 m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK;
487
488 // print some extra information
489 av_dump_format(m_pFormatContext, 0, strFile.c_str(), 0);
490
491 UpdateCurrentPTS();
492
493 // in case of mpegts and we have not seen pat/pmt, defer creation of streams
494 if (!skipCreateStreams || m_pFormatContext->nb_programs > 0)
495 CreateStreams();
496
497 // allow IsProgramChange to return true
498 if (skipCreateStreams && GetNrOfStreams() == 0)
499 m_program = 0;
500
501 return true;
502}
503
504void CDVDDemuxFFmpeg::Dispose()
505{
506 m_pkt.result = -1;
507 av_free_packet(&m_pkt.pkt);
508
509 if (m_pFormatContext)
510 {
511 if (m_ioContext && m_pFormatContext->pb && m_pFormatContext->pb != m_ioContext)
512 {
513 CLog::Log(LOGWARNING, "CDVDDemuxFFmpeg::Dispose - demuxer changed our byte context behind our back, possible memleak");
514 m_ioContext = m_pFormatContext->pb;
515 }
516 avformat_close_input(&m_pFormatContext);
517 }
518
519 if(m_ioContext)
520 {
521 av_free(m_ioContext->buffer);
522 av_free(m_ioContext);
523 }
524
525 m_ioContext = NULL;
526 m_pFormatContext = NULL;
527 m_speed = DVD_PLAYSPEED_NORMAL;
528
529 DisposeStreams();
530
531 m_pInput = NULL;
532}
533
534void CDVDDemuxFFmpeg::Reset()
535{
536 CDVDInputStream* pInputStream = m_pInput;
537 Dispose();
538 Open(pInputStream, m_streaminfo);
539}
540
541void CDVDDemuxFFmpeg::Flush()
542{
543 // naughty usage of an internal ffmpeg function
544 if (m_pFormatContext)
545 av_read_frame_flush(m_pFormatContext);
546
547 m_currentPts = DVD_NOPTS_VALUE;
548
549 m_pkt.result = -1;
550 av_free_packet(&m_pkt.pkt);
551}
552
553void CDVDDemuxFFmpeg::Abort()
554{
555 m_timeout.SetExpired();
556}
557
558void CDVDDemuxFFmpeg::SetSpeed(int iSpeed)
559{
560 if(!m_pFormatContext)
561 return;
562
563 if(m_speed != DVD_PLAYSPEED_PAUSE && iSpeed == DVD_PLAYSPEED_PAUSE)
564 {
565 m_pInput->Pause(m_currentPts);
566 av_read_pause(m_pFormatContext);
567 }
568 else if(m_speed == DVD_PLAYSPEED_PAUSE && iSpeed != DVD_PLAYSPEED_PAUSE)
569 {
570 m_pInput->Pause(m_currentPts);
571 av_read_play(m_pFormatContext);
572 }
573 m_speed = iSpeed;
574
575 AVDiscard discard = AVDISCARD_NONE;
576 if(m_speed > 4*DVD_PLAYSPEED_NORMAL)
577 discard = AVDISCARD_NONKEY;
578 else if(m_speed > 2*DVD_PLAYSPEED_NORMAL)
579 discard = AVDISCARD_BIDIR;
580 else if(m_speed < DVD_PLAYSPEED_PAUSE)
581 discard = AVDISCARD_NONKEY;
582
583
584 for(unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
585 {
586 if(m_pFormatContext->streams[i])
587 {
588 if(m_pFormatContext->streams[i]->discard != AVDISCARD_ALL)
589 m_pFormatContext->streams[i]->discard = discard;
590 }
591 }
592}
593
594AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromURL(const CURL &url)
595{
596
597 AVDictionary *options = NULL;
598
599 if (url.IsProtocol("http") || url.IsProtocol("https"))
600 {
601 std::map<std::string, std::string> protocolOptions;
602 url.GetProtocolOptions(protocolOptions);
603 std::string headers;
604 bool hasUserAgent = false;
605 for(std::map<std::string, std::string>::const_iterator it = protocolOptions.begin(); it != protocolOptions.end(); ++it)
606 {
607 std::string name = it->first; StringUtils::ToLower(name);
608 const std::string &value = it->second;
609
610 if (name == "seekable")
611 av_dict_set(&options, "seekable", value.c_str(), 0);
612 else if (name == "user-agent")
613 {
614 av_dict_set(&options, "user-agent", value.c_str(), 0);
615 hasUserAgent = true;
616 }
617 else if (name != "auth" && name != "encoding")
618 // all other protocol options can be added as http header.
619 headers.append(it->first).append(": ").append(value).append("\r\n");
620 }
621 if (!hasUserAgent)
622 // set default xbmc user-agent.
623 av_dict_set(&options, "user-agent", g_advancedSettings.m_userAgent.c_str(), 0);
624
625 if (!headers.empty())
626 av_dict_set(&options, "headers", headers.c_str(), 0);
627
628 std::string cookies;
629 if (XFILE::CCurlFile::GetCookies(url, cookies))
630 av_dict_set(&options, "cookies", cookies.c_str(), 0);
631
632 }
633 return options;
634}
635
636double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num)
637{
638 if (pts == (int64_t)AV_NOPTS_VALUE)
639 return DVD_NOPTS_VALUE;
640
641 // do calculations in floats as they can easily overflow otherwise
642 // we don't care for having a completly exact timestamp anyway
643 double timestamp = (double)pts * num / den;
644 double starttime = 0.0f;
645
646 // for dvd's we need the original time
647 if(CDVDInputStream::IMenus* menu = dynamic_cast<CDVDInputStream::IMenus*>(m_pInput))
648 starttime = menu->GetTimeStampCorrection() / DVD_TIME_BASE;
649 else if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE)
650 starttime = (double)m_pFormatContext->start_time / AV_TIME_BASE;
651
652 if(timestamp > starttime)
653 timestamp -= starttime;
654 // allow for largest possible difference in pts and dts for a single packet
655 else if( timestamp + 0.5f > starttime )
656 timestamp = 0;
657
658 return timestamp*DVD_TIME_BASE;
659}
660
661DemuxPacket* CDVDDemuxFFmpeg::Read()
662{
663 DemuxPacket* pPacket = NULL;
664 // on some cases where the received packet is invalid we will need to return an empty packet (0 length) otherwise the main loop (in CDVDPlayer)
665 // would consider this the end of stream and stop.
666 bool bReturnEmpty = false;
667 { CSingleLock lock(m_critSection); // open lock scope
668 if (m_pFormatContext)
669 {
670 // assume we are not eof
671 if(m_pFormatContext->pb)
672 m_pFormatContext->pb->eof_reached = 0;
673
674 // check for saved packet after a program change
675 if (m_pkt.result < 0)
676 {
677 // keep track if ffmpeg doesn't always set these
678 m_pkt.pkt.size = 0;
679 m_pkt.pkt.data = NULL;
680
681 // timeout reads after 100ms
682 m_timeout.Set(20000);
683 m_pkt.result = av_read_frame(m_pFormatContext, &m_pkt.pkt);
684 m_timeout.SetInfinite();
685 }
686
687 if (m_pkt.result == AVERROR(EINTR) || m_pkt.result == AVERROR(EAGAIN))
688 {
689 // timeout, probably no real error, return empty packet
690 bReturnEmpty = true;
691 }
692 else if (m_pkt.result < 0)
693 {
694 Flush();
695 }
696 else if (IsProgramChange())
697 {
698 // update streams
699 CreateStreams(m_program);
700
701 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0);
702 pPacket->iStreamId = DMX_SPECIALID_STREAMCHANGE;
703
704 return pPacket;
705 }
706 // check size and stream index for being in a valid range
707 else if (m_pkt.pkt.size < 0 ||
708 m_pkt.pkt.stream_index < 0 ||
709 m_pkt.pkt.stream_index >= (int)m_pFormatContext->nb_streams)
710 {
711 // XXX, in some cases ffmpeg returns a negative packet size
712 if(m_pFormatContext->pb && !m_pFormatContext->pb->eof_reached)
713 {
714 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::Read() no valid packet");
715 bReturnEmpty = true;
716 Flush();
717 }
718 else
719 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::Read() returned invalid packet and eof reached");
720
721 m_pkt.result = -1;
722 av_free_packet(&m_pkt.pkt);
723 }
724 else
725 {
726 ParsePacket(&m_pkt.pkt);
727
728 AVStream *stream = m_pFormatContext->streams[m_pkt.pkt.stream_index];
729
730 if (IsVideoReady())
731 {
732 if (m_program != UINT_MAX)
733 {
734 /* check so packet belongs to selected program */
735 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
736 {
737 if(m_pkt.pkt.stream_index == (int)m_pFormatContext->programs[m_program]->stream_index[i])
738 {
739 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
740 break;
741 }
742 }
743
744 if (!pPacket)
745 bReturnEmpty = true;
746 }
747 else
748 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
749 }
750 else
751 bReturnEmpty = true;
752
753 if (pPacket)
754 {
755 // lavf sometimes bugs out and gives 0 dts/pts instead of no dts/pts
756 // since this could only happens on initial frame under normal
757 // circomstances, let's assume it is wrong all the time
758 if(m_pkt.pkt.dts == 0)
759 m_pkt.pkt.dts = AV_NOPTS_VALUE;
760 if(m_pkt.pkt.pts == 0)
761 m_pkt.pkt.pts = AV_NOPTS_VALUE;
762
763 if(m_bMatroska && stream->codec && stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
764 { // matroska can store different timestamps
765 // for different formats, for native stored
766 // stuff it is pts, but for ms compatibility
767 // tracks, it is really dts. sadly ffmpeg
768 // sets these two timestamps equal all the
769 // time, so we select it here instead
770 if(stream->codec->codec_tag == 0)
771 m_pkt.pkt.dts = AV_NOPTS_VALUE;
772 else
773 m_pkt.pkt.pts = AV_NOPTS_VALUE;
774 }
775
776 // we need to get duration slightly different for matroska embedded text subtitels
777 if(m_bMatroska && stream->codec && stream->codec->codec_id == AV_CODEC_ID_TEXT && m_pkt.pkt.convergence_duration != 0)
778 m_pkt.pkt.duration = m_pkt.pkt.convergence_duration;
779
780 if(m_bAVI && stream->codec && stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
781 {
782 // AVI's always have borked pts, specially if m_pFormatContext->flags includes
783 // AVFMT_FLAG_GENPTS so always use dts
784 m_pkt.pkt.pts = AV_NOPTS_VALUE;
785 }
786
787 // copy contents into our own packet
788 pPacket->iSize = m_pkt.pkt.size;
789
790 // maybe we can avoid a memcpy here by detecting where pkt.destruct is pointing too?
791 if (m_pkt.pkt.data)
792 memcpy(pPacket->pData, m_pkt.pkt.data, pPacket->iSize);
793
794 pPacket->pts = ConvertTimestamp(m_pkt.pkt.pts, stream->time_base.den, stream->time_base.num);
795 pPacket->dts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num);
796 pPacket->duration = DVD_SEC_TO_TIME((double)m_pkt.pkt.duration * stream->time_base.num / stream->time_base.den);
797
798 // used to guess streamlength
799 if (pPacket->dts != DVD_NOPTS_VALUE && (pPacket->dts > m_currentPts || m_currentPts == DVD_NOPTS_VALUE))
800 m_currentPts = pPacket->dts;
801
802
803 // check if stream has passed full duration, needed for live streams
804 bool bAllowDurationExt = (stream->codec && (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO || stream->codec->codec_type == AVMEDIA_TYPE_AUDIO));
805 if(bAllowDurationExt && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE)
806 {
807 int64_t duration;
808 duration = m_pkt.pkt.dts;
809 if(stream->start_time != (int64_t)AV_NOPTS_VALUE)
810 duration -= stream->start_time;
811
812 if(duration > stream->duration)
813 {
814 stream->duration = duration;
815 duration = av_rescale_rnd(stream->duration, (int64_t)stream->time_base.num * AV_TIME_BASE, stream->time_base.den, AV_ROUND_NEAR_INF);
816 if ((m_pFormatContext->duration == (int64_t)AV_NOPTS_VALUE)
817 || (m_pFormatContext->duration != (int64_t)AV_NOPTS_VALUE && duration > m_pFormatContext->duration))
818 m_pFormatContext->duration = duration;
819 }
820 }
821
822 // store internal id until we know the continuous id presented to player
823 // the stream might not have been created yet
824 pPacket->iStreamId = m_pkt.pkt.stream_index;
825 }
826 m_pkt.result = -1;
827 av_free_packet(&m_pkt.pkt);
828 }
829 }
830 } // end of lock scope
831 if (bReturnEmpty && !pPacket)
832 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0);
833
834 if (!pPacket) return NULL;
835
836 // check streams, can we make this a bit more simple?
837 if (pPacket && pPacket->iStreamId >= 0)
838 {
839 CDemuxStream *stream = GetStreamInternal(pPacket->iStreamId);
840 if (!stream ||
841 stream->pPrivate != m_pFormatContext->streams[pPacket->iStreamId] ||
842 stream->codec != m_pFormatContext->streams[pPacket->iStreamId]->codec->codec_id)
843 {
844 // content has changed, or stream did not yet exist
845 stream = AddStream(pPacket->iStreamId);
846 }
847 // we already check for a valid m_streams[pPacket->iStreamId] above
848 else if (stream->type == STREAM_AUDIO)
849 {
850 if (((CDemuxStreamAudio*)stream)->iChannels != m_pFormatContext->streams[pPacket->iStreamId]->codec->channels ||
851 ((CDemuxStreamAudio*)stream)->iSampleRate != m_pFormatContext->streams[pPacket->iStreamId]->codec->sample_rate)
852 {
853 // content has changed
854 stream = AddStream(pPacket->iStreamId);
855 }
856 }
857 else if (stream->type == STREAM_VIDEO)
858 {
859 if (((CDemuxStreamVideo*)stream)->iWidth != m_pFormatContext->streams[pPacket->iStreamId]->codec->width ||
860 ((CDemuxStreamVideo*)stream)->iHeight != m_pFormatContext->streams[pPacket->iStreamId]->codec->height)
861 {
862 // content has changed
863 stream = AddStream(pPacket->iStreamId);
864 }
865 }
866 if (!stream)
867 {
868 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::AddStream - internal error, stream is null");
869 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
870 return NULL;
871 }
872 // set continuous stream id for player
873 pPacket->iStreamId = stream->iId;
874 }
875 return pPacket;
876}
877
878bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
879{
880 if (!m_pInput)
881 return false;
882
883 if(time < 0)
884 time = 0;
885
886 m_pkt.result = -1;
887 av_free_packet(&m_pkt.pkt);
888
889 CDVDInputStream::ISeekTime* ist = dynamic_cast<CDVDInputStream::ISeekTime*>(m_pInput);
890 if (ist)
891 {
892 if (!ist->SeekTime(time))
893 return false;
894
895 if(startpts)
896 *startpts = DVD_NOPTS_VALUE;
897
898 Flush();
899
900 // also empty the internal ffmpeg buffer
901 m_ioContext->buf_ptr = m_ioContext->buf_end;
902
903 return true;
904 }
905
906 if(!m_pInput->Seek(0, SEEK_POSSIBLE)
907 && !m_pInput->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
908 {
909 CLog::Log(LOGDEBUG, "%s - input stream reports it is not seekable", __FUNCTION__);
910 return false;
911 }
912
913 int64_t seek_pts = (int64_t)time * (AV_TIME_BASE / 1000);
914 bool ismp3 = m_pFormatContext->iformat && (strcmp(m_pFormatContext->iformat->name, "mp3") == 0);
915 if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE && !ismp3)
916 seek_pts += m_pFormatContext->start_time;
917
918 int ret;
919 {
920 CSingleLock lock(m_critSection);
921 ret = av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0);
922
923 // demuxer will return failure, if you seek behind eof
924 if (ret < 0 && m_pFormatContext->duration && seek_pts >= (m_pFormatContext->duration + m_pFormatContext->start_time))
925 ret = 0;
926 else if (ret < 0 && m_pInput->IsEOF())
927 ret = 0;
928
929 if(ret >= 0)
930 UpdateCurrentPTS();
931 }
932
933 if(m_currentPts == DVD_NOPTS_VALUE)
934 CLog::Log(LOGDEBUG, "%s - unknown position after seek", __FUNCTION__);
935 else
936 CLog::Log(LOGDEBUG, "%s - seek ended up on time %d", __FUNCTION__, (int)(m_currentPts / DVD_TIME_BASE * 1000));
937
938 // in this case the start time is requested time
939 if(startpts)
940 *startpts = DVD_MSEC_TO_TIME(time);
941
942 return (ret >= 0);
943}
944
945bool CDVDDemuxFFmpeg::SeekByte(int64_t pos)
946{
947 CSingleLock lock(m_critSection);
948 int ret = av_seek_frame(m_pFormatContext, -1, pos, AVSEEK_FLAG_BYTE);
949
950 if(ret >= 0)
951 UpdateCurrentPTS();
952
953 m_pkt.result = -1;
954 av_free_packet(&m_pkt.pkt);
955
956 return (ret >= 0);
957}
958
959void CDVDDemuxFFmpeg::UpdateCurrentPTS()
960{
961 m_currentPts = DVD_NOPTS_VALUE;
962
963 int idx = av_find_default_stream_index(m_pFormatContext);
964 if (idx >= 0)
965 {
966 AVStream *stream = m_pFormatContext->streams[idx];
967 if(stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE)
968 {
969 double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num);
970 if(m_currentPts == DVD_NOPTS_VALUE || m_currentPts > ts )
971 m_currentPts = ts;
972 }
973 }
974}
975
976int CDVDDemuxFFmpeg::GetStreamLength()
977{
978 if (!m_pFormatContext)
979 return 0;
980
981 if (m_pFormatContext->duration < 0)
982 return 0;
983
984 return (int)(m_pFormatContext->duration / (AV_TIME_BASE / 1000));
985}
986
987/**
988 * @brief Finds stream based on demuxer index
989 */
990CDemuxStream* CDVDDemuxFFmpeg::GetStream(int iStreamId)
991{
992 if(iStreamId >= 0 && (size_t)iStreamId < m_stream_index.size())
993 return m_stream_index[iStreamId]->second;
994 else
995 return NULL;
996}
997
998/**
999 * @brief Finds stream based on ffmpeg index
1000 */
1001CDemuxStream* CDVDDemuxFFmpeg::GetStreamInternal(int iId)
1002{
1003 std::map<int, CDemuxStream*>::iterator it = m_streams.find(iId);
1004 if (it == m_streams.end())
1005 return NULL;
1006 else
1007 return it->second;
1008}
1009
1010int CDVDDemuxFFmpeg::GetNrOfStreams()
1011{
1012 return m_stream_index.size();
1013}
1014
1015static double SelectAspect(AVStream* st, bool* forced)
1016{
1017 *forced = false;
1018 /* if stream aspect is 1:1 or 0:0 use codec aspect */
1019 if((st->sample_aspect_ratio.den == 1 || st->sample_aspect_ratio.den == 0)
1020 && (st->sample_aspect_ratio.num == 1 || st->sample_aspect_ratio.num == 0)
1021 && st->codec->sample_aspect_ratio.num != 0)
1022 return av_q2d(st->codec->sample_aspect_ratio);
1023
1024 *forced = true;
1025 if(st->sample_aspect_ratio.num != 0)
1026 return av_q2d(st->sample_aspect_ratio);
1027
1028 return 0.0;
1029}
1030
1031void CDVDDemuxFFmpeg::CreateStreams(unsigned int program)
1032{
1033 DisposeStreams();
1034
1035 // add the ffmpeg streams to our own stream map
1036 if (m_pFormatContext->nb_programs)
1037 {
1038 // check if desired program is available
1039 if (program < m_pFormatContext->nb_programs && m_pFormatContext->programs[program]->nb_stream_indexes > 0)
1040 {
1041 m_program = program;
1042 }
1043 else
1044 m_program = UINT_MAX;
1045
1046 // look for first non empty stream and discard nonselected programs
1047 for (unsigned int i = 0; i < m_pFormatContext->nb_programs; i++)
1048 {
1049 if(m_program == UINT_MAX && m_pFormatContext->programs[i]->nb_stream_indexes > 0)
1050 {
1051 m_program = i;
1052 }
1053
1054 if(i != m_program)
1055 m_pFormatContext->programs[i]->discard = AVDISCARD_ALL;
1056 }
1057 if(m_program != UINT_MAX)
1058 {
1059 // add streams from selected program
1060 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
1061 AddStream(m_pFormatContext->programs[m_program]->stream_index[i]);
1062 }
1063 }
1064 else
1065 m_program = UINT_MAX;
1066
1067 // if there were no programs or they were all empty, add all streams
1068 if (m_program == UINT_MAX)
1069 {
1070 for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
1071 AddStream(i);
1072 }
1073}
1074
1075void CDVDDemuxFFmpeg::DisposeStreams()
1076{
1077 std::map<int, CDemuxStream*>::iterator it;
1078 for(it = m_streams.begin(); it != m_streams.end(); ++it)
1079 delete it->second;
1080 m_streams.clear();
1081 m_stream_index.clear();
1082}
1083
1084CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId)
1085{
1086 AVStream* pStream = m_pFormatContext->streams[iId];
1087 if (pStream)
1088 {
1089 CDemuxStream* stream = NULL;
1090
1091 switch (pStream->codec->codec_type)
1092 {
1093 case AVMEDIA_TYPE_AUDIO:
1094 {
1095 CDemuxStreamAudioFFmpeg* st = new CDemuxStreamAudioFFmpeg(this, pStream);
1096 stream = st;
1097 st->iChannels = pStream->codec->channels;
1098 st->iSampleRate = pStream->codec->sample_rate;
1099 st->iBlockAlign = pStream->codec->block_align;
1100 st->iBitRate = pStream->codec->bit_rate;
1101 st->iBitsPerSample = pStream->codec->bits_per_raw_sample;
1102 if (st->iBitsPerSample == 0)
1103 st->iBitsPerSample = pStream->codec->bits_per_coded_sample;
1104
1105 if(av_dict_get(pStream->metadata, "title", NULL, 0))
1106 st->m_description = av_dict_get(pStream->metadata, "title", NULL, 0)->value;
1107
1108 break;
1109 }
1110 case AVMEDIA_TYPE_VIDEO:
1111 {
1112 CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream);
1113 stream = st;
1114 if(strcmp(m_pFormatContext->iformat->name, "flv") == 0)
1115 st->bVFR = true;
1116 else
1117 st->bVFR = false;
1118
1119 // never trust pts in avi files with h264.
1120 if (m_bAVI && pStream->codec->codec_id == AV_CODEC_ID_H264)
1121 st->bPTSInvalid = true;
1122
1123#if defined(AVFORMAT_HAS_STREAM_GET_R_FRAME_RATE)
1124 AVRational r_frame_rate = av_stream_get_r_frame_rate(pStream);
1125#else
1126 AVRational r_frame_rate = pStream->r_frame_rate;
1127#endif
1128
1129 //average fps is more accurate for mkv files
1130 if (m_bMatroska && pStream->avg_frame_rate.den && pStream->avg_frame_rate.num)
1131 {
1132 st->iFpsRate = pStream->avg_frame_rate.num;
1133 st->iFpsScale = pStream->avg_frame_rate.den;
1134 }
1135 else if(r_frame_rate.den && r_frame_rate.num)
1136 {
1137 st->iFpsRate = r_frame_rate.num;
1138 st->iFpsScale = r_frame_rate.den;
1139 }
1140 else
1141 {
1142 st->iFpsRate = 0;
1143 st->iFpsScale = 0;
1144 }
1145
1146 // added for aml hw decoder, mkv frame-rate can be wrong.
1147 if (r_frame_rate.den && r_frame_rate.num)
1148 {
1149 st->irFpsRate = r_frame_rate.num;
1150 st->irFpsScale = r_frame_rate.den;
1151 }
1152 else
1153 {
1154 st->irFpsRate = 0;
1155 st->irFpsScale = 0;
1156 }
1157
1158 if (pStream->codec_info_nb_frames > 0
1159 && pStream->codec_info_nb_frames <= 2
1160 && m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
1161 {
1162 CLog::Log(LOGDEBUG, "%s - fps may be unreliable since ffmpeg decoded only %d frame(s)", __FUNCTION__, pStream->codec_info_nb_frames);
1163 st->iFpsRate = 0;
1164 st->iFpsScale = 0;
1165 }
1166
1167 st->iWidth = pStream->codec->width;
1168 st->iHeight = pStream->codec->height;
1169 st->fAspect = SelectAspect(pStream, &st->bForcedAspect) * pStream->codec->width / pStream->codec->height;
1170 st->iOrientation = 0;
1171 st->iBitsPerPixel = pStream->codec->bits_per_coded_sample;
1172
1173 AVDictionaryEntry *rtag = av_dict_get(pStream->metadata, "rotate", NULL, 0);
1174 if (rtag)
1175 st->iOrientation = atoi(rtag->value);
1176
1177 // detect stereoscopic mode
1178 std::string stereoMode = GetStereoModeFromMetadata(pStream->metadata);
1179 // check for metadata in file if detection in stream failed
1180 if (stereoMode.empty())
1181 stereoMode = GetStereoModeFromMetadata(m_pFormatContext->metadata);
1182 if (!stereoMode.empty())
1183 st->stereo_mode = stereoMode;
1184
1185
1186 if ( m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD) )
1187 {
1188 if (pStream->codec->codec_id == AV_CODEC_ID_PROBE)
1189 {
1190 // fix MPEG-1/MPEG-2 video stream probe returning AV_CODEC_ID_PROBE for still frames.
1191 // ffmpeg issue 1871, regression from ffmpeg r22831.
1192 if ((pStream->id & 0xF0) == 0xE0)
1193 {
1194 pStream->codec->codec_id = AV_CODEC_ID_MPEG2VIDEO;
1195 pStream->codec->codec_tag = MKTAG('M','P','2','V');
1196 CLog::Log(LOGERROR, "%s - AV_CODEC_ID_PROBE detected, forcing AV_CODEC_ID_MPEG2VIDEO", __FUNCTION__);
1197 }
1198 }
1199 }
1200 break;
1201 }
1202 case AVMEDIA_TYPE_DATA:
1203 {
1204 stream = new CDemuxStream();
1205 stream->type = STREAM_DATA;
1206 break;
1207 }
1208 case AVMEDIA_TYPE_SUBTITLE:
1209 {
1210 if (pStream->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT && CSettings::Get().GetBool("videoplayer.teletextenabled"))
1211 {
1212 CDemuxStreamTeletext* st = new CDemuxStreamTeletext();
1213 stream = st;
1214 stream->type = STREAM_TELETEXT;
1215 break;
1216 }
1217 else
1218 {
1219 CDemuxStreamSubtitleFFmpeg* st = new CDemuxStreamSubtitleFFmpeg(this, pStream);
1220 stream = st;
1221
1222 if(av_dict_get(pStream->metadata, "title", NULL, 0))
1223 st->m_description = av_dict_get(pStream->metadata, "title", NULL, 0)->value;
1224
1225 break;
1226 }
1227 }
1228 case AVMEDIA_TYPE_ATTACHMENT:
1229 { //mkv attachments. Only bothering with fonts for now.
1230 if(pStream->codec->codec_id == AV_CODEC_ID_TTF
1231 || pStream->codec->codec_id == AV_CODEC_ID_OTF
1232 )
1233 {
1234 std::string fileName = "special://temp/fonts/";
1235 XFILE::CDirectory::Create(fileName);
1236 AVDictionaryEntry *nameTag = av_dict_get(pStream->metadata, "filename", NULL, 0);
1237 if (!nameTag)
1238 {
1239 CLog::Log(LOGERROR, "%s: TTF attachment has no name", __FUNCTION__);
1240 }
1241 else
1242 {
1243 fileName += nameTag->value;
1244 XFILE::CFile file;
1245 if(pStream->codec->extradata && file.OpenForWrite(fileName))
1246 {
1247 if (file.Write(pStream->codec->extradata, pStream->codec->extradata_size) != pStream->codec->extradata_size)
1248 {
1249 file.Close();
1250 XFILE::CFile::Delete(fileName);
1251 CLog::Log(LOGDEBUG, "%s: Error saving font file \"%s\"", __FUNCTION__, fileName.c_str());
1252 }
1253 }
1254 }
1255 }
1256 stream = new CDemuxStream();
1257 stream->type = STREAM_NONE;
1258 break;
1259 }
1260 default:
1261 {
1262 stream = new CDemuxStream();
1263 stream->type = STREAM_NONE;
1264 break;
1265 }
1266 }
1267
1268 // set ffmpeg type
1269 stream->orig_type = pStream->codec->codec_type;
1270
1271 // generic stuff
1272 if (pStream->duration != (int64_t)AV_NOPTS_VALUE)
1273 stream->iDuration = (int)((pStream->duration / AV_TIME_BASE) & 0xFFFFFFFF);
1274
1275 stream->codec = pStream->codec->codec_id;
1276 stream->codec_fourcc = pStream->codec->codec_tag;
1277 stream->profile = pStream->codec->profile;
1278 stream->level = pStream->codec->level;
1279
1280 stream->source = STREAM_SOURCE_DEMUX;
1281 stream->pPrivate = pStream;
1282 stream->flags = (CDemuxStream::EFlags)pStream->disposition;
1283
1284 AVDictionaryEntry *langTag = av_dict_get(pStream->metadata, "language", NULL, 0);
1285 if (langTag)
1286 strncpy(stream->language, langTag->value, 3);
1287
1288 if( pStream->codec->extradata && pStream->codec->extradata_size > 0 )
1289 {
1290 stream->ExtraSize = pStream->codec->extradata_size;
1291 stream->ExtraData = new uint8_t[pStream->codec->extradata_size];
1292 memcpy(stream->ExtraData, pStream->codec->extradata, pStream->codec->extradata_size);
1293 }
1294
1295#ifdef HAVE_LIBBLURAY
1296 if( m_pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY) )
1297 static_cast<CDVDInputStreamBluray*>(m_pInput)->GetStreamInfo(pStream->id, stream->language);
1298#endif
1299 if( m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD) )
1300 {
1301 // this stuff is really only valid for dvd's.
1302 // this is so that the physicalid matches the
1303 // id's reported from libdvdnav
1304 switch(stream->codec)
1305 {
1306 case AV_CODEC_ID_AC3:
1307 stream->iPhysicalId = pStream->id - 128;
1308 break;
1309 case AV_CODEC_ID_DTS:
1310 stream->iPhysicalId = pStream->id - 136;
1311 break;
1312 case AV_CODEC_ID_MP2:
1313 stream->iPhysicalId = pStream->id - 448;
1314 break;
1315 case AV_CODEC_ID_PCM_S16BE:
1316 stream->iPhysicalId = pStream->id - 160;
1317 break;
1318 case AV_CODEC_ID_DVD_SUBTITLE:
1319 stream->iPhysicalId = pStream->id - 0x20;
1320 break;
1321 default:
1322 stream->iPhysicalId = pStream->id & 0x1f;
1323 break;
1324 }
1325 }
1326 else
1327 stream->iPhysicalId = pStream->id;
1328
1329 AddStream(iId, stream);
1330 return stream;
1331 }
1332 else
1333 return NULL;
1334}
1335
1336/**
1337 * @brief Adds or updates a demux stream based in ffmpeg id
1338 */
1339void CDVDDemuxFFmpeg::AddStream(int iId, CDemuxStream* stream)
1340{
1341 std::pair<std::map<int, CDemuxStream*>::iterator, bool> res;
1342
1343 res = m_streams.insert(std::make_pair(iId, stream));
1344 if(res.second)
1345 {
1346 /* was new stream */
1347 stream->iId = m_stream_index.size();
1348 m_stream_index.push_back(res.first);
1349 }
1350 else
1351 {
1352 /* replace old stream, keeping old index */
1353 stream->iId = res.first->second->iId;
1354
1355 delete res.first->second;
1356 res.first->second = stream;
1357 }
1358 if(g_advancedSettings.m_logLevel > LOG_LEVEL_NORMAL)
1359 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::AddStream(%d, ...) -> %d", iId, stream->iId);
1360}
1361
1362
1363std::string CDVDDemuxFFmpeg::GetFileName()
1364{
1365 if(m_pInput)
1366 return m_pInput->GetFileName();
1367 else
1368 return "";
1369}
1370
1371int CDVDDemuxFFmpeg::GetChapterCount()
1372{
1373 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1374 if(ich)
1375 return ich->GetChapterCount();
1376
1377 if(m_pFormatContext == NULL)
1378 return 0;
1379
1380 return m_pFormatContext->nb_chapters;
1381}
1382
1383int CDVDDemuxFFmpeg::GetChapter()
1384{
1385 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1386 if(ich)
1387 return ich->GetChapter();
1388
1389 if(m_pFormatContext == NULL
1390 || m_currentPts == DVD_NOPTS_VALUE)
1391 return 0;
1392
1393 for(unsigned i = 0; i < m_pFormatContext->nb_chapters; i++)
1394 {
1395 AVChapter *chapter = m_pFormatContext->chapters[i];
1396 if(m_currentPts >= ConvertTimestamp(chapter->start, chapter->time_base.den, chapter->time_base.num)
1397 && m_currentPts < ConvertTimestamp(chapter->end, chapter->time_base.den, chapter->time_base.num))
1398 return i + 1;
1399 }
1400
1401 return 0;
1402}
1403
1404void CDVDDemuxFFmpeg::GetChapterName(std::string& strChapterName, int chapterIdx)
1405{
1406 if (chapterIdx <= 0 || chapterIdx > GetChapterCount())
1407 chapterIdx = GetChapter();
1408 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1409 if(ich)
1410 ich->GetChapterName(strChapterName, chapterIdx);
1411 else
1412 {
1413 if(chapterIdx <= 0)
1414 return;
1415
1416 AVDictionaryEntry *titleTag = av_dict_get(m_pFormatContext->chapters[chapterIdx-1]->metadata,
1417 "title", NULL, 0);
1418 if (titleTag)
1419 strChapterName = titleTag->value;
1420 }
1421}
1422
1423int64_t CDVDDemuxFFmpeg::GetChapterPos(int chapterIdx)
1424{
1425 if (chapterIdx <= 0 || chapterIdx > GetChapterCount())
1426 chapterIdx = GetChapter();
1427 if(chapterIdx <= 0)
1428 return 0;
1429
1430 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1431 if(ich)
1432 return ich->GetChapterPos(chapterIdx);
1433
1434 return m_pFormatContext->chapters[chapterIdx-1]->start*av_q2d(m_pFormatContext->chapters[chapterIdx-1]->time_base);
1435}
1436
1437bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts)
1438{
1439 if(chapter < 1)
1440 chapter = 1;
1441
1442 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1443 if(ich)
1444 {
1445 CLog::Log(LOGDEBUG, "%s - chapter seeking using input stream", __FUNCTION__);
1446 if(!ich->SeekChapter(chapter))
1447 return false;
1448
1449 if(startpts)
1450 {
1451 *startpts = DVD_SEC_TO_TIME(ich->GetChapterPos(chapter));
1452 }
1453
1454 Flush();
1455 return true;
1456 }
1457
1458 if(m_pFormatContext == NULL)
1459 return false;
1460
1461 if(chapter < 1 || chapter > (int)m_pFormatContext->nb_chapters)
1462 return false;
1463
1464 AVChapter *ch = m_pFormatContext->chapters[chapter-1];
1465 double dts = ConvertTimestamp(ch->start, ch->time_base.den, ch->time_base.num);
1466 return SeekTime(DVD_TIME_TO_MSEC(dts), true, startpts);
1467}
1468
1469void CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId, std::string &strName)
1470{
1471 CDemuxStream *stream = GetStream(iStreamId);
1472 if (stream)
1473 {
1474 unsigned int in = stream->codec_fourcc;
1475 // FourCC codes are only valid on video streams, audio codecs in AVI/WAV
1476 // are 2 bytes and audio codecs in transport streams have subtle variation
1477 // e.g AC-3 instead of ac3
1478 if (stream->type == STREAM_VIDEO && in != 0)
1479 {
1480 char fourcc[5];
1481#if defined(__powerpc__)
1482 fourcc[0] = in & 0xff;
1483 fourcc[1] = (in >> 8) & 0xff;
1484 fourcc[2] = (in >> 16) & 0xff;
1485 fourcc[3] = (in >> 24) & 0xff;
1486#else
1487 memcpy(fourcc, &in, 4);
1488#endif
1489 fourcc[4] = 0;
1490 // fourccs have to be 4 characters
1491 if (strlen(fourcc) == 4)
1492 {
1493 strName = fourcc;
1494 StringUtils::ToLower(strName);
1495 return;
1496 }
1497 }
1498
1499#ifdef FF_PROFILE_DTS_HD_MA
1500 /* use profile to determine the DTS type */
1501 if (stream->codec == AV_CODEC_ID_DTS)
1502 {
1503 if (stream->profile == FF_PROFILE_DTS_HD_MA)
1504 strName = "dtshd_ma";
1505 else if (stream->profile == FF_PROFILE_DTS_HD_HRA)
1506 strName = "dtshd_hra";
1507 else
1508 strName = "dca";
1509 return;
1510 }
1511#endif
1512
1513 AVCodec *codec = avcodec_find_decoder(stream->codec);
1514 if (codec)
1515 strName = codec->name;
1516 }
1517}
1518
1519bool CDVDDemuxFFmpeg::IsProgramChange()
1520{
1521 if (m_program == UINT_MAX)
1522 return false;
1523
1524 if (m_program == 0 && !m_pFormatContext->nb_programs)
1525 return false;
1526
1527 if(m_pFormatContext->programs[m_program]->nb_stream_indexes != m_streams.size())
1528 return true;
1529
1530 if (m_program >= m_pFormatContext->nb_programs)
1531 return true;
1532
1533 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
1534 {
1535 int idx = m_pFormatContext->programs[m_program]->stream_index[i];
1536 CDemuxStream *stream = GetStreamInternal(idx);
1537 if(!stream)
1538 return true;
1539 if(m_pFormatContext->streams[idx]->codec->codec_type != stream->orig_type)
1540 return true;
1541 }
1542 return false;
1543}
1544
1545std::string CDVDDemuxFFmpeg::GetStereoModeFromMetadata(AVDictionary *pMetadata)
1546{
1547 std::string stereoMode;
1548 AVDictionaryEntry *tag = NULL;
1549
1550 // matroska
1551 tag = av_dict_get(pMetadata, "stereo_mode", NULL, 0);
1552 if (tag && tag->value)
1553 stereoMode = tag->value;
1554
1555 // asf / wmv
1556 if (stereoMode.empty())
1557 {
1558 tag = av_dict_get(pMetadata, "Stereoscopic", NULL, 0);
1559 if (tag && tag->value)
1560 {
1561 tag = av_dict_get(pMetadata, "StereoscopicLayout", NULL, 0);
1562 if (tag && tag->value)
1563 stereoMode = ConvertCodecToInternalStereoMode(tag->value, WmvToInternalStereoModeMap);
1564 }
1565 }
1566
1567 return stereoMode;
1568}
1569
1570std::string CDVDDemuxFFmpeg::ConvertCodecToInternalStereoMode(const std::string &mode, const StereoModeConversionMap *conversionMap)
1571{
1572 size_t i = 0;
1573 while (conversionMap[i].name)
1574 {
1575 if (mode == conversionMap[i].name)
1576 return conversionMap[i].mode;
1577 i++;
1578 }
1579 return "";
1580}
1581
1582void CDVDDemuxFFmpeg::ParsePacket(AVPacket *pkt)
1583{
1584 AVStream *st = m_pFormatContext->streams[pkt->stream_index];
1585 CDemuxStream *stream = GetStreamInternal(pkt->stream_index);
1586
1587 // if the stream is new, tell ffmpeg to parse the stream
1588 if (!stream && !st->parser)
1589 {
1590 st->need_parsing = AVSTREAM_PARSE_FULL;
1591 }
1592
1593 // split extradata
1594 if(st->parser && st->parser->parser->split && !st->codec->extradata)
1595 {
1596 int i = st->parser->parser->split(st->codec, pkt->data, pkt->size);
1597 if (i > 0 && i < FF_MAX_EXTRADATA_SIZE)
1598 {
1599 // Found extradata, fill it in. This will cause
1600 // a new stream to be created and used.
1601 st->codec->extradata_size = i;
1602 st->codec->extradata = (uint8_t*)av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
1603 if (st->codec->extradata)
1604 {
1605 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::Read() fetching extradata, extradata_size(%d)", st->codec->extradata_size);
1606 memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size);
1607 memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE);
1608 }
1609 else
1610 {
1611 st->codec->extradata_size = 0;
1612 }
1613 }
1614 }
1615
1616 // for video we need a decoder to get desired information into codec context
1617 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->codec->extradata &&
1618 (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
1619 {
1620 // open a decoder, it will be cleared down by ffmpeg on closing the stream
1621 if (!st->codec->codec)
1622 {
1623 const AVCodec* codec;
1624 AVDictionary *thread_opt = NULL;
1625 codec = avcodec_find_decoder(st->codec->codec_id);
1626 // Force thread count to 1 since the h264 decoder will not extract
1627 // SPS and PPS to extradata during multi-threaded decoding
1628 av_dict_set(&thread_opt, "threads", "1", 0);
1629 int res = avcodec_open2(st->codec, codec, &thread_opt);
1630 if(res < 0)
1631 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() unable to open codec %d", res);
1632 av_dict_free(&thread_opt);
1633 }
1634
1635 // We don't need to actually decode here
1636 // we just want to transport SPS data into codec context
1637 st->codec->skip_idct = AVDISCARD_ALL;
1638 // extradata is not decoded if skip_frame >= AVDISCARD_NONREF
1639// st->codec->skip_frame = AVDISCARD_ALL;
1640 st->codec->skip_loop_filter = AVDISCARD_ALL;
1641
1642 // We are looking for an IDR frame
1643 AVFrame picture;
1644 memset(&picture, 0, sizeof(AVFrame));
1645 picture.pts = picture.pkt_dts = picture.pkt_pts = picture.best_effort_timestamp = AV_NOPTS_VALUE;
1646 picture.pkt_pos = -1;
1647 picture.key_frame = 1;
1648 picture.format = -1;
1649
1650 int got_picture = 0;
1651 avcodec_decode_video2(st->codec, &picture, &got_picture, pkt);
1652 }
1653}
1654
1655bool CDVDDemuxFFmpeg::IsVideoReady()
1656{
1657 AVStream *st;
1658 bool hasVideo = false;
1659
1660 if(!m_checkvideo)
1661 return true;
1662
1663 if (m_program == 0 && !m_pFormatContext->nb_programs)
1664 return false;
1665
1666 if(m_program != UINT_MAX)
1667 {
1668 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
1669 {
1670 int idx = m_pFormatContext->programs[m_program]->stream_index[i];
1671 st = m_pFormatContext->streams[idx];
1672 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
1673 {
1674 if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE)
1675 return true;
1676 hasVideo = true;
1677 }
1678 }
1679 }
1680 else
1681 {
1682 for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
1683 {
1684 st = m_pFormatContext->streams[i];
1685 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
1686 {
1687 if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE)
1688 return true;
1689 hasVideo = true;
1690 }
1691 }
1692 }
1693 return !hasVideo;
1694}
1695
1696void CDVDDemuxFFmpeg::ResetVideoStreams()
1697{
1698 AVStream *st;
1699 for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
1700 {
1701 st = m_pFormatContext->streams[i];
1702 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
1703 {
1704 if (st->codec->extradata)
1705 av_free(st->codec->extradata);
1706 st->codec->extradata = NULL;
1707 st->codec->width = 0;
1708 }
1709 }
1710}
1711
1712void CDVDDemuxFFmpeg::GetL16Parameters(int &channels, int &samplerate)
1713{
1714 std::string content;
1715 if (XFILE::CCurlFile::GetContentType(m_pInput->GetURL(), content))
1716 {
1717 StringUtils::ToLower(content);
1718 const size_t len = content.length();
1719 size_t pos = content.find(';');
1720 while (pos < len)
1721 {
1722 // move to the next non-whitespace character
1723 pos = content.find_first_not_of(" \t", pos + 1);
1724
1725 if (pos != std::string::npos)
1726 {
1727 if (content.compare(pos, 9, "channels=", 9) == 0)
1728 {
1729 pos += 9; // move position to char after 'channels='
1730 size_t len = content.find(';', pos);
1731 if (len != std::string::npos)
1732 len -= pos;
1733 std::string no_channels(content, pos, len);
1734 // as we don't support any charset with ';' in name
1735 StringUtils::Trim(no_channels, " \t");
1736 if (!no_channels.empty())
1737 {
1738 int val = strtol(no_channels.c_str(), NULL, 0);
1739 if (val > 0)
1740 channels = val;
1741 else
1742 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::%s - no parameter for channels", __FUNCTION__);
1743 }
1744 }
1745 else if (content.compare(pos, 5, "rate=", 5) == 0)
1746 {
1747 pos += 5; // move position to char after 'rate='
1748 size_t len = content.find(';', pos);
1749 if (len != std::string::npos)
1750 len -= pos;
1751 std::string rate(content, pos, len);
1752 // as we don't support any charset with ';' in name
1753 StringUtils::Trim(rate, " \t");
1754 if (!rate.empty())
1755 {
1756 int val = strtol(rate.c_str(), NULL, 0);
1757 if (val > 0)
1758 samplerate = val;
1759 else
1760 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::%s - no parameter for samplerate", __FUNCTION__);
1761 }
1762 }
1763 pos = content.find(';', pos); // find next parameter
1764 }
1765 }
1766 }
1767}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
new file mode 100644
index 0000000..d180e40
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
@@ -0,0 +1,172 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemux.h"
24#include "threads/CriticalSection.h"
25#include "threads/SystemClock.h"
26#include <map>
27#include <vector>
28
29extern "C" {
30#include "libavformat/avformat.h"
31}
32
33class CDVDDemuxFFmpeg;
34class CURL;
35
36class CDemuxStreamVideoFFmpeg
37 : public CDemuxStreamVideo
38{
39 CDVDDemuxFFmpeg *m_parent;
40 AVStream* m_stream;
41public:
42 CDemuxStreamVideoFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream)
43 : m_parent(parent)
44 , m_stream(stream)
45 {}
46 virtual void GetStreamInfo(std::string& strInfo);
47};
48
49
50class CDemuxStreamAudioFFmpeg
51 : public CDemuxStreamAudio
52{
53 CDVDDemuxFFmpeg *m_parent;
54 AVStream* m_stream;
55public:
56 CDemuxStreamAudioFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream)
57 : m_parent(parent)
58 , m_stream(stream)
59 {}
60 std::string m_description;
61
62 virtual void GetStreamInfo(std::string& strInfo);
63 virtual void GetStreamName(std::string& strInfo);
64};
65
66class CDemuxStreamSubtitleFFmpeg
67 : public CDemuxStreamSubtitle
68{
69 CDVDDemuxFFmpeg *m_parent;
70 AVStream* m_stream;
71public:
72 CDemuxStreamSubtitleFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream)
73 : m_parent(parent)
74 , m_stream(stream)
75 {}
76 std::string m_description;
77
78 virtual void GetStreamInfo(std::string& strInfo);
79 virtual void GetStreamName(std::string& strInfo);
80
81};
82
83#define FFMPEG_FILE_BUFFER_SIZE 32768 // default reading size for ffmpeg
84#define FFMPEG_DVDNAV_BUFFER_SIZE 2048 // for dvd's
85
86struct StereoModeConversionMap;
87
88class CDVDDemuxFFmpeg : public CDVDDemux
89{
90public:
91 CDVDDemuxFFmpeg();
92 virtual ~CDVDDemuxFFmpeg();
93
94 bool Open(CDVDInputStream* pInput, bool streaminfo = true, bool fileinfo = false);
95 void Dispose();
96 void Reset();
97 void Flush();
98 void Abort();
99 void SetSpeed(int iSpeed);
100 virtual std::string GetFileName();
101
102 DemuxPacket* Read();
103
104 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
105 bool SeekByte(int64_t pos);
106 int GetStreamLength();
107 CDemuxStream* GetStream(int iStreamId);
108 int GetNrOfStreams();
109
110 bool SeekChapter(int chapter, double* startpts = NULL);
111 int GetChapterCount();
112 int GetChapter();
113 void GetChapterName(std::string& strChapterName, int chapterIdx=-1);
114 int64_t GetChapterPos(int chapterIdx=-1);
115 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
116
117 bool Aborted();
118
119 AVFormatContext* m_pFormatContext;
120 CDVDInputStream* m_pInput;
121
122protected:
123 friend class CDemuxStreamAudioFFmpeg;
124 friend class CDemuxStreamVideoFFmpeg;
125 friend class CDemuxStreamSubtitleFFmpeg;
126
127 int ReadFrame(AVPacket *packet);
128 CDemuxStream* AddStream(int iId);
129 void AddStream(int iId, CDemuxStream* stream);
130 CDemuxStream* GetStreamInternal(int iStreamId);
131 void CreateStreams(unsigned int program = UINT_MAX);
132 void DisposeStreams();
133 void ParsePacket(AVPacket *pkt);
134 bool IsVideoReady();
135 void ResetVideoStreams();
136
137 AVDictionary *GetFFMpegOptionsFromURL(const CURL &url);
138 double ConvertTimestamp(int64_t pts, int den, int num);
139 void UpdateCurrentPTS();
140 bool IsProgramChange();
141
142 std::string GetStereoModeFromMetadata(AVDictionary *pMetadata);
143 std::string ConvertCodecToInternalStereoMode(const std::string &mode, const StereoModeConversionMap *conversionMap);
144
145 void GetL16Parameters(int &channels, int &samplerate);
146
147 CCriticalSection m_critSection;
148 std::map<int, CDemuxStream*> m_streams;
149 std::vector<std::map<int, CDemuxStream*>::iterator> m_stream_index;
150
151 AVIOContext* m_ioContext;
152
153 double m_currentPts; // used for stream length estimation
154 bool m_bMatroska;
155 bool m_bAVI;
156 int m_speed;
157 unsigned m_program;
158 XbmcThreads::EndTime m_timeout;
159
160 // Due to limitations of ffmpeg, we only can detect a program change
161 // with a packet. This struct saves the packet for the next read and
162 // signals STREAMCHANGE to player
163 struct
164 {
165 AVPacket pkt; // packet ffmpeg returned
166 int result; // result from av_read_packet
167 }m_pkt;
168
169 bool m_streaminfo;
170 bool m_checkvideo;
171};
172
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp
new file mode 100644
index 0000000..3674416
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp
@@ -0,0 +1,391 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21
22#include "DVDCodecs/DVDCodecs.h"
23#include "DVDInputStreams/DVDInputStream.h"
24#include "DVDInputStreams/DVDInputStreamHTSP.h"
25#include "DVDDemuxHTSP.h"
26#include "DVDDemuxUtils.h"
27#include "DVDClock.h"
28#include "dialogs/GUIDialogKaiToast.h"
29#include "utils/log.h"
30#include "utils/StringUtils.h"
31#include <arpa/inet.h>
32
33extern "C" {
34#include "lib/libhts/net.h"
35#include "lib/libhts/htsmsg.h"
36#include "lib/libhts/htsmsg_binary.h"
37}
38
39using namespace std;
40using namespace HTSP;
41
42class CDemuxStreamVideoHTSP
43 : public CDemuxStreamVideo
44{
45 CDVDDemuxHTSP *m_parent;
46 string m_codec;
47public:
48 CDemuxStreamVideoHTSP(CDVDDemuxHTSP *parent, const string& codec)
49 : m_parent(parent)
50 , m_codec(codec)
51 {}
52 void GetStreamInfo(std::string& strInfo)
53 {
54 strInfo = StringUtils::Format("%s, delay: %u, drops: %ub %up %ui"
55 , m_codec.c_str()
56 , m_parent->m_QueueStatus.delay
57 , m_parent->m_QueueStatus.bdrops
58 , m_parent->m_QueueStatus.pdrops
59 , m_parent->m_QueueStatus.idrops);
60 }
61};
62
63class CDemuxStreamAudioHTSP
64 : public CDemuxStreamAudio
65{
66 CDVDDemuxHTSP *m_parent;
67 string m_codec;
68public:
69 CDemuxStreamAudioHTSP(CDVDDemuxHTSP *parent, const string& codec)
70 : m_parent(parent)
71 , m_codec(codec)
72
73 {}
74 void GetStreamInfo(string& strInfo)
75 {
76 strInfo = StringUtils::Format("%s", m_codec.c_str());
77 }
78};
79
80CDVDDemuxHTSP::CDVDDemuxHTSP()
81 : CDVDDemux()
82 , m_Input(NULL)
83 , m_StatusCount(0)
84{
85}
86
87CDVDDemuxHTSP::~CDVDDemuxHTSP()
88{
89 Dispose();
90}
91
92bool CDVDDemuxHTSP::Open(CDVDInputStream* input)
93{
94 Dispose();
95
96 if(!input->IsStreamType(DVDSTREAM_TYPE_HTSP))
97 return false;
98
99 m_Input = (CDVDInputStreamHTSP*)input;
100 m_StatusCount = 0;
101
102 while(m_Streams.empty() && m_StatusCount == 0)
103 {
104 DemuxPacket* pkg = Read();
105 if(!pkg)
106 return false;
107 CDVDDemuxUtils::FreeDemuxPacket(pkg);
108 }
109
110 return true;
111}
112
113void CDVDDemuxHTSP::Dispose()
114{
115}
116
117void CDVDDemuxHTSP::Reset()
118{
119}
120
121
122void CDVDDemuxHTSP::Flush()
123{
124}
125
126bool CDVDDemuxHTSP::ReadStream(uint8_t* buf, int len)
127{
128 while(len > 0)
129 {
130 int ret = m_Input->Read(buf, len);
131 if(ret <= 0)
132 return false;
133 len -= ret;
134 buf += ret;
135 }
136 return true;
137}
138
139htsmsg_t* CDVDDemuxHTSP::ReadStream()
140{
141 if(m_Input->IsStreamType(DVDSTREAM_TYPE_HTSP))
142 return ((CDVDInputStreamHTSP*)m_Input)->ReadStream();
143
144 uint32_t l;
145 if(!ReadStream((uint8_t*)&l, 4))
146 return NULL;
147
148 l = ntohl(l);
149 if(l == 0)
150 return htsmsg_create_map();
151
152 uint8_t* buf = (uint8_t*)malloc(l);
153 if(!buf)
154 return NULL;
155
156 if(!ReadStream(buf, l))
157 return NULL;
158
159 return htsmsg_binary_deserialize(buf, l, buf); /* consumes 'buf' */
160}
161
162DemuxPacket* CDVDDemuxHTSP::Read()
163{
164 htsmsg_t * msg;
165 while((msg = ReadStream()))
166 {
167 const char* method = htsmsg_get_str(msg, "method");
168 if(method == NULL)
169 break;
170
171 if (strcmp("subscriptionStart", method) == 0)
172 SubscriptionStart(msg);
173 else if(strcmp("subscriptionStop", method) == 0)
174 SubscriptionStop (msg);
175 else if(strcmp("subscriptionStatus", method) == 0)
176 SubscriptionStatus(msg);
177 else if(strcmp("queueStatus" , method) == 0)
178 CHTSPSession::ParseQueueStatus(msg, m_QueueStatus);
179 else if(strcmp("muxpkt" , method) == 0)
180 {
181 uint32_t index, duration;
182 const void* bin;
183 size_t binlen;
184 int64_t ts;
185
186 if(htsmsg_get_u32(msg, "stream" , &index) ||
187 htsmsg_get_bin(msg, "payload", &bin, &binlen))
188 break;
189
190 DemuxPacket* pkt = CDVDDemuxUtils::AllocateDemuxPacket(binlen);
191
192 memcpy(pkt->pData, bin, binlen);
193 pkt->iSize = binlen;
194
195 if(!htsmsg_get_u32(msg, "duration", &duration))
196 pkt->duration = (double)duration * DVD_TIME_BASE / 1000000;
197
198 if(!htsmsg_get_s64(msg, "dts", &ts))
199 pkt->dts = (double)ts * DVD_TIME_BASE / 1000000;
200 else
201 pkt->dts = DVD_NOPTS_VALUE;
202
203 if(!htsmsg_get_s64(msg, "pts", &ts))
204 pkt->pts = (double)ts * DVD_TIME_BASE / 1000000;
205 else
206 pkt->pts = DVD_NOPTS_VALUE;
207
208 pkt->iStreamId = -1;
209 for(int i = 0; i < (int)m_Streams.size(); i++)
210 {
211 if(m_Streams[i]->iPhysicalId == (int)index)
212 {
213 pkt->iStreamId = i;
214 break;
215 }
216 }
217
218 htsmsg_destroy(msg);
219 return pkt;
220 }
221
222 break;
223 }
224
225 if(msg)
226 {
227 htsmsg_destroy(msg);
228 return CDVDDemuxUtils::AllocateDemuxPacket(0);
229 }
230 return NULL;
231}
232
233void CDVDDemuxHTSP::SubscriptionStart (htsmsg_t *m)
234{
235 htsmsg_t *streams;
236 htsmsg_t *info;
237 htsmsg_field_t *f;
238
239 if((info = htsmsg_get_map(m, "sourceinfo")))
240 {
241 HTSMSG_FOREACH(f, info)
242 {
243 if(f->hmf_type != HMF_STR)
244 continue;
245 CLog::Log(LOGDEBUG, "CDVDDemuxHTSP::SubscriptionStart - %s: %s", f->hmf_name, htsmsg_field_get_string(f));
246 }
247 }
248
249 if((streams = htsmsg_get_list(m, "streams")) == NULL)
250 {
251 CLog::Log(LOGERROR, "CDVDDemuxHTSP::SubscriptionStart - malformed message");
252 return;
253 }
254
255 for(int i = 0; i < (int)m_Streams.size(); i++)
256 delete m_Streams[i];
257 m_Streams.clear();
258
259 HTSMSG_FOREACH(f, streams)
260 {
261 uint32_t index;
262 const char* type;
263 const char* lang;
264 htsmsg_t* sub;
265
266 if(f->hmf_type != HMF_MAP)
267 continue;
268 sub = &f->hmf_msg;
269
270 if((type = htsmsg_get_str(sub, "type")) == NULL)
271 continue;
272
273 if(htsmsg_get_u32(sub, "index", &index))
274 continue;
275
276 union {
277 CDemuxStream* g;
278 CDemuxStreamAudio* a;
279 CDemuxStreamVideo* v;
280 CDemuxStreamSubtitle* s;
281 CDemuxStreamTeletext* t;
282 } st;
283
284 CLog::Log(LOGDEBUG, "CDVDDemuxHTSP::SubscriptionStart - id: %d, type: %s", index, type);
285
286 if(!strcmp(type, "AC3")) {
287 st.a = new CDemuxStreamAudioHTSP(this, type);
288 st.a->codec = AV_CODEC_ID_AC3;
289 } else if(!strcmp(type, "EAC3")) {
290 st.a = new CDemuxStreamAudioHTSP(this, type);
291 st.a->codec = AV_CODEC_ID_EAC3;
292 } else if(!strcmp(type, "MPEG2AUDIO")) {
293 st.a = new CDemuxStreamAudioHTSP(this, type);
294 st.a->codec = AV_CODEC_ID_MP2;
295 } else if(!strcmp(type, "AAC")) {
296 st.a = new CDemuxStreamAudioHTSP(this, type);
297 st.a->codec = AV_CODEC_ID_AAC;
298 } else if(!strcmp(type, "MPEG2VIDEO")) {
299 st.v = new CDemuxStreamVideoHTSP(this, type);
300 st.v->codec = AV_CODEC_ID_MPEG2VIDEO;
301 st.v->iWidth = htsmsg_get_u32_or_default(sub, "width" , 0);
302 st.v->iHeight = htsmsg_get_u32_or_default(sub, "height", 0);
303 } else if(!strcmp(type, "H264")) {
304 st.v = new CDemuxStreamVideoHTSP(this, type);
305 st.v->codec = AV_CODEC_ID_H264;
306 st.v->iWidth = htsmsg_get_u32_or_default(sub, "width" , 0);
307 st.v->iHeight = htsmsg_get_u32_or_default(sub, "height", 0);
308 } else if(!strcmp(type, "DVBSUB")) {
309 st.s = new CDemuxStreamSubtitle();
310 st.s->codec = AV_CODEC_ID_DVB_SUBTITLE;
311 uint32_t composition_id = 0, ancillary_id = 0;
312 htsmsg_get_u32(sub, "composition_id", &composition_id);
313 htsmsg_get_u32(sub, "ancillary_id" , &ancillary_id);
314 if(composition_id || ancillary_id)
315 {
316 st.s->ExtraData = new uint8_t[4];
317 st.s->ExtraSize = 4;
318 st.s->ExtraData[0] = (composition_id >> 8) & 0xff;
319 st.s->ExtraData[1] = (composition_id >> 0) & 0xff;
320 st.s->ExtraData[2] = (ancillary_id >> 8) & 0xff;
321 st.s->ExtraData[3] = (ancillary_id >> 0) & 0xff;
322 }
323 } else if(!strcmp(type, "TEXTSUB")) {
324 st.s = new CDemuxStreamSubtitle();
325 st.s->codec = AV_CODEC_ID_TEXT;
326 } else if(!strcmp(type, "TELETEXT")) {
327 st.t = new CDemuxStreamTeletext();
328 st.t->codec = AV_CODEC_ID_DVB_TELETEXT;
329 } else {
330 continue;
331 }
332
333 if((lang = htsmsg_get_str(sub, "language")))
334 {
335 strncpy(st.g->language, lang, sizeof(st.g->language));
336 st.g->language[sizeof(st.g->language) - 1] = '\0';
337 }
338
339 st.g->iId = m_Streams.size();
340 st.g->iPhysicalId = index;
341 m_Streams.push_back(st.g);
342 }
343}
344void CDVDDemuxHTSP::SubscriptionStop (htsmsg_t *m)
345{
346 for(int i = 0; i < (int)m_Streams.size(); i++)
347 delete m_Streams[i];
348 m_Streams.clear();
349}
350
351void CDVDDemuxHTSP::SubscriptionStatus(htsmsg_t *m)
352{
353 const char* status;
354 status = htsmsg_get_str(m, "status");
355 if(status == NULL)
356 m_Status = "";
357 else
358 {
359 m_StatusCount++;
360 m_Status = status;
361 CLog::Log(LOGDEBUG, "CDVDDemuxHTSP::SubscriptionStatus - %s", status);
362 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, "TVHeadend Status", status, TOAST_DISPLAY_TIME, false);
363 }
364}
365
366CDemuxStream* CDVDDemuxHTSP::GetStream(int iStreamId)
367{
368 if(iStreamId >= 0 && iStreamId < (int)m_Streams.size())
369 return m_Streams[iStreamId];
370
371 return NULL;
372}
373
374int CDVDDemuxHTSP::GetNrOfStreams()
375{
376 return m_Streams.size();
377}
378
379std::string CDVDDemuxHTSP::GetFileName()
380{
381 if(m_Input)
382 return m_Input->GetFileName();
383 else
384 return "";
385}
386
387void CDVDDemuxHTSP::Abort()
388{
389 if(m_Input)
390 return m_Input->Abort();
391}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h
new file mode 100644
index 0000000..6d73a9d
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#pragma once
22#include "DVDDemux.h"
23#include "filesystem/HTSPSession.h"
24
25class CDVDInputStreamHTSP;
26typedef struct htsmsg htsmsg_t;
27
28class CDVDDemuxHTSP : public CDVDDemux
29{
30public:
31 CDVDDemuxHTSP();
32 virtual ~CDVDDemuxHTSP();
33
34 bool Open(CDVDInputStream* input);
35 void Dispose();
36 void Reset();
37 void Flush();
38 void Abort();
39 void SetSpeed(int iSpeed){};
40
41 std::string GetFileName();
42
43 DemuxPacket* Read();
44
45 bool SeekTime(int time, bool backwords = false, double* startpts = NULL) { return false; }
46 int GetStreamLength() { return 0; }
47
48 CDemuxStream* GetStream(int iStreamId);
49 int GetNrOfStreams();
50
51protected:
52 friend class CDemuxStreamVideoHTSP;
53
54 void SubscriptionStart (htsmsg_t *m);
55 void SubscriptionStop (htsmsg_t *m);
56 void SubscriptionStatus(htsmsg_t *m);
57
58 htsmsg_t* ReadStream();
59 bool ReadStream(uint8_t* buf, int len);
60
61 typedef std::vector<CDemuxStream*> TStreams;
62
63 CDVDInputStream* m_Input;
64 TStreams m_Streams;
65 std::string m_Status;
66 int m_StatusCount;
67 HTSP::SQueueStatus m_QueueStatus;
68};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
new file mode 100644
index 0000000..4ed2d5c
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
@@ -0,0 +1,493 @@
1/*
2 * Copyright (C) 2012-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDInputStreams/DVDInputStream.h"
22#include "DVDDemuxPVRClient.h"
23#include "DVDDemuxUtils.h"
24#include "utils/log.h"
25#include "pvr/PVRManager.h"
26#include "pvr/addons/PVRClients.h"
27#include "../DVDClock.h"
28
29#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
30
31using namespace PVR;
32
33CDemuxStreamPVRInternal::CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent)
34 : m_parent(parent)
35 , m_parser(NULL)
36 , m_context(NULL)
37 , m_parser_split(false)
38{
39}
40
41CDemuxStreamPVRInternal::~CDemuxStreamPVRInternal()
42{
43 DisposeParser();
44}
45
46void CDemuxStreamPVRInternal::DisposeParser()
47{
48 if (m_parser)
49 {
50 av_parser_close(m_parser);
51 m_parser = NULL;
52 }
53 if (m_context)
54 {
55 avcodec_close(m_context);
56 m_context = NULL;
57 }
58}
59
60void CDemuxStreamVideoPVRClient::GetStreamInfo(std::string& strInfo)
61{
62 switch (codec)
63 {
64 case AV_CODEC_ID_MPEG2VIDEO:
65 strInfo = "mpeg2video";
66 break;
67 case AV_CODEC_ID_H264:
68 strInfo = "h264";
69 break;
70 default:
71 break;
72 }
73}
74
75void CDemuxStreamAudioPVRClient::GetStreamInfo(std::string& strInfo)
76{
77 switch (codec)
78 {
79 case AV_CODEC_ID_AC3:
80 strInfo = "ac3";
81 break;
82 case AV_CODEC_ID_EAC3:
83 strInfo = "eac3";
84 break;
85 case AV_CODEC_ID_MP2:
86 strInfo = "mpeg2audio";
87 break;
88 case AV_CODEC_ID_AAC:
89 strInfo = "aac";
90 break;
91 case AV_CODEC_ID_DTS:
92 strInfo = "dts";
93 break;
94 default:
95 break;
96 }
97}
98
99void CDemuxStreamSubtitlePVRClient::GetStreamInfo(std::string& strInfo)
100{
101}
102
103CDVDDemuxPVRClient::CDVDDemuxPVRClient() : CDVDDemux()
104{
105 m_pInput = NULL;
106 for (int i = 0; i < MAX_STREAMS; i++) m_streams[i] = NULL;
107}
108
109CDVDDemuxPVRClient::~CDVDDemuxPVRClient()
110{
111 Dispose();
112}
113
114bool CDVDDemuxPVRClient::Open(CDVDInputStream* pInput)
115{
116 Abort();
117
118 m_pInput = pInput;
119 if (!g_PVRClients->GetPlayingClient(m_pvrClient))
120 return false;
121
122 return true;
123}
124
125void CDVDDemuxPVRClient::Dispose()
126{
127 for (int i = 0; i < MAX_STREAMS; i++)
128 {
129 delete m_streams[i];
130 m_streams[i] = NULL;
131 }
132
133 m_pInput = NULL;
134}
135
136void CDVDDemuxPVRClient::DisposeStream(int iStreamId)
137{
138 if (iStreamId < 0 || iStreamId >= MAX_STREAMS)
139 return;
140 delete m_streams[iStreamId];
141 m_streams[iStreamId] = NULL;
142}
143
144void CDVDDemuxPVRClient::Reset()
145{
146 if(m_pInput && g_PVRManager.IsStarted())
147 m_pvrClient->DemuxReset();
148
149 CDVDInputStream* pInputStream = m_pInput;
150 Dispose();
151 Open(pInputStream);
152}
153
154void CDVDDemuxPVRClient::Abort()
155{
156 if(m_pInput)
157 m_pvrClient->DemuxAbort();
158}
159
160void CDVDDemuxPVRClient::Flush()
161{
162 if(m_pInput && g_PVRManager.IsStarted())
163 m_pvrClient->DemuxFlush();
164}
165
166void CDVDDemuxPVRClient::ParsePacket(DemuxPacket* pkt)
167{
168 CDemuxStream* st = m_streams[pkt->iStreamId];
169 if (st == NULL)
170 return;
171
172 if (st->ExtraSize)
173 return;
174
175 CDemuxStreamPVRInternal* pvr = dynamic_cast<CDemuxStreamPVRInternal*>(st);
176
177 if(pvr == NULL
178 || pvr->m_parser == NULL)
179 return;
180
181 if(pvr->m_context == NULL)
182 {
183 AVCodec *codec = avcodec_find_decoder(st->codec);
184 if (codec == NULL)
185 {
186 CLog::Log(LOGERROR, "%s - can't find decoder", __FUNCTION__);
187 pvr->DisposeParser();
188 return;
189 }
190
191 pvr->m_context = avcodec_alloc_context3(codec);
192 if(pvr->m_context == NULL)
193 {
194 CLog::Log(LOGERROR, "%s - can't allocate context", __FUNCTION__);
195 pvr->DisposeParser();
196 return;
197 }
198 pvr->m_context->time_base.num = 1;
199 pvr->m_context->time_base.den = DVD_TIME_BASE;
200 }
201
202 if(pvr->m_parser_split && pvr->m_parser->parser->split)
203 {
204 int len = pvr->m_parser->parser->split(pvr->m_context, pkt->pData, pkt->iSize);
205 if (len > 0 && len < FF_MAX_EXTRADATA_SIZE)
206 {
207 if (st->ExtraData)
208 delete[] (uint8_t*)st->ExtraData;
209 st->changes++;
210 st->disabled = false;
211 st->ExtraSize = len;
212 st->ExtraData = new uint8_t[len+FF_INPUT_BUFFER_PADDING_SIZE];
213 memcpy(st->ExtraData, pkt->pData, len);
214 memset((uint8_t*)st->ExtraData + len, 0 , FF_INPUT_BUFFER_PADDING_SIZE);
215 pvr->m_parser_split = false;
216 }
217 }
218
219
220 uint8_t *outbuf = NULL;
221 int outbuf_size = 0;
222 int len = av_parser_parse2(pvr->m_parser
223 , pvr->m_context, &outbuf, &outbuf_size
224 , pkt->pData, pkt->iSize
225 , (int64_t)(pkt->pts * DVD_TIME_BASE)
226 , (int64_t)(pkt->dts * DVD_TIME_BASE)
227 , 0);
228 /* our parse is setup to parse complete frames, so we don't care about outbufs */
229 if(len >= 0)
230 {
231#define CHECK_UPDATE(st, trg, src, invalid) do { \
232 if(src != invalid \
233 && src != st->trg) { \
234 CLog::Log(LOGDEBUG, "%s - {%d} " #trg " changed from %d to %d", __FUNCTION__, st->iId, st->trg, src); \
235 st->trg = src; \
236 st->changes++; \
237 st->disabled = false; \
238 } \
239 } while(0)
240
241
242 CHECK_UPDATE(st, profile, pvr->m_context->profile , FF_PROFILE_UNKNOWN);
243 CHECK_UPDATE(st, level , pvr->m_context->level , FF_LEVEL_UNKNOWN);
244
245 switch (st->type)
246 {
247 case STREAM_AUDIO: {
248 CDemuxStreamAudioPVRClient* sta = static_cast<CDemuxStreamAudioPVRClient*>(st);
249 CHECK_UPDATE(sta, iChannels , pvr->m_context->channels , 0);
250 CHECK_UPDATE(sta, iSampleRate , pvr->m_context->sample_rate, 0);
251 break;
252 }
253 case STREAM_VIDEO: {
254 CDemuxStreamVideoPVRClient* stv = static_cast<CDemuxStreamVideoPVRClient*>(st);
255 CHECK_UPDATE(stv, iWidth , pvr->m_context->width , 0);
256 CHECK_UPDATE(stv, iHeight , pvr->m_context->height, 0);
257 break;
258 }
259
260 default:
261 break;
262 }
263
264#undef CHECK_UPDATE
265 }
266 else
267 CLog::Log(LOGDEBUG, "%s - parser returned error %d", __FUNCTION__, len);
268
269 return;
270}
271
272DemuxPacket* CDVDDemuxPVRClient::Read()
273{
274 if (!g_PVRManager.IsStarted())
275 return CDVDDemuxUtils::AllocateDemuxPacket(0);
276
277 DemuxPacket* pPacket = m_pvrClient->DemuxRead();
278 if (!pPacket)
279 {
280 if (m_pInput)
281 m_pInput->Close();
282 return NULL;
283 }
284
285 if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO)
286 {
287 RequestStreams();
288 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
289 return CDVDDemuxUtils::AllocateDemuxPacket(0);
290 }
291 else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE)
292 {
293 RequestStreams();
294 }
295 else if (pPacket->iStreamId >= 0
296 && pPacket->iStreamId < MAX_STREAMS
297 && m_streams[pPacket->iStreamId])
298 {
299 ParsePacket(pPacket);
300 }
301
302 return pPacket;
303}
304
305CDemuxStream* CDVDDemuxPVRClient::GetStream(int iStreamId)
306{
307 if (iStreamId < 0 || iStreamId >= MAX_STREAMS) return NULL;
308 return m_streams[iStreamId];
309}
310
311void CDVDDemuxPVRClient::RequestStreams()
312{
313 if (!g_PVRManager.IsStarted())
314 return;
315
316 PVR_STREAM_PROPERTIES props = {};
317 m_pvrClient->GetStreamProperties(&props);
318 unsigned int i;
319
320 for (i = 0; i < props.iStreamCount; ++i)
321 {
322 CDemuxStream *stm = m_streams[i];
323
324 if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_AUDIO)
325 {
326 CDemuxStreamAudioPVRClient* st = NULL;
327 if (stm)
328 {
329 st = dynamic_cast<CDemuxStreamAudioPVRClient*>(stm);
330 if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
331 DisposeStream(i);
332 }
333 if (!m_streams[i])
334 {
335 st = new CDemuxStreamAudioPVRClient(this);
336 st->m_parser = av_parser_init(props.stream[i].iCodecId);
337 if(st->m_parser)
338 st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
339 }
340 st->iChannels = props.stream[i].iChannels;
341 st->iSampleRate = props.stream[i].iSampleRate;
342 st->iBlockAlign = props.stream[i].iBlockAlign;
343 st->iBitRate = props.stream[i].iBitRate;
344 st->iBitsPerSample = props.stream[i].iBitsPerSample;
345 m_streams[i] = st;
346 st->m_parser_split = true;
347 st->changes++;
348 }
349 else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_VIDEO)
350 {
351 CDemuxStreamVideoPVRClient* st = NULL;
352 if (stm)
353 {
354 st = dynamic_cast<CDemuxStreamVideoPVRClient*>(stm);
355 if (!st
356 || (st->codec != (AVCodecID)props.stream[i].iCodecId)
357 || (st->iWidth != props.stream[i].iWidth)
358 || (st->iHeight != props.stream[i].iHeight))
359 DisposeStream(i);
360 }
361 if (!m_streams[i])
362 {
363 st = new CDemuxStreamVideoPVRClient(this);
364 st->m_parser = av_parser_init(props.stream[i].iCodecId);
365 if(st->m_parser)
366 st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
367 }
368 st->iFpsScale = props.stream[i].iFPSScale;
369 st->iFpsRate = props.stream[i].iFPSRate;
370 st->iHeight = props.stream[i].iHeight;
371 st->iWidth = props.stream[i].iWidth;
372 st->fAspect = props.stream[i].fAspect;
373 st->stereo_mode = "mono";
374 m_streams[i] = st;
375 st->m_parser_split = true;
376 }
377 else if (props.stream[i].iCodecId == AV_CODEC_ID_DVB_TELETEXT)
378 {
379 if (stm)
380 {
381 if (stm->codec != (AVCodecID)props.stream[i].iCodecId)
382 DisposeStream(i);
383 }
384 if (!m_streams[i])
385 m_streams[i] = new CDemuxStreamTeletext();
386 }
387 else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_SUBTITLE)
388 {
389 CDemuxStreamSubtitlePVRClient* st = NULL;
390 if (stm)
391 {
392 st = dynamic_cast<CDemuxStreamSubtitlePVRClient*>(stm);
393 if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
394 DisposeStream(i);
395 }
396 if (!m_streams[i])
397 {
398 st = new CDemuxStreamSubtitlePVRClient(this);
399 }
400 if(props.stream[i].iIdentifier)
401 {
402 st->ExtraData = new uint8_t[4];
403 st->ExtraSize = 4;
404 st->ExtraData[0] = (props.stream[i].iIdentifier >> 8) & 0xff;
405 st->ExtraData[1] = (props.stream[i].iIdentifier >> 0) & 0xff;
406 st->ExtraData[2] = (props.stream[i].iIdentifier >> 24) & 0xff;
407 st->ExtraData[3] = (props.stream[i].iIdentifier >> 16) & 0xff;
408 }
409 m_streams[i] = st;
410 }
411 else
412 {
413 if (m_streams[i])
414 DisposeStream(i);
415 m_streams[i] = new CDemuxStream();
416 }
417
418 m_streams[i]->codec = (AVCodecID)props.stream[i].iCodecId;
419 m_streams[i]->iId = i;
420 m_streams[i]->iPhysicalId = props.stream[i].iPhysicalId;
421 m_streams[i]->language[0] = props.stream[i].strLanguage[0];
422 m_streams[i]->language[1] = props.stream[i].strLanguage[1];
423 m_streams[i]->language[2] = props.stream[i].strLanguage[2];
424 m_streams[i]->language[3] = props.stream[i].strLanguage[3];
425
426 CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): added/updated stream %d:%d with codec_id %d",
427 m_streams[i]->iId,
428 m_streams[i]->iPhysicalId,
429 m_streams[i]->codec);
430 }
431 // check if we need to dispose any streams no longer in props
432 for (unsigned int j = i; j < MAX_STREAMS; j++)
433 {
434 if (m_streams[j])
435 {
436 CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): disposed stream %d:%d with codec_id %d",
437 m_streams[j]->iId,
438 m_streams[j]->iPhysicalId,
439 m_streams[j]->codec);
440 DisposeStream(j);
441 }
442 }
443}
444
445int CDVDDemuxPVRClient::GetNrOfStreams()
446{
447 int i = 0;
448 while (i < MAX_STREAMS && m_streams[i]) i++;
449 return i;
450}
451
452std::string CDVDDemuxPVRClient::GetFileName()
453{
454 if(m_pInput)
455 return m_pInput->GetFileName();
456 else
457 return "";
458}
459
460void CDVDDemuxPVRClient::GetStreamCodecName(int iStreamId, std::string &strName)
461{
462 CDemuxStream *stream = GetStream(iStreamId);
463 if (stream)
464 {
465 if (stream->codec == AV_CODEC_ID_AC3)
466 strName = "ac3";
467 else if (stream->codec == AV_CODEC_ID_MP2)
468 strName = "mp2";
469 else if (stream->codec == AV_CODEC_ID_AAC)
470 strName = "aac";
471 else if (stream->codec == AV_CODEC_ID_DTS)
472 strName = "dca";
473 else if (stream->codec == AV_CODEC_ID_MPEG2VIDEO)
474 strName = "mpeg2video";
475 else if (stream->codec == AV_CODEC_ID_H264)
476 strName = "h264";
477 else if (stream->codec == AV_CODEC_ID_EAC3)
478 strName = "eac3";
479 }
480}
481
482bool CDVDDemuxPVRClient::SeekTime(int timems, bool backwards, double *startpts)
483{
484 if (m_pInput)
485 return m_pvrClient->SeekTime(timems, backwards, startpts);
486 return false;
487}
488
489void CDVDDemuxPVRClient::SetSpeed ( int speed )
490{
491 if (m_pInput)
492 m_pvrClient->SetSpeed(speed);
493}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h
new file mode 100644
index 0000000..2fc3c63
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h
@@ -0,0 +1,118 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DVDDemux.h"
23#include <map>
24#include "pvr/addons/PVRClient.h"
25
26extern "C" {
27#include "libavcodec/avcodec.h"
28#include "libavformat/avformat.h"
29}
30
31class CDVDDemuxPVRClient;
32struct PVR_STREAM_PROPERTIES;
33
34class CDemuxStreamPVRInternal
35{
36public:
37 CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent);
38 ~CDemuxStreamPVRInternal();
39
40 void DisposeParser();
41
42 CDVDDemuxPVRClient * m_parent;
43 AVCodecParserContext* m_parser;
44 AVCodecContext * m_context;
45 bool m_parser_split;
46};
47
48class CDemuxStreamVideoPVRClient
49 : public CDemuxStreamVideo
50 , public CDemuxStreamPVRInternal
51{
52public:
53 CDemuxStreamVideoPVRClient(CDVDDemuxPVRClient *parent)
54 : CDemuxStreamPVRInternal(parent)
55 {}
56 virtual void GetStreamInfo(std::string& strInfo);
57};
58
59class CDemuxStreamAudioPVRClient
60 : public CDemuxStreamAudio
61 , public CDemuxStreamPVRInternal
62{
63public:
64 CDemuxStreamAudioPVRClient(CDVDDemuxPVRClient *parent)
65 : CDemuxStreamPVRInternal(parent)
66 {}
67 virtual void GetStreamInfo(std::string& strInfo);
68};
69
70class CDemuxStreamSubtitlePVRClient
71 : public CDemuxStreamSubtitle
72 , public CDemuxStreamPVRInternal
73{
74public:
75 CDemuxStreamSubtitlePVRClient(CDVDDemuxPVRClient *parent)
76 : CDemuxStreamPVRInternal(parent)
77 {}
78 virtual void GetStreamInfo(std::string& strInfo);
79};
80
81
82class CDVDDemuxPVRClient : public CDVDDemux
83{
84 friend class CDemuxStreamPVRInternal;
85
86public:
87
88 CDVDDemuxPVRClient();
89 ~CDVDDemuxPVRClient();
90
91 bool Open(CDVDInputStream* pInput);
92 void Dispose();
93 void Reset();
94 void Abort();
95 void Flush();
96 DemuxPacket* Read();
97 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
98 void SetSpeed(int iSpeed);
99 int GetStreamLength() { return 0; }
100 CDemuxStream* GetStream(int iStreamId);
101 int GetNrOfStreams();
102 std::string GetFileName();
103 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
104
105protected:
106 CDVDInputStream* m_pInput;
107#ifndef MAX_STREAMS
108 #define MAX_STREAMS 100
109#endif
110 CDemuxStream* m_streams[MAX_STREAMS]; // maximum number of streams that ffmpeg can handle
111 std::shared_ptr<PVR::CPVRClient> m_pvrClient;
112
113private:
114 void RequestStreams();
115 void ParsePacket(DemuxPacket* pPacket);
116 void DisposeStream(int iStreamId);
117};
118
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
new file mode 100644
index 0000000..d64fbb3
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
@@ -0,0 +1,36 @@
1#pragma once
2
3/*
4 * Copyright (C) 2012-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#define DMX_SPECIALID_STREAMINFO -10
24#define DMX_SPECIALID_STREAMCHANGE -11
25
26 typedef struct DemuxPacket
27{
28 unsigned char* pData; // data
29 int iSize; // data size
30 int iStreamId; // integer representing the stream index
31 int iGroupId; // the group this data belongs to, used to group data from different streams together
32
33 double pts; // pts in DVD_TIME_BASE
34 double dts; // dts in DVD_TIME_BASE
35 double duration; // duration in DVD_TIME_BASE if available
36} DemuxPacket;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp
new file mode 100644
index 0000000..a69342a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp
@@ -0,0 +1,199 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDCodecs/DVDCodecs.h"
22#include "DVDInputStreams/DVDInputStreamHttp.h"
23#include "DVDDemuxShoutcast.h"
24#include "DVDDemuxUtils.h"
25#include "DVDClock.h" // for DVD_TIME_BASE
26#include "../../../utils/HttpHeader.h"
27
28#define ICY_NOTICE1 "icy-notice1" // string
29#define ICY_NOTICE2 "icy-notice2" // string
30#define ICY_NAME "icy-name" // string
31#define ICY_GENRE "icy-genre" // string
32#define ICY_URL "icy-url" // string
33#define ICY_PUBLIC "icy-pub" // int (1 / 0)
34#define ICY_BITRATE "icy-br" // int (bitrate = val * 1000 ?)
35#define ICY_METAINTERVAL "icy-metaint" // int
36
37#define CONTENT_TYPE_MP3 "audio/mpeg"
38#define CONTENT_TYPE_AAC "audio/aac"
39#define CONTENT_TYPE_AACPLUS "audio/aacp"
40
41// class CDemuxStreamVideoFFmpeg
42void CDemuxStreamAudioShoutcast::GetStreamInfo(std::string& strInfo)
43{
44 strInfo = "Shoutcast";
45}
46
47CDVDDemuxShoutcast::CDVDDemuxShoutcast() : CDVDDemux()
48{
49 m_pInput = NULL;
50 m_pDemuxStream = NULL;
51 m_iMetaStreamInterval = 0;
52}
53
54CDVDDemuxShoutcast::~CDVDDemuxShoutcast()
55{
56 Dispose();
57}
58
59bool CDVDDemuxShoutcast::Open(CDVDInputStream* pInput)
60{
61 Dispose();
62
63 m_pInput = pInput;
64
65 // the input stream should be a http stream
66 if (!pInput->IsStreamType(DVDSTREAM_TYPE_HTTP)) return false;
67 CDVDInputStreamHttp* pInputStreamHttp = (CDVDInputStreamHttp*)pInput;
68
69 CHttpHeader* pHeader = pInputStreamHttp->GetHttpHeader();
70
71 std::string strMetaInt = pHeader->GetValue(ICY_METAINTERVAL);
72 std::string strMimeType = pHeader->GetMimeType();
73
74 // create new demuxer stream
75 m_pDemuxStream = new CDemuxStreamAudioShoutcast();
76 m_pDemuxStream->iId = 0;
77 m_pDemuxStream->iPhysicalId = 0;
78 m_pDemuxStream->iDuration = 0;
79 m_pDemuxStream->iChannels = 2;
80 m_pDemuxStream->iSampleRate = 0;
81
82 // set meta interval
83 m_iMetaStreamInterval = atoi(strMetaInt.c_str());
84
85 if (stricmp(strMimeType.c_str(), CONTENT_TYPE_AAC) == 0 ||
86 stricmp(strMimeType.c_str(), CONTENT_TYPE_AACPLUS) == 0)
87 {
88 // need an aac decoder first
89 m_pDemuxStream->codec = AV_CODEC_ID_AAC;
90 }
91 else // (stricmp(strMimeType, CONTENT_TYPE_MP3) == 0)
92 {
93 // default to mp3
94 m_pDemuxStream->codec = AV_CODEC_ID_MP3;
95 }
96
97 return true;
98}
99
100void CDVDDemuxShoutcast::Dispose()
101{
102 if (m_pDemuxStream) delete m_pDemuxStream;
103 m_pDemuxStream = NULL;
104
105 m_pInput = NULL;
106}
107
108void CDVDDemuxShoutcast::Reset()
109{
110 CDVDInputStream* pInputStream = m_pInput;
111 Dispose();
112 Open(pInputStream);
113}
114
115void CDVDDemuxShoutcast::Flush()
116{
117}
118
119DemuxPacket* CDVDDemuxShoutcast::Read()
120{
121 // XXX
122 // if meta interval is greater than FileCurl's max read size (currently 64k)
123 // it will simply fail becuse the meta-interval will get incorrect
124
125 int iDataToRead = SHOUTCAST_BUFFER_SIZE;
126 if (m_iMetaStreamInterval > 0) iDataToRead = m_iMetaStreamInterval;
127
128 DemuxPacket* pPacket;
129 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(iDataToRead);
130 if (pPacket)
131 {
132 pPacket->dts = DVD_NOPTS_VALUE;
133 pPacket->pts = DVD_NOPTS_VALUE;
134 pPacket->iStreamId = 0;
135
136 // read the data
137 int iRead = m_pInput->Read(pPacket->pData, iDataToRead);
138
139 pPacket->iSize = iRead;
140
141 if (iRead <= 0)
142 {
143 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
144 pPacket = NULL;
145 }
146 }
147
148 if (m_iMetaStreamInterval > 0)
149 {
150 // we already have read m_iMetaStreamInterval bytes of streaming data
151 // metadata follows
152 uint8_t l;
153 int iRead = m_pInput->Read(&l, 1);
154 if (iRead > 0)
155 {
156 int iMetaLength = l * 16;
157
158 if (iMetaLength > 0)
159 {
160 // iMetaLength cannot be larger then 16 * 255
161 uint8_t buffer[16 * 255];
162
163 // skip meta data for now
164 m_pInput->Read(buffer, iMetaLength);
165 }
166 }
167 }
168
169 return pPacket;
170}
171
172bool CDVDDemuxShoutcast::SeekTime(int time, bool backwords, double* startpts)
173{
174 return false;
175}
176
177int CDVDDemuxShoutcast::GetStreamLength()
178{
179 return 0;
180}
181
182CDemuxStream* CDVDDemuxShoutcast::GetStream(int iStreamId)
183{
184 return m_pDemuxStream;
185}
186
187int CDVDDemuxShoutcast::GetNrOfStreams()
188{
189 return 1;
190}
191
192std::string CDVDDemuxShoutcast::GetFileName()
193{
194 if(m_pInput)
195 return m_pInput->GetFileName();
196 else
197 return "";
198}
199
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h
new file mode 100644
index 0000000..a802167
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h
@@ -0,0 +1,60 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemux.h"
24
25class CDemuxStreamAudioShoutcast : public CDemuxStreamAudio
26{
27public:
28 virtual void GetStreamInfo(std::string& strInfo);
29};
30
31#define SHOUTCAST_BUFFER_SIZE 1024 * 32
32
33class CDVDDemuxShoutcast : public CDVDDemux
34{
35public:
36 CDVDDemuxShoutcast();
37 virtual ~CDVDDemuxShoutcast();
38
39 bool Open(CDVDInputStream* pInput);
40 void Dispose();
41 void Reset();
42 void Flush();
43 void Abort(){}
44 void SetSpeed(int iSpeed){};
45 virtual std::string GetFileName();
46
47 DemuxPacket* Read();
48
49 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
50 int GetStreamLength();
51 CDemuxStream* GetStream(int iStreamId);
52 int GetNrOfStreams();
53
54protected:
55
56 CDemuxStreamAudioShoutcast* m_pDemuxStream;
57
58 int m_iMetaStreamInterval;
59 CDVDInputStream* m_pInput;
60};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp
new file mode 100644
index 0000000..ab298b2
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp
@@ -0,0 +1,89 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
22 #include "config.h"
23#endif
24#include "DVDDemuxUtils.h"
25#include "DVDClock.h"
26#include "utils/log.h"
27
28extern "C" {
29#include "libavcodec/avcodec.h"
30}
31
32void CDVDDemuxUtils::FreeDemuxPacket(DemuxPacket* pPacket)
33{
34 if (pPacket)
35 {
36 try {
37 if (pPacket->pData) _aligned_free(pPacket->pData);
38 delete pPacket;
39 }
40 catch(...) {
41 CLog::Log(LOGERROR, "%s - Exception thrown while freeing packet", __FUNCTION__);
42 }
43 }
44}
45
46DemuxPacket* CDVDDemuxUtils::AllocateDemuxPacket(int iDataSize)
47{
48 DemuxPacket* pPacket = new DemuxPacket;
49 if (!pPacket) return NULL;
50
51 try
52 {
53 memset(pPacket, 0, sizeof(DemuxPacket));
54
55 if (iDataSize > 0)
56 {
57 // need to allocate a few bytes more.
58 // From avcodec.h (ffmpeg)
59 /**
60 * Required number of additionally allocated bytes at the end of the input bitstream for decoding.
61 * this is mainly needed because some optimized bitstream readers read
62 * 32 or 64 bit at once and could read over the end<br>
63 * Note, if the first 23 bits of the additional bytes are not 0 then damaged
64 * MPEG bitstreams could cause overread and segfault
65 */
66 pPacket->pData =(uint8_t*)_aligned_malloc(iDataSize + FF_INPUT_BUFFER_PADDING_SIZE, 16);
67 if (!pPacket->pData)
68 {
69 FreeDemuxPacket(pPacket);
70 return NULL;
71 }
72
73 // reset the last 8 bytes to 0;
74 memset(pPacket->pData + iDataSize, 0, FF_INPUT_BUFFER_PADDING_SIZE);
75 }
76
77 // setup defaults
78 pPacket->dts = DVD_NOPTS_VALUE;
79 pPacket->pts = DVD_NOPTS_VALUE;
80 pPacket->iStreamId = -1;
81 }
82 catch(...)
83 {
84 CLog::Log(LOGERROR, "%s - Exception thrown", __FUNCTION__);
85 FreeDemuxPacket(pPacket);
86 pPacket = NULL;
87 }
88 return pPacket;
89}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h
new file mode 100644
index 0000000..2c12df3
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h
@@ -0,0 +1,31 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemuxPacket.h"
24
25class CDVDDemuxUtils
26{
27public:
28 static void FreeDemuxPacket(DemuxPacket* pPacket);
29 static DemuxPacket* AllocateDemuxPacket(int iDataSize = 0);
30};
31
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp
new file mode 100644
index 0000000..9625a19
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp
@@ -0,0 +1,247 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "DVDDemuxVobsub.h"
22#include "DVDInputStreams/DVDFactoryInputStream.h"
23#include "DVDInputStreams/DVDInputStream.h"
24#include "DVDStreamInfo.h"
25#include "DVDCodecs/DVDCodecs.h"
26#include "DVDDemuxers/DVDDemuxFFmpeg.h"
27#include "DVDDemuxers/DVDDemuxUtils.h"
28#include "DVDClock.h"
29#include "DVDSubtitles/DVDSubtitleStream.h"
30
31#include <string.h>
32
33using namespace std;
34
35CDVDDemuxVobsub::CDVDDemuxVobsub()
36{
37}
38
39CDVDDemuxVobsub::~CDVDDemuxVobsub()
40{
41 for(unsigned i=0;i<m_Streams.size();i++)
42 {
43 delete m_Streams[i];
44 }
45 m_Streams.clear();
46}
47
48bool CDVDDemuxVobsub::Open(const string& filename, const string& subfilename)
49{
50 m_Filename = filename;
51
52 unique_ptr<CDVDSubtitleStream> pStream(new CDVDSubtitleStream());
53 if(!pStream->Open(filename))
54 return false;
55
56 string vobsub = subfilename;
57 if ( vobsub == "")
58 {
59 vobsub = filename;
60 vobsub.erase(vobsub.rfind('.'), vobsub.size());
61 vobsub += ".sub";
62 }
63
64 m_Input.reset(CDVDFactoryInputStream::CreateInputStream(NULL, vobsub, ""));
65 if(!m_Input.get() || !m_Input->Open(vobsub.c_str(), "video/x-vobsub"))
66 return false;
67
68 m_Demuxer.reset(new CDVDDemuxFFmpeg());
69 if(!m_Demuxer->Open(m_Input.get()))
70 return false;
71
72 CDVDStreamInfo hints;
73 CDVDCodecOptions options;
74 hints.codec = AV_CODEC_ID_DVD_SUBTITLE;
75
76 char line[2048];
77 DECLARE_UNUSED(bool,res)
78
79 SState state;
80 state.delay = 0;
81 state.id = -1;
82
83 while( pStream->ReadLine(line, sizeof(line)) )
84 {
85 if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#')
86 continue;
87 else if (strncmp("langidx:", line, 8) == 0)
88 res = ParseLangIdx(state, line + 8);
89 else if (strncmp("delay:", line, 6) == 0)
90 res = ParseDelay(state, line + 6);
91 else if (strncmp("id:", line, 3) == 0)
92 res = ParseId(state, line + 3);
93 else if (strncmp("timestamp:", line, 10) == 0)
94 res = ParseTimestamp(state, line + 10);
95 else if (strncmp("palette:", line, 8) == 0
96 || strncmp("size:", line, 5) == 0
97 || strncmp("org:", line, 4) == 0
98 || strncmp("custom colors:", line, 14) == 0
99 || strncmp("scale:", line, 6) == 0
100 || strncmp("alpha:", line, 6) == 0
101 || strncmp("fadein/out:", line, 11) == 0
102 || strncmp("forced subs:", line, 12) == 0)
103 res = ParseExtra(state, line);
104 else
105 continue;
106 }
107
108 struct sorter s;
109 sort(m_Timestamps.begin(), m_Timestamps.end(), s);
110 m_Timestamp = m_Timestamps.begin();
111
112 for(unsigned i=0;i<m_Streams.size();i++)
113 {
114 m_Streams[i]->ExtraSize = state.extra.length()+1;
115 m_Streams[i]->ExtraData = new uint8_t[m_Streams[i]->ExtraSize];
116 strcpy((char*)m_Streams[i]->ExtraData, state.extra.c_str());
117 }
118
119 return true;
120}
121
122void CDVDDemuxVobsub::Reset()
123{
124 Flush();
125}
126
127void CDVDDemuxVobsub::Flush()
128{
129 m_Demuxer->Flush();
130}
131
132bool CDVDDemuxVobsub::SeekTime(int time, bool backwords, double* startpts)
133{
134 double pts = DVD_MSEC_TO_TIME(time);
135 m_Timestamp = m_Timestamps.begin();
136 for(;m_Timestamp != m_Timestamps.end();++m_Timestamp)
137 {
138 if(m_Timestamp->pts > pts)
139 break;
140 }
141 for(unsigned i=0;i<m_Streams.size() && m_Timestamps.begin() != m_Timestamp;i++)
142 {
143 --m_Timestamp;
144 }
145 return true;
146}
147
148DemuxPacket* CDVDDemuxVobsub::Read()
149{
150 vector<STimestamp>::iterator current;
151 do {
152 if(m_Timestamp == m_Timestamps.end())
153 return NULL;
154
155 current = m_Timestamp++;
156 } while(m_Streams[current->id]->m_discard == AVDISCARD_ALL);
157
158 if(!m_Demuxer->SeekByte(current->pos))
159 return NULL;
160
161 DemuxPacket *packet = m_Demuxer->Read();
162 if(!packet)
163 return NULL;
164
165 packet->iStreamId = current->id;
166 packet->pts = current->pts;
167 packet->dts = current->pts;
168
169 return packet;
170}
171
172bool CDVDDemuxVobsub::ParseLangIdx(SState& state, char* line)
173{
174 return true;
175}
176
177bool CDVDDemuxVobsub::ParseDelay(SState& state, char* line)
178{
179 int h,m,s,ms;
180 bool negative = false;
181
182 while(*line == ' ') line++;
183 if(*line == '-')
184 {
185 line++;
186 negative = true;
187 }
188 if(sscanf(line, "%d:%d:%d:%d", &h, &m, &s, &ms) != 4)
189 return false;
190 state.delay = h*3600.0 + m*60.0 + s + ms*0.001;
191 if(negative)
192 state.delay *= -1;
193 return true;
194}
195
196bool CDVDDemuxVobsub::ParseId(SState& state, char* line)
197{
198 unique_ptr<CStream> stream(new CStream(this));
199
200 while(*line == ' ') line++;
201 strncpy(stream->language, line, 2);
202 stream->language[2] = '\0';
203 line+=2;
204
205 while(*line == ' ' || *line == ',') line++;
206 if (strncmp("index:", line, 6) == 0)
207 {
208 line+=6;
209 while(*line == ' ') line++;
210 stream->iPhysicalId = atoi(line);
211 }
212 else
213 stream->iPhysicalId = -1;
214
215 stream->codec = AV_CODEC_ID_DVD_SUBTITLE;
216 stream->iId = m_Streams.size();
217 stream->source = STREAM_SOURCE_DEMUX_SUB;
218
219 state.id = stream->iId;
220 m_Streams.push_back(stream.release());
221 return true;
222}
223
224bool CDVDDemuxVobsub::ParseExtra(SState& state, char* line)
225{
226 state.extra += line;
227 state.extra += '\n';
228 return true;
229}
230
231bool CDVDDemuxVobsub::ParseTimestamp(SState& state, char* line)
232{
233 if(state.id < 0)
234 return false;
235
236 int h,m,s,ms;
237 STimestamp timestamp;
238
239 while(*line == ' ') line++;
240 if(sscanf(line, "%d:%d:%d:%d, filepos:%" PRIx64, &h, &m, &s, &ms, &timestamp.pos) != 5)
241 return false;
242
243 timestamp.id = state.id;
244 timestamp.pts = DVD_SEC_TO_TIME(state.delay + h*3600.0 + m*60.0 + s + ms*0.001);
245 m_Timestamps.push_back(timestamp);
246 return true;
247}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h
new file mode 100644
index 0000000..0c75c4a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h
@@ -0,0 +1,99 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemux.h"
24
25#include <memory>
26#include <vector>
27
28class CDVDOverlayCodecFFmpeg;
29class CDVDInputStream;
30class CDVDDemuxFFmpeg;
31
32class CDVDDemuxVobsub : public CDVDDemux
33{
34public:
35 CDVDDemuxVobsub();
36 virtual ~CDVDDemuxVobsub();
37
38 virtual bool Open(const std::string& filename, const std::string& subfilename = "");
39 virtual void Reset();
40 virtual void Abort() {};
41 virtual void Flush();
42 virtual DemuxPacket* Read();
43 virtual bool SeekTime(int time, bool backwords, double* startpts = NULL);
44 virtual void SetSpeed(int speed) {}
45 virtual CDemuxStream* GetStream(int index) { return m_Streams[index]; }
46 virtual int GetNrOfStreams() { return m_Streams.size(); }
47 virtual int GetStreamLength() { return 0; }
48 virtual std::string GetFileName() { return m_Filename; }
49
50private:
51 class CStream
52 : public CDemuxStreamSubtitle
53 {
54 public:
55 CStream(CDVDDemuxVobsub* parent)
56 : m_discard(AVDISCARD_NONE), m_parent(parent)
57 {}
58 virtual void SetDiscard(AVDiscard discard) { m_discard = discard; }
59 virtual AVDiscard GetDiscard() { return m_discard; }
60
61 AVDiscard m_discard;
62 CDVDDemuxVobsub* m_parent;
63 };
64
65 typedef struct STimestamp
66 {
67 int64_t pos;
68 double pts;
69 int id;
70 } STimestamp;
71
72 std::string m_Filename;
73 std::unique_ptr<CDVDInputStream> m_Input;
74 std::unique_ptr<CDVDDemuxFFmpeg> m_Demuxer;
75 std::vector<STimestamp> m_Timestamps;
76 std::vector<STimestamp>::iterator m_Timestamp;
77 std::vector<CStream*> m_Streams;
78
79 typedef struct SState
80 {
81 int id;
82 double delay;
83 std::string extra;
84 } SState;
85
86 struct sorter
87 {
88 bool operator()(const STimestamp &p1, const STimestamp &p2)
89 {
90 return p1.pts < p2.pts || (p1.pts == p2.pts && p1.id < p2.id);
91 }
92 };
93
94 bool ParseLangIdx(SState& state, char* line);
95 bool ParseDelay(SState& state, char* line);
96 bool ParseId(SState& state, char* line);
97 bool ParseExtra(SState& state, char* line);
98 bool ParseTimestamp(SState& state, char* line);
99};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
new file mode 100644
index 0000000..f909c32
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
@@ -0,0 +1,153 @@
1/*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include "system.h"
22#include "DVDFactoryDemuxer.h"
23
24#include "DVDInputStreams/DVDInputStream.h"
25#include "DVDInputStreams/DVDInputStreamHttp.h"
26#include "DVDInputStreams/DVDInputStreamPVRManager.h"
27
28#include "DVDDemuxFFmpeg.h"
29#include "DVDDemuxShoutcast.h"
30#ifdef HAS_FILESYSTEM_HTSP
31#include "DVDDemuxHTSP.h"
32#endif
33#include "DVDDemuxBXA.h"
34#include "DVDDemuxCDDA.h"
35#include "DVDDemuxPVRClient.h"
36#include "pvr/PVRManager.h"
37#include "pvr/addons/PVRClients.h"
38
39using namespace std;
40using namespace PVR;
41
42CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream, bool fileinfo)
43{
44 if (!pInputStream)
45 return NULL;
46
47 // Try to open the AirTunes demuxer
48 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 )
49 {
50 // audio/x-xbmc-pcm this is the used codec for AirTunes
51 // (apples audio only streaming)
52 unique_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA());
53 if(demuxer->Open(pInputStream))
54 return demuxer.release();
55 else
56 return NULL;
57 }
58
59 // Try to open CDDA demuxer
60 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("application/octet-stream") == 0)
61 {
62 std::string filename = pInputStream->GetFileName();
63 if (filename.substr(0, 7) == "cdda://")
64 {
65 CLog::Log(LOGDEBUG, "DVDFactoryDemuxer: Stream is probably CD audio. Creating CDDA demuxer.");
66
67 unique_ptr<CDVDDemuxCDDA> demuxer(new CDVDDemuxCDDA());
68 if (demuxer->Open(pInputStream))
69 {
70 return demuxer.release();
71 }
72 }
73 }
74
75 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP))
76 {
77 CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream;
78 CHttpHeader *header = pHttpStream->GetHttpHeader();
79
80 /* check so we got the meta information as requested in our http header */
81 if( header->GetValue("icy-metaint").length() > 0 )
82 {
83 unique_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast());
84 if(demuxer->Open(pInputStream))
85 return demuxer.release();
86 else
87 return NULL;
88 }
89 }
90
91#ifdef HAS_FILESYSTEM_HTSP
92 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP))
93 {
94 unique_ptr<CDVDDemuxHTSP> demuxer(new CDVDDemuxHTSP());
95 if(demuxer->Open(pInputStream))
96 return demuxer.release();
97 else
98 return NULL;
99 }
100#endif
101
102 bool streaminfo = true; /* Look for streams before playback */
103 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
104 {
105 CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream;
106 CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream();
107
108 /* Don't parse the streaminfo for some cases of streams to reduce the channel switch time */
109 bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
110 streaminfo = !useFastswitch;
111
112 if(pOtherStream)
113 {
114 /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */
115 if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
116 {
117 unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg());
118 if(demuxer->Open(pOtherStream, streaminfo))
119 return demuxer.release();
120 else
121 return NULL;
122 }
123 }
124
125 /* Use PVR demuxer only for live streams */
126 if (URIUtils::IsPVRChannel(pInputStream->GetFileName()))
127 {
128 std::shared_ptr<CPVRClient> client;
129 if (g_PVRClients->GetPlayingClient(client) &&
130 client->HandlesDemuxing())
131 {
132 unique_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient());
133 if(demuxer->Open(pInputStream))
134 return demuxer.release();
135 else
136 return NULL;
137 }
138 }
139 }
140
141 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
142 {
143 bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
144 streaminfo = !useFastswitch;
145 }
146
147 unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg());
148 if(demuxer->Open(pInputStream, streaminfo, fileinfo))
149 return demuxer.release();
150 else
151 return NULL;
152}
153
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h
new file mode 100644
index 0000000..8281d28
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h
@@ -0,0 +1,30 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23class CDVDDemux;
24class CDVDInputStream;
25
26class CDVDFactoryDemuxer
27{
28public:
29 static CDVDDemux* CreateDemuxer(CDVDInputStream* pInputStream, bool fileinfo = false);
30};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in b/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
new file mode 100644
index 0000000..98493fe
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
@@ -0,0 +1,19 @@
1INCLUDES+=-I@abs_top_srcdir@/xbmc/cores/dvdplayer
2
3SRCS = DVDDemux.cpp
4SRCS += DVDDemuxBXA.cpp
5SRCS += DVDDemuxCDDA.cpp
6SRCS += DVDDemuxFFmpeg.cpp
7SRCS += DVDDemuxHTSP.cpp
8SRCS += DVDDemuxPVRClient.cpp
9SRCS += DVDDemuxShoutcast.cpp
10SRCS += DVDDemuxUtils.cpp
11SRCS += DVDDemuxVobsub.cpp
12SRCS += DVDDemuxCC.cpp
13SRCS += DVDFactoryDemuxer.cpp
14
15LIB = DVDDemuxers.a
16
17include @abs_top_srcdir@/Makefile.include
18-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
19