diff options
| author | manuel <manuel@mausz.at> | 2015-03-03 16:53:59 +0100 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2015-03-03 16:53:59 +0100 |
| commit | ffca21f2743a7b367fa212799c6e2fea6190dd5d (patch) | |
| tree | 0608ea3a29cf644ec9ab204e2b4bb9bfaae1c381 | |
| download | kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.gz kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.tar.bz2 kodi-pvr-build-ffca21f2743a7b367fa212799c6e2fea6190dd5d.zip | |
initial commit for kodi master
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 | |||
| 35 | static 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 | */ | ||
| 41 | static 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 | |||
| 55 | static 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( ) */ | ||
| 70 | static char last_name[MAX_PATH]; | ||
| 71 | |||
| 72 | static 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 | |||
| 91 | void *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 | |||
| 159 | int 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 | |||
| 181 | void *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 | |||
| 223 | char *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 | |||
| 41 | void *dlopen ( const char *file, int mode ); | ||
| 42 | int dlclose( void *handle ); | ||
| 43 | void *dlsym ( void *handle, const char *name ); | ||
| 44 | char *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 | ||
| 32 | typedef 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 | |||
| 86 | namespace 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 | |||
| 37 | class CHelper_libXBMC_codec | ||
| 38 | { | ||
| 39 | public: | ||
| 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 | |||
| 110 | protected: | ||
| 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 | |||
| 115 | private: | ||
| 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 | |||
| 29 | typedef 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 | |||
| 48 | class CAddonGUIWindow; | ||
| 49 | class CAddonGUISpinControl; | ||
| 50 | class CAddonGUIRadioButton; | ||
| 51 | class CAddonGUIProgressControl; | ||
| 52 | class CAddonListItem; | ||
| 53 | class CAddonGUIRenderingControl; | ||
| 54 | class CAddonGUISliderControl; | ||
| 55 | class CAddonGUISettingsSliderControl; | ||
| 56 | |||
| 57 | class CHelper_libXBMC_gui | ||
| 58 | { | ||
| 59 | public: | ||
| 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 | |||
| 555 | protected: | ||
| 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 | |||
| 606 | private: | ||
| 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 | |||
| 616 | class CAddonGUISpinControl | ||
| 617 | { | ||
| 618 | public: | ||
| 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 | |||
| 629 | private: | ||
| 630 | CAddonGUIWindow *m_Window; | ||
| 631 | int m_ControlId; | ||
| 632 | GUIHANDLE m_SpinHandle; | ||
| 633 | void *m_Handle; | ||
| 634 | void *m_cb; | ||
| 635 | }; | ||
| 636 | |||
| 637 | class CAddonGUIRadioButton | ||
| 638 | { | ||
| 639 | public: | ||
| 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 | |||
| 648 | private: | ||
| 649 | CAddonGUIWindow *m_Window; | ||
| 650 | int m_ControlId; | ||
| 651 | GUIHANDLE m_ButtonHandle; | ||
| 652 | void *m_Handle; | ||
| 653 | void *m_cb; | ||
| 654 | }; | ||
| 655 | |||
| 656 | class CAddonGUIProgressControl | ||
| 657 | { | ||
| 658 | public: | ||
| 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 | |||
| 668 | private: | ||
| 669 | CAddonGUIWindow *m_Window; | ||
| 670 | int m_ControlId; | ||
| 671 | GUIHANDLE m_ProgressHandle; | ||
| 672 | void *m_Handle; | ||
| 673 | void *m_cb; | ||
| 674 | }; | ||
| 675 | |||
| 676 | class CAddonGUISliderControl | ||
| 677 | { | ||
| 678 | public: | ||
| 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 | |||
| 698 | private: | ||
| 699 | CAddonGUIWindow *m_Window; | ||
| 700 | int m_ControlId; | ||
| 701 | GUIHANDLE m_SliderHandle; | ||
| 702 | void *m_Handle; | ||
| 703 | void *m_cb; | ||
| 704 | }; | ||
| 705 | |||
| 706 | class CAddonGUISettingsSliderControl | ||
| 707 | { | ||
| 708 | public: | ||
| 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 | |||
| 729 | private: | ||
| 730 | CAddonGUIWindow *m_Window; | ||
| 731 | int m_ControlId; | ||
| 732 | GUIHANDLE m_SettingsSliderHandle; | ||
| 733 | void *m_Handle; | ||
| 734 | void *m_cb; | ||
| 735 | }; | ||
| 736 | |||
| 737 | class CAddonListItem | ||
| 738 | { | ||
| 739 | friend class CAddonGUIWindow; | ||
| 740 | |||
| 741 | public: | ||
| 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(); | ||
| 758 | protected: | ||
| 759 | GUIHANDLE m_ListItemHandle; | ||
| 760 | void *m_Handle; | ||
| 761 | void *m_cb; | ||
| 762 | }; | ||
| 763 | |||
| 764 | class CAddonGUIWindow | ||
| 765 | { | ||
| 766 | friend class CAddonGUISpinControl; | ||
| 767 | friend class CAddonGUIRadioButton; | ||
| 768 | friend class CAddonGUIProgressControl; | ||
| 769 | friend class CAddonGUIRenderingControl; | ||
| 770 | friend class CAddonGUISliderControl; | ||
| 771 | friend class CAddonGUISettingsSliderControl; | ||
| 772 | |||
| 773 | public: | ||
| 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 | |||
| 815 | protected: | ||
| 816 | GUIHANDLE m_WindowHandle; | ||
| 817 | void *m_Handle; | ||
| 818 | void *m_cb; | ||
| 819 | }; | ||
| 820 | |||
| 821 | class CAddonGUIRenderingControl | ||
| 822 | { | ||
| 823 | public: | ||
| 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 | |||
| 839 | private: | ||
| 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 | |||
| 40 | class CHelper_libXBMC_pvr | ||
| 41 | { | ||
| 42 | public: | ||
| 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 | |||
| 303 | protected: | ||
| 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 | |||
| 324 | private: | ||
| 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 @@ | |||
| 1 | project(kodi-addons) | ||
| 2 | |||
| 3 | cmake_minimum_required(VERSION 2.8) | ||
| 4 | |||
| 5 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) | ||
| 6 | |||
| 7 | if(NOT CMAKE_BUILD_TYPE) | ||
| 8 | set(CMAKE_BUILD_TYPE Release) | ||
| 9 | endif() | ||
| 10 | |||
| 11 | if(NOT CORE_SYSTEM_NAME) | ||
| 12 | string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME) | ||
| 13 | endif() | ||
| 14 | |||
| 15 | include(ExternalProject) | ||
| 16 | |||
| 17 | ### setup all the necessary paths | ||
| 18 | if(NOT APP_ROOT AND NOT XBMCROOT) | ||
| 19 | set(APP_ROOT ${PROJECT_SOURCE_DIR}/../../..) | ||
| 20 | elseif(NOT APP_ROOT) | ||
| 21 | file(TO_CMAKE_PATH "${XBMCROOT}" APP_ROOT) | ||
| 22 | else() | ||
| 23 | file(TO_CMAKE_PATH "${APP_ROOT}" APP_ROOT) | ||
| 24 | endif() | ||
| 25 | get_filename_component(APP_ROOT "${APP_ROOT}" ABSOLUTE) | ||
| 26 | |||
| 27 | if(NOT BUILD_DIR) | ||
| 28 | set(BUILD_DIR "${CMAKE_BINARY_DIR}/build") | ||
| 29 | else() | ||
| 30 | file(TO_CMAKE_PATH "${BUILD_DIR}" BUILD_DIR) | ||
| 31 | endif() | ||
| 32 | get_filename_component(BUILD_DIR "${BUILD_DIR}" ABSOLUTE) | ||
| 33 | |||
| 34 | if(NOT DEPENDS_PATH) | ||
| 35 | set(DEPENDS_PATH "${BUILD_DIR}/depends") | ||
| 36 | else() | ||
| 37 | file(TO_CMAKE_PATH "${DEPENDS_PATH}" DEPENDS_PATH) | ||
| 38 | endif() | ||
| 39 | get_filename_component(DEPENDS_PATH "${DEPENDS_PATH}" ABSOLUTE) | ||
| 40 | |||
| 41 | if(NOT PLATFORM_DIR) | ||
| 42 | set(PLATFORM_DIR ${APP_ROOT}/project/cmake/platform/${CORE_SYSTEM_NAME}) | ||
| 43 | file(TO_CMAKE_PATH "${PLATFORM_DIR}" PLATFORM_DIR) | ||
| 44 | endif() | ||
| 45 | |||
| 46 | # make sure CMAKE_PREFIX_PATH is set | ||
| 47 | if(NOT CMAKE_PREFIX_PATH) | ||
| 48 | set(CMAKE_PREFIX_PATH "${DEPENDS_PATH}") | ||
| 49 | else() | ||
| 50 | file(TO_CMAKE_PATH "${CMAKE_PREFIX_PATH}" CMAKE_PREFIX_PATH) | ||
| 51 | list(APPEND CMAKE_PREFIX_PATH "${DEPENDS_PATH}") | ||
| 52 | endif() | ||
| 53 | |||
| 54 | # check for autoconf stuff to pass on | ||
| 55 | if(AUTOCONF_FILES) | ||
| 56 | separate_arguments(AUTOCONF_FILES) | ||
| 57 | set(CROSS_AUTOCONF "yes") | ||
| 58 | endif() | ||
| 59 | |||
| 60 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT OR NOT CMAKE_INSTALL_PREFIX) | ||
| 61 | set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/output/addons") | ||
| 62 | endif() | ||
| 63 | list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}) | ||
| 64 | |||
| 65 | set(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 | |||
| 76 | if(PACKAGE_ZIP) | ||
| 77 | # needed for project installing | ||
| 78 | list(APPEND BUILD_ARGS -DPACKAGE_ZIP=1) | ||
| 79 | MESSAGE("package zip specified") | ||
| 80 | endif() | ||
| 81 | |||
| 82 | if(CMAKE_TOOLCHAIN_FILE) | ||
| 83 | list(APPEND BUILD_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) | ||
| 84 | MESSAGE("toolchain specified") | ||
| 85 | MESSAGE(${BUILD_ARGS}) | ||
| 86 | endif() | ||
| 87 | |||
| 88 | if(NOT ADDONS_TO_BUILD) | ||
| 89 | set(ADDONS_TO_BUILD "all") | ||
| 90 | else() | ||
| 91 | message(STATUS "Building following addons: ${ADDONS_TO_BUILD}") | ||
| 92 | separate_arguments(ADDONS_TO_BUILD) | ||
| 93 | endif() | ||
| 94 | |||
| 95 | if(NOT KODI_LIB_DIR) | ||
| 96 | set(KODI_LIB_DIR "${DEPENDS_PATH}/lib/kodi") | ||
| 97 | else() | ||
| 98 | file(TO_CMAKE_PATH "${KODI_LIB_DIR}" KODI_LIB_DIR) | ||
| 99 | endif() | ||
| 100 | |||
| 101 | # check for platform specific stuff | ||
| 102 | if(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() | ||
| 108 | endif() | ||
| 109 | |||
| 110 | # include check_target_platform() function | ||
| 111 | include(${APP_ROOT}/project/cmake/scripts/common/check_target_platform.cmake) | ||
| 112 | |||
| 113 | # check install permissions | ||
| 114 | set(ADDON_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}) | ||
| 115 | check_install_permissions(${CMAKE_INSTALL_PREFIX} can_write) | ||
| 116 | if(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}") | ||
| 120 | endif() | ||
| 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 | ||
| 124 | file(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 | ||
| 127 | list(APPEND CMAKE_MODULE_PATH ${KODI_LIB_DIR}) | ||
| 128 | |||
| 129 | # include prepare-env.cmake which contains the logic to install the addon header bindings etc | ||
| 130 | include(prepare-env) | ||
| 131 | |||
| 132 | ### add the depends subdirectory for any general dependencies | ||
| 133 | add_subdirectory(depends) | ||
| 134 | |||
| 135 | ### get and build all the binary addons | ||
| 136 | # look for all the addons to be built | ||
| 137 | file(GLOB_RECURSE addons ${PROJECT_SOURCE_DIR}/addons/*.txt) | ||
| 138 | foreach(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() | ||
| 211 | endforeach() | ||
| 212 | |||
| 213 | foreach(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() | ||
| 240 | endforeach() | ||
| 241 | |||
| 242 | if(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) | ||
| 249 | endif() | ||
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 @@ | |||
| 1 | KODI ADDONS | ||
| 2 | =========== | ||
| 3 | This directory contains the cmake-based buildsystem for addons. It looks into | ||
| 4 | the "addons" sub-directory and parses all *.txt files recursively. Each addon | ||
| 5 | must have its own <addon-id>.txt file in a separate sub-directory which must | ||
| 6 | follow the defined format: | ||
| 7 | <addon-id> <git-url> <git-revision> | ||
| 8 | where | ||
| 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 | |||
| 15 | Reserved filenames (for additional information on how to build an addon) | ||
| 16 | are: | ||
| 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 | |||
| 22 | The buildsystem uses the following variables (which can be passed into it when | ||
| 23 | executing cmake with the -D<variable-name>=<value> option) to e.g. access | ||
| 24 | specific 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 | |||
| 46 | The buildsystem makes some assumptions about the environment which must be met | ||
| 47 | by 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 | |||
| 52 | To trigger the cmake-based buildsystem the following command must be executed | ||
| 53 | with <path> being the path to this directory (absolute or relative, allowing for | ||
| 54 | in-source and out-of-source builds). | ||
| 55 | |||
| 56 | cmake <path> -G <generator> | ||
| 57 | |||
| 58 | cmake supports multiple generators, see | ||
| 59 | http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Generators for a list. | ||
| 60 | |||
| 61 | In 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 @@ | |||
| 1 | project(kodi-addons-depends) | ||
| 2 | |||
| 3 | cmake_minimum_required(VERSION 2.8) | ||
| 4 | |||
| 5 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) | ||
| 6 | |||
| 7 | if(NOT CMAKE_BUILD_TYPE) | ||
| 8 | set(CMAKE_BUILD_TYPE Release) | ||
| 9 | endif() | ||
| 10 | |||
| 11 | if(NOT CORE_SYSTEM_NAME) | ||
| 12 | string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME) | ||
| 13 | endif() | ||
| 14 | |||
| 15 | include(ExternalProject) | ||
| 16 | |||
| 17 | if(NOT DEPENDS_PATH) | ||
| 18 | set(DEPENDS_PATH ${PROJECT_SOURCE_DIR}/../build/depends) | ||
| 19 | else() | ||
| 20 | file(TO_CMAKE_PATH "${DEPENDS_PATH}" DEPENDS_PATH) | ||
| 21 | endif() | ||
| 22 | get_filename_component(DEPENDS_PATH "${DEPENDS_PATH}" ABSOLUTE) | ||
| 23 | list(APPEND CMAKE_PREFIX_PATH ${DEPENDS_PATH}) | ||
| 24 | |||
| 25 | if(NOT BUILD_DIR) | ||
| 26 | set(BUILD_DIR "${CMAKE_BINARY_DIR}/build") | ||
| 27 | else() | ||
| 28 | file(TO_CMAKE_PATH "${BUILD_DIR}" BUILD_DIR) | ||
| 29 | endif() | ||
| 30 | get_filename_component(BUILD_DIR "${BUILD_DIR}" ABSOLUTE) | ||
| 31 | |||
| 32 | ## use add_addon_depends to handle the cmake based dependencies | ||
| 33 | include(${APP_ROOT}/project/cmake/scripts/common/handle-depends.cmake) | ||
| 34 | add_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 | ||
| 37 | if(EXISTS ${PROJECT_SOURCE_DIR}/${CORE_SYSTEM_NAME}/CMakeLists.txt) | ||
| 38 | message(STATUS "Processing ${CORE_SYSTEM_NAME}") | ||
| 39 | add_subdirectory(${CORE_SYSTEM_NAME}) | ||
| 40 | else() | ||
| 41 | message(STATUS "No platform specific file ${PROJECT_SOURCE_DIR}/${CORE_SYSTEM_NAME}/CMakeLists.txt found") | ||
| 42 | endif() | ||
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 @@ | |||
| 1 | KODI ADDON DEPENDENCIES | ||
| 2 | ======================= | ||
| 3 | This directory contains the cmake-based buildsystem for addon dependencies. It | ||
| 4 | looks into the "common" and the "<platform>/cmake" sub-directories and parses | ||
| 5 | all *.txt files recursively. Each dependency must have its own <dependency>.txt | ||
| 6 | file (either in the main sub-directory or in a separate subdirectory of the main | ||
| 7 | subdirectory) 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> | ||
| 12 | where | ||
| 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 | |||
| 20 | Reserved filenames (for additional information on how to build a dependency) | ||
| 21 | are: | ||
| 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 | |||
| 28 | The buildsystem uses the following variables (which can be passed into it when | ||
| 29 | executing cmake with the -D<variable-name>=<value> option) to e.g. access | ||
| 30 | specific 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 | |||
| 46 | To trigger the cmake-based buildsystem the following command must be executed | ||
| 47 | with <path> being the path to this directory (absolute or relative, allowing for | ||
| 48 | in-source and out-of-source builds). | ||
| 49 | |||
| 50 | cmake <path> -G <generator> | ||
| 51 | |||
| 52 | cmake supports multiple generators, see | ||
| 53 | http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Generators for a list. | ||
| 54 | |||
| 55 | In 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 @@ | |||
| 1 | kodi | ||
| 2 | tinyxml \ 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 @@ | |||
| 1 | project(tinyxml) | ||
| 2 | |||
| 3 | cmake_minimum_required(VERSION 2.8) | ||
| 4 | |||
| 5 | set(SOURCES src/tinystr.cpp | ||
| 6 | src/tinyxml.cpp | ||
| 7 | src/tinyxmlerror.cpp | ||
| 8 | src/tinyxmlparser.cpp) | ||
| 9 | |||
| 10 | if(WIN32) | ||
| 11 | add_definitions(-DWIN32 -D_LIB) | ||
| 12 | endif() | ||
| 13 | add_definitions(-DTIXML_USE_STL) | ||
| 14 | |||
| 15 | add_library(tinyxml ${SOURCES}) | ||
| 16 | |||
| 17 | include_directories(${PROJECT_SOURCE_DIR}/include) | ||
| 18 | |||
| 19 | set(HEADERS ${PROJECT_SOURCE_DIR}/include/tinystr.h | ||
| 20 | ${PROJECT_SOURCE_DIR}/include/tinyxml.h) | ||
| 21 | |||
| 22 | install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) | ||
| 23 | install(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 @@ | |||
| 1 | project(kodi-addons-depends-windows) | ||
| 2 | |||
| 3 | cmake_minimum_required(VERSION 2.8) | ||
| 4 | |||
| 5 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) | ||
| 6 | |||
| 7 | if(NOT CMAKE_BUILD_TYPE) | ||
| 8 | set(CMAKE_BUILD_TYPE Release) | ||
| 9 | endif() | ||
| 10 | |||
| 11 | include(ExternalProject) | ||
| 12 | |||
| 13 | if(NOT DEPENDS_PATH) | ||
| 14 | message(FATAL_ERROR "DEPENDS_PATH (${DEPENDS_PATH}) is not a valid target directory.") | ||
| 15 | else() | ||
| 16 | file(TO_CMAKE_PATH "${DEPENDS_PATH}" DEPENDS_PATH) | ||
| 17 | endif() | ||
| 18 | get_filename_component(DEPENDS_PATH "${DEPENDS_PATH}" ABSOLUTE) | ||
| 19 | list(APPEND CMAKE_PREFIX_PATH ${DEPENDS_PATH}) | ||
| 20 | |||
| 21 | if(NOT DEPENDS_TO_BUILD) | ||
| 22 | set(DEPENDS_TO_BUILD "all") | ||
| 23 | endif() | ||
| 24 | |||
| 25 | function(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 | ) | ||
| 37 | endfunction() | ||
| 38 | |||
| 39 | #find_package(7Zip REQUIRED) | ||
| 40 | |||
| 41 | file(GLOB_RECURSE download_input_files prebuilt/*.txt) | ||
| 42 | foreach(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() | ||
| 55 | endforeach() | ||
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 @@ | |||
| 1 | find_program(7ZIP_EXECUTABLE NAMES 7z.exe | ||
| 2 | HINTS PATHS "c:/Program Files/7-Zip") | ||
| 3 | |||
| 4 | include(FindPackageHandleStandardArgs) | ||
| 5 | find_package_handle_standard_args(7Zip DEFAULT_MSG 7ZIP_EXECUTABLE) | ||
| 6 | |||
| 7 | mark_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 @@ | |||
| 1 | KODI WIN32 ADDON DEPENDENCIES | ||
| 2 | ============================= | ||
| 3 | This directory contains the cmake-based buildsystem for dependencies (currently | ||
| 4 | only prebuilt) used by one or multiple addons. The buildsystem looks into the | ||
| 5 | "prebuilt" sub-directory, downloads all the specified dependencies, extracts | ||
| 6 | them and places them into the "depends" sub-directory. | ||
| 7 | |||
| 8 | To trigger the cmake-based buildsystem the following command must be executed | ||
| 9 | with <path> being the path to this directory (absolute or relative, allowing for | ||
| 10 | in-source and out-of-source builds). | ||
| 11 | |||
| 12 | cmake <path> [-G <generator>] | ||
| 13 | |||
| 14 | cmake supports multiple generators, see | ||
| 15 | http://www.cmake.org/cmake/help/v2.8.8/cmake.html#section_Generators for a list. | ||
| 16 | For win32 builds one of the "Visual Studio XX" or the "NMake Makefiles" | ||
| 17 | generators is preferred. For the "NMake Makefiles" generator to work the above | ||
| 18 | command must be called from an environment prepared for VC++ builds (see | ||
| 19 | http://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 @@ | |||
| 1 | get_filename_component(file ${URL} NAME) | ||
| 2 | file(DOWNLOAD ${URL} ${DEST}/${file}) | ||
| 3 | execute_process(COMMAND ${7ZIP_EXECUTABLE} -y x ${DEST}/${file} | ||
| 4 | WORKING_DIRECTORY ${DESTDIR}) | ||
| 5 | if(${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}) | ||
| 10 | endif() | ||
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 @@ | |||
| 1 | get_filename_component(file ${URL} NAME) | ||
| 2 | file(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 @@ | |||
| 1 | if(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() | ||
| 21 | else() | ||
| 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}) | ||
| 24 | endif() \ 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 @@ | |||
| 1 | KODI WIN32 PREBUILT ADDON DEPENDENCIES | ||
| 2 | ====================================== | ||
| 3 | This directory contains a file or sub-directory for every prebuilt dependency | ||
| 4 | used by one of the addons being built. There are two different modes supported. | ||
| 5 | Both include a file named <library-id>.txt which must follow the defined format | ||
| 6 | <library-id> <download-url> | ||
| 7 | |||
| 8 | If 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 @@ | |||
| 1 | SET(KODI_INCLUDE_DIR @prefix@/include) | ||
| 2 | SET(APP_NAME @APP_NAME@) | ||
| 3 | SET(APP_VERSION_MAJOR @APP_VERSION_MAJOR@) | ||
| 4 | SET(APP_VERSION_MINOR @APP_VERSION_MINOR@) | ||
| 5 | IF(NOT WIN32) | ||
| 6 | SET(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} @CXX11_SWITCH@") | ||
| 7 | ENDIF() | ||
| 8 | LIST(APPEND CMAKE_MODULE_PATH @prefix@/lib/kodi) | ||
| 9 | ADD_DEFINITIONS(@ARCH_DEFINES@) | ||
| 10 | |||
| 11 | include(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. | ||
| 9 | add_custom_target(addon-package | ||
| 10 | COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target package) | ||
| 11 | |||
| 12 | macro(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}) | ||
| 15 | endmacro() | ||
| 16 | |||
| 17 | # Grab the version from a given add-on's addon.xml | ||
| 18 | macro (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}) | ||
| 23 | endmacro() | ||
| 24 | |||
| 25 | # Build, link and optionally package an add-on | ||
| 26 | macro (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) | ||
| 82 | endmacro() | ||
| 83 | |||
| 84 | # finds a path to a given file (recursive) | ||
| 85 | function (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) | ||
| 91 | endfunction() | ||
| 92 | |||
| 93 | # Cmake build options | ||
| 94 | include(addoptions) | ||
| 95 | include(TestCXXAcceptsFlag) | ||
| 96 | OPTION(PACKAGE_ZIP "Package Zip file?" OFF) | ||
| 97 | OPTION(PACKAGE_TGZ "Package TGZ file?" OFF) | ||
| 98 | OPTION(BUILD_SHARED_LIBS "Build shared libs?" ON) | ||
| 99 | |||
| 100 | # LTO support? | ||
| 101 | CHECK_CXX_ACCEPTS_FLAG("-flto" HAVE_LTO) | ||
| 102 | IF(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) | ||
| 107 | ENDIF(HAVE_LTO) | ||
| 108 | |||
| 109 | # set this to try linking dependencies as static as possible | ||
| 110 | IF(ADDONS_PREFER_STATIC_LIBS) | ||
| 111 | SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) | ||
| 112 | ENDIF(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 | |||
| 26 | function (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) | ||
| 61 | endfunction (add_options lang build) | ||
| 62 | |||
| 63 | # set varname to flag unless user has specified something that matches regex | ||
| 64 | function (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}") | ||
| 76 | endfunction (set_default_option) | ||
| 77 | |||
| 78 | # note: this must be called before project() | ||
| 79 | macro (no_default_options) | ||
| 80 | # prevent the platform probe to set options | ||
| 81 | set (CMAKE_NOT_USING_CONFIG_FLAGS TRUE) | ||
| 82 | endmacro (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 | ||
| 2 | function(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) | ||
| 40 | endfunction() | ||
| 41 | |||
| 42 | function(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() | ||
| 61 | endfunction() | ||
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 @@ | |||
| 1 | include(${APP_ROOT}/project/cmake/scripts/common/check_target_platform.cmake) | ||
| 2 | |||
| 3 | # handle addon depends | ||
| 4 | function(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) | ||
| 190 | endfunction() | ||
| 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 | ||
| 2 | if(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() | ||
| 15 | endif() | ||
| 16 | |||
| 17 | # bail if we can't parse versions | ||
| 18 | if(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") | ||
| 20 | endif() | ||
| 21 | |||
| 22 | ### copy all the addon binding header files to include/kodi | ||
| 23 | # make sure include/kodi exists and is empty | ||
| 24 | set(KODI_LIB_DIR ${DEPENDS_PATH}/lib/kodi) | ||
| 25 | if(NOT EXISTS "${KODI_LIB_DIR}/") | ||
| 26 | file(MAKE_DIRECTORY ${KODI_LIB_DIR}) | ||
| 27 | endif() | ||
| 28 | |||
| 29 | set(KODI_INCLUDE_DIR ${DEPENDS_PATH}/include/kodi) | ||
| 30 | if(NOT EXISTS "${KODI_INCLUDE_DIR}/") | ||
| 31 | file(MAKE_DIRECTORY ${KODI_INCLUDE_DIR}) | ||
| 32 | endif() | ||
| 33 | |||
| 34 | # we still need XBMC_INCLUDE_DIR and XBMC_LIB_DIR for backwards compatibility to xbmc | ||
| 35 | set(XBMC_LIB_DIR ${DEPENDS_PATH}/lib/xbmc) | ||
| 36 | if(NOT EXISTS "${XBMC_LIB_DIR}/") | ||
| 37 | file(MAKE_DIRECTORY ${XBMC_LIB_DIR}) | ||
| 38 | endif() | ||
| 39 | set(XBMC_INCLUDE_DIR ${DEPENDS_PATH}/include/xbmc) | ||
| 40 | if(NOT EXISTS "${XBMC_INCLUDE_DIR}/") | ||
| 41 | file(MAKE_DIRECTORY ${XBMC_INCLUDE_DIR}) | ||
| 42 | endif() | ||
| 43 | |||
| 44 | # make sure C++11 is always set | ||
| 45 | if(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() | ||
| 50 | endif() | ||
| 51 | |||
| 52 | # kodi-config.cmake.in (further down) expects a "prefix" variable | ||
| 53 | get_filename_component(prefix "${DEPENDS_PATH}" ABSOLUTE) | ||
| 54 | |||
| 55 | # generate the proper kodi-config.cmake file | ||
| 56 | configure_file(${APP_ROOT}/project/cmake/kodi-config.cmake.in ${KODI_LIB_DIR}/kodi-config.cmake @ONLY) | ||
| 57 | # copy cmake helpers to lib/kodi | ||
| 58 | file(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 | ||
| 61 | configure_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 | ||
| 65 | file(STRINGS ${APP_ROOT}/xbmc/addons/addon-bindings.mk bindings) | ||
| 66 | string(REPLACE "\n" ";" bindings "${bindings}") | ||
| 67 | foreach(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() | ||
| 88 | endforeach() | ||
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 @@ | |||
| 1 | if(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") | ||
| 5 | endif(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 @@ | |||
| 1 | if(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") | ||
| 5 | endif(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 @@ | |||
| 1 | message(WARNING "find_package(xbmc) has been deprecated, please use find_package(kodi)") | ||
| 2 | |||
| 3 | find_package(kodi REQUIRED) | ||
| 4 | set(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 | |||
| 3 | rbase="/root/kodi/xbmc.git" | ||
| 4 | |||
| 5 | for p in \ | ||
| 6 | addons/library.xbmc.* \ | ||
| 7 | "project/cmake" \ | ||
| 8 | "version.txt" \ | ||
| 9 | "xbmc/addons" \ | ||
| 10 | "xbmc/cores/dvdplayer/DVDDemuxers" | ||
| 11 | do | ||
| 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 | ||
| 17 | done | ||
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 @@ | |||
| 1 | set(CMAKE_SYSTEM_VERSION 1) | ||
| 2 | set(OS "android") | ||
| 3 | set(CPU "armeabi-v7a") | ||
| 4 | set(PLATFORM "") | ||
| 5 | if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android") | ||
| 6 | set(CMAKE_SYSTEM_NAME Linux) | ||
| 7 | endif() | ||
| 8 | |||
| 9 | # set special CORE_SYSTEM_NAME | ||
| 10 | if("${OS}" STREQUAL "android") | ||
| 11 | set(CORE_SYSTEM_NAME android) | ||
| 12 | elseif("${OS}" STREQUAL "ios") | ||
| 13 | set(CORE_SYSTEM_NAME ios) | ||
| 14 | elseif("${PLATFORM}" STREQUAL "raspberry-pi") | ||
| 15 | set(CORE_SYSTEM_NAME rbpi) | ||
| 16 | elseif("${PLATFORM}" STREQUAL "darwin") | ||
| 17 | set(CORE_SYSTEM_NAME darwin) | ||
| 18 | endif() | ||
| 19 | |||
| 20 | #set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) | ||
| 21 | |||
| 22 | if("${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) | ||
| 28 | endif() | ||
| 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 | ||
| 37 | set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/android-14/bin/arm-linux-androideabi) | ||
| 38 | set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc) | ||
| 39 | set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++) | ||
| 40 | set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver") | ||
| 41 | set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker") | ||
| 42 | set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib) | ||
| 43 | set(CMAKE_C_FLAGS "-march=armv7-a -mtune=cortex-a9 -mfloat-abi=softfp -mfpu=neon") | ||
| 44 | set(CMAKE_CXX_FLAGS "-march=armv7-a -mtune=cortex-a9 -mfloat-abi=softfp -mfpu=neon -frtti") | ||
| 45 | set(CMAKE_CPP_FLAGS "") | ||
| 46 | set(ENV{CFLAGS} ${CMAKE_C_FLAGS}) | ||
| 47 | set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS}) | ||
| 48 | set(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 | |||
| 56 | if(NOT OS STREQUAL "linux") | ||
| 57 | set(ADDONS_PREFER_STATIC_LIBS ON) | ||
| 58 | endif() | ||
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 @@ | |||
| 1 | set(CMAKE_SYSTEM_VERSION 1) | ||
| 2 | set(OS "ios") | ||
| 3 | set(CPU "armv7") | ||
| 4 | set(PLATFORM "darwin") | ||
| 5 | if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android") | ||
| 6 | set(CMAKE_SYSTEM_NAME Linux) | ||
| 7 | endif() | ||
| 8 | |||
| 9 | # set special CORE_SYSTEM_NAME | ||
| 10 | if("${OS}" STREQUAL "android") | ||
| 11 | set(CORE_SYSTEM_NAME android) | ||
| 12 | elseif("${OS}" STREQUAL "ios") | ||
| 13 | set(CORE_SYSTEM_NAME ios) | ||
| 14 | elseif("${PLATFORM}" STREQUAL "raspberry-pi") | ||
| 15 | set(CORE_SYSTEM_NAME rbpi) | ||
| 16 | elseif("${PLATFORM}" STREQUAL "darwin") | ||
| 17 | set(CORE_SYSTEM_NAME darwin) | ||
| 18 | endif() | ||
| 19 | |||
| 20 | #set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) | ||
| 21 | |||
| 22 | if("${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) | ||
| 28 | endif() | ||
| 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 | ||
| 37 | set(COMPILER_PREFIX /var/www/ud_3/xbmc/osx/osxcross/target/bin/arm-apple-darwin14) | ||
| 38 | set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-clang) | ||
| 39 | set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-clang++) | ||
| 40 | set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver") | ||
| 41 | set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker") | ||
| 42 | set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib) | ||
| 43 | set(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") | ||
| 44 | set(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++") | ||
| 45 | set(CMAKE_CPP_FLAGS "") | ||
| 46 | set(ENV{CFLAGS} ${CMAKE_C_FLAGS}) | ||
| 47 | set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS}) | ||
| 48 | set(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 | |||
| 56 | if(NOT OS STREQUAL "linux") | ||
| 57 | set(ADDONS_PREFER_STATIC_LIBS ON) | ||
| 58 | endif() | ||
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 @@ | |||
| 1 | set(CMAKE_SYSTEM_VERSION 1) | ||
| 2 | set(OS "linux") | ||
| 3 | set(CPU "i686") | ||
| 4 | set(PLATFORM "") | ||
| 5 | if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android") | ||
| 6 | set(CMAKE_SYSTEM_NAME Linux) | ||
| 7 | endif() | ||
| 8 | |||
| 9 | # set special CORE_SYSTEM_NAME | ||
| 10 | if("${OS}" STREQUAL "android") | ||
| 11 | set(CORE_SYSTEM_NAME android) | ||
| 12 | elseif("${OS}" STREQUAL "ios") | ||
| 13 | set(CORE_SYSTEM_NAME ios) | ||
| 14 | elseif("${PLATFORM}" STREQUAL "raspberry-pi") | ||
| 15 | set(CORE_SYSTEM_NAME rbpi) | ||
| 16 | elseif("${PLATFORM}" STREQUAL "darwin") | ||
| 17 | set(CORE_SYSTEM_NAME darwin) | ||
| 18 | endif() | ||
| 19 | |||
| 20 | #set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) | ||
| 21 | |||
| 22 | if("${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) | ||
| 28 | endif() | ||
| 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 | ||
| 37 | set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu) | ||
| 38 | set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc) | ||
| 39 | set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++) | ||
| 40 | set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver") | ||
| 41 | set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker") | ||
| 42 | set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib) | ||
| 43 | set(CMAKE_C_FLAGS "-m32") | ||
| 44 | set(CMAKE_CXX_FLAGS "-m32") | ||
| 45 | set(CMAKE_CPP_FLAGS "") | ||
| 46 | set(ENV{CFLAGS} ${CMAKE_C_FLAGS}) | ||
| 47 | set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS}) | ||
| 48 | set(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 | |||
| 56 | if(NOT OS STREQUAL "linux") | ||
| 57 | set(ADDONS_PREFER_STATIC_LIBS ON) | ||
| 58 | endif() | ||
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 @@ | |||
| 1 | set(CMAKE_SYSTEM_VERSION 1) | ||
| 2 | set(OS "linux") | ||
| 3 | set(CPU "x86_64") | ||
| 4 | set(PLATFORM "") | ||
| 5 | if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android") | ||
| 6 | set(CMAKE_SYSTEM_NAME Linux) | ||
| 7 | endif() | ||
| 8 | |||
| 9 | # set special CORE_SYSTEM_NAME | ||
| 10 | if("${OS}" STREQUAL "android") | ||
| 11 | set(CORE_SYSTEM_NAME android) | ||
| 12 | elseif("${OS}" STREQUAL "ios") | ||
| 13 | set(CORE_SYSTEM_NAME ios) | ||
| 14 | elseif("${PLATFORM}" STREQUAL "raspberry-pi") | ||
| 15 | set(CORE_SYSTEM_NAME rbpi) | ||
| 16 | elseif("${PLATFORM}" STREQUAL "darwin") | ||
| 17 | set(CORE_SYSTEM_NAME darwin) | ||
| 18 | endif() | ||
| 19 | |||
| 20 | #set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) | ||
| 21 | |||
| 22 | if("${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) | ||
| 28 | endif() | ||
| 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 | ||
| 37 | set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu) | ||
| 38 | set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc) | ||
| 39 | set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++) | ||
| 40 | set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver") | ||
| 41 | set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker") | ||
| 42 | set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib) | ||
| 43 | set(CMAKE_C_FLAGS "") | ||
| 44 | set(CMAKE_CXX_FLAGS "") | ||
| 45 | set(CMAKE_CPP_FLAGS "") | ||
| 46 | set(ENV{CFLAGS} ${CMAKE_C_FLAGS}) | ||
| 47 | set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS}) | ||
| 48 | set(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 | |||
| 56 | if(NOT OS STREQUAL "linux") | ||
| 57 | set(ADDONS_PREFER_STATIC_LIBS ON) | ||
| 58 | endif() | ||
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 @@ | |||
| 1 | set(CMAKE_SYSTEM_VERSION 1) | ||
| 2 | set(OS "osx") | ||
| 3 | set(CPU "i386") | ||
| 4 | set(PLATFORM "darwin") | ||
| 5 | if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android") | ||
| 6 | set(CMAKE_SYSTEM_NAME Linux) | ||
| 7 | endif() | ||
| 8 | |||
| 9 | # set special CORE_SYSTEM_NAME | ||
| 10 | if("${OS}" STREQUAL "android") | ||
| 11 | set(CORE_SYSTEM_NAME android) | ||
| 12 | elseif("${OS}" STREQUAL "ios") | ||
| 13 | set(CORE_SYSTEM_NAME ios) | ||
| 14 | elseif("${PLATFORM}" STREQUAL "raspberry-pi") | ||
| 15 | set(CORE_SYSTEM_NAME rbpi) | ||
| 16 | elseif("${PLATFORM}" STREQUAL "darwin") | ||
| 17 | set(CORE_SYSTEM_NAME darwin) | ||
| 18 | endif() | ||
| 19 | |||
| 20 | #set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) | ||
| 21 | |||
| 22 | if("${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) | ||
| 28 | endif() | ||
| 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 | ||
| 37 | set(COMPILER_PREFIX /var/www/ud_3/xbmc/osx/osxcross/target/bin/i386-apple-darwin14) | ||
| 38 | set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-clang) | ||
| 39 | set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-clang++) | ||
| 40 | set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver") | ||
| 41 | set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker") | ||
| 42 | set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib) | ||
| 43 | set(CMAKE_C_FLAGS "") | ||
| 44 | set(CMAKE_CXX_FLAGS "-stdlib=libc++") | ||
| 45 | set(CMAKE_CPP_FLAGS "") | ||
| 46 | set(ENV{CFLAGS} ${CMAKE_C_FLAGS}) | ||
| 47 | set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS}) | ||
| 48 | set(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 | |||
| 56 | if(NOT OS STREQUAL "linux") | ||
| 57 | set(ADDONS_PREFER_STATIC_LIBS ON) | ||
| 58 | endif() | ||
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 @@ | |||
| 1 | set(CMAKE_SYSTEM_VERSION 1) | ||
| 2 | set(OS "osx") | ||
| 3 | set(CPU "x86_64") | ||
| 4 | set(PLATFORM "darwin") | ||
| 5 | if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android") | ||
| 6 | set(CMAKE_SYSTEM_NAME Linux) | ||
| 7 | endif() | ||
| 8 | |||
| 9 | # set special CORE_SYSTEM_NAME | ||
| 10 | if("${OS}" STREQUAL "android") | ||
| 11 | set(CORE_SYSTEM_NAME android) | ||
| 12 | elseif("${OS}" STREQUAL "ios") | ||
| 13 | set(CORE_SYSTEM_NAME ios) | ||
| 14 | elseif("${PLATFORM}" STREQUAL "raspberry-pi") | ||
| 15 | set(CORE_SYSTEM_NAME rbpi) | ||
| 16 | elseif("${PLATFORM}" STREQUAL "darwin") | ||
| 17 | set(CORE_SYSTEM_NAME darwin) | ||
| 18 | endif() | ||
| 19 | |||
| 20 | #set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) | ||
| 21 | |||
| 22 | if("${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) | ||
| 28 | endif() | ||
| 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 | ||
| 37 | set(COMPILER_PREFIX /var/www/ud_3/xbmc/osx/osxcross/target/bin/x86_64-apple-darwin14) | ||
| 38 | set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-clang) | ||
| 39 | set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-clang++) | ||
| 40 | set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver") | ||
| 41 | set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker") | ||
| 42 | set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib) | ||
| 43 | set(CMAKE_C_FLAGS "") | ||
| 44 | set(CMAKE_CXX_FLAGS "-stdlib=libc++") | ||
| 45 | set(CMAKE_CPP_FLAGS "") | ||
| 46 | set(ENV{CFLAGS} ${CMAKE_C_FLAGS}) | ||
| 47 | set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS}) | ||
| 48 | set(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 | |||
| 56 | if(NOT OS STREQUAL "linux") | ||
| 57 | set(ADDONS_PREFER_STATIC_LIBS ON) | ||
| 58 | endif() | ||
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 @@ | |||
| 1 | set(CMAKE_SYSTEM_VERSION 1) | ||
| 2 | set(OS "linux") | ||
| 3 | set(CPU "arm1176jzf-s") | ||
| 4 | set(PLATFORM "raspberry-pi") | ||
| 5 | if("${OS}" STREQUAL "linux" OR "${OS}" STREQUAL "android") | ||
| 6 | set(CMAKE_SYSTEM_NAME Linux) | ||
| 7 | endif() | ||
| 8 | |||
| 9 | # set special CORE_SYSTEM_NAME | ||
| 10 | if("${OS}" STREQUAL "android") | ||
| 11 | set(CORE_SYSTEM_NAME android) | ||
| 12 | elseif("${OS}" STREQUAL "ios") | ||
| 13 | set(CORE_SYSTEM_NAME ios) | ||
| 14 | elseif("${PLATFORM}" STREQUAL "raspberry-pi") | ||
| 15 | set(CORE_SYSTEM_NAME rbpi) | ||
| 16 | elseif("${PLATFORM}" STREQUAL "darwin") | ||
| 17 | set(CORE_SYSTEM_NAME darwin) | ||
| 18 | endif() | ||
| 19 | |||
| 20 | #set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) | ||
| 21 | |||
| 22 | if("${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) | ||
| 28 | endif() | ||
| 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 | ||
| 37 | set(COMPILER_PREFIX /var/www/ud_3/xbmc/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi) | ||
| 38 | set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc) | ||
| 39 | set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++) | ||
| 40 | set(CMAKE_AR ${COMPILER_PREFIX}-ar CACHE FILEPATH "Archiver") | ||
| 41 | set(CMAKE_LINKER ${COMPILER_PREFIX}-ld CACHE FILEPATH "Linker") | ||
| 42 | set(CMAKE_RANLIB ${COMPILER_PREFIX}-ranlib) | ||
| 43 | set(CMAKE_C_FLAGS "-mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux") | ||
| 44 | set(CMAKE_CXX_FLAGS "-mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -mabi=aapcs-linux") | ||
| 45 | set(CMAKE_CPP_FLAGS "") | ||
| 46 | set(ENV{CFLAGS} ${CMAKE_C_FLAGS}) | ||
| 47 | set(ENV{CXXFLAGS} ${CMAKE_CXX_FLAGS}) | ||
| 48 | set(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 | |||
| 56 | if(NOT OS STREQUAL "linux") | ||
| 57 | set(ADDONS_PREFER_STATIC_LIBS ON) | ||
| 58 | endif() | ||
diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..d21c18f --- /dev/null +++ b/version.txt | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | APP_NAME Kodi | ||
| 2 | COMPANY_NAME XBMC-Foundation | ||
| 3 | WEBSITE http://kodi.tv | ||
| 4 | VERSION_MAJOR 15 | ||
| 5 | VERSION_MINOR 0 | ||
| 6 | VERSION_TAG ALPHA2 | ||
| 7 | VERSION_CODE 149702 | ||
| 8 | ADDON_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 | |||
| 45 | using XFILE::CDirectory; | ||
| 46 | using XFILE::CFile; | ||
| 47 | using namespace std; | ||
| 48 | |||
| 49 | namespace ADDON | ||
| 50 | { | ||
| 51 | |||
| 52 | /** | ||
| 53 | * helper functions | ||
| 54 | * | ||
| 55 | */ | ||
| 56 | |||
| 57 | typedef struct | ||
| 58 | { | ||
| 59 | const char* name; | ||
| 60 | TYPE type; | ||
| 61 | int pretty; | ||
| 62 | const char* icon; | ||
| 63 | } TypeMapping; | ||
| 64 | |||
| 65 | static 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 | |||
| 95 | const 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 | |||
| 111 | TYPE 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 | |||
| 123 | const 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 | |||
| 143 | AddonProps::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 | |||
| 180 | AddonProps::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 | |||
| 193 | void 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 | |||
| 246 | void 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 | |||
| 260 | CAddon::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 | |||
| 275 | CAddon::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 | |||
| 286 | CAddon::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 | |||
| 301 | CAddon::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 | |||
| 317 | AddonPtr CAddon::Clone() const | ||
| 318 | { | ||
| 319 | return AddonPtr(new CAddon(*this)); | ||
| 320 | } | ||
| 321 | |||
| 322 | bool 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 | ||
| 329 | void 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 | */ | ||
| 415 | bool 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 | |||
| 424 | void CAddon::ClearStrings() | ||
| 425 | { | ||
| 426 | // Unload temporary language strings | ||
| 427 | m_strings.Clear(); | ||
| 428 | m_hasStrings = false; | ||
| 429 | } | ||
| 430 | |||
| 431 | std::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 | */ | ||
| 442 | bool CAddon::HasSettings() | ||
| 443 | { | ||
| 444 | return LoadSettings(); | ||
| 445 | } | ||
| 446 | |||
| 447 | bool 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 | |||
| 476 | bool CAddon::HasUserSettings() | ||
| 477 | { | ||
| 478 | if (!LoadSettings()) | ||
| 479 | return false; | ||
| 480 | |||
| 481 | return m_userSettingsLoaded; | ||
| 482 | } | ||
| 483 | |||
| 484 | bool CAddon::ReloadSettings() | ||
| 485 | { | ||
| 486 | return LoadSettings(true); | ||
| 487 | } | ||
| 488 | |||
| 489 | bool 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 | |||
| 498 | void 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 | |||
| 527 | std::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 | |||
| 538 | void 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 | |||
| 545 | bool 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 | |||
| 577 | void 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 | |||
| 591 | TiXmlElement* CAddon::GetSettingsXML() | ||
| 592 | { | ||
| 593 | return m_addonXmlDoc.RootElement(); | ||
| 594 | } | ||
| 595 | |||
| 596 | void CAddon::BuildProfilePath() | ||
| 597 | { | ||
| 598 | m_profile = StringUtils::Format("special://profile/addon_data/%s/", ID().c_str()); | ||
| 599 | } | ||
| 600 | |||
| 601 | const 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 | |||
| 608 | const std::string CAddon::LibPath() const | ||
| 609 | { | ||
| 610 | return URIUtils::AddFileToFolder(m_props.path, m_strLibName); | ||
| 611 | } | ||
| 612 | |||
| 613 | AddonVersion 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 | |||
| 627 | CAddonLibrary::CAddonLibrary(const cp_extension_t *ext) | ||
| 628 | : CAddon(ext) | ||
| 629 | , m_addonType(SetAddonType()) | ||
| 630 | { | ||
| 631 | } | ||
| 632 | |||
| 633 | CAddonLibrary::CAddonLibrary(const AddonProps& props) | ||
| 634 | : CAddon(props) | ||
| 635 | , m_addonType(SetAddonType()) | ||
| 636 | { | ||
| 637 | } | ||
| 638 | |||
| 639 | AddonPtr CAddonLibrary::Clone() const | ||
| 640 | { | ||
| 641 | return AddonPtr(new CAddonLibrary(*this)); | ||
| 642 | } | ||
| 643 | |||
| 644 | TYPE 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 | |||
| 29 | class TiXmlElement; | ||
| 30 | class CAddonCallbacksAddon; | ||
| 31 | |||
| 32 | typedef struct cp_plugin_info_t cp_plugin_info_t; | ||
| 33 | typedef struct cp_extension_t cp_extension_t; | ||
| 34 | |||
| 35 | namespace ADDON | ||
| 36 | { | ||
| 37 | typedef std::vector<AddonPtr> VECADDONS; | ||
| 38 | typedef std::vector<AddonPtr>::iterator IVECADDONS; | ||
| 39 | |||
| 40 | // utils | ||
| 41 | const std::string TranslateType(const TYPE &type, bool pretty=false); | ||
| 42 | const std::string GetIcon(const TYPE &type); | ||
| 43 | TYPE TranslateType(const std::string &string); | ||
| 44 | |||
| 45 | class AddonProps : public ISerializable | ||
| 46 | { | ||
| 47 | public: | ||
| 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; | ||
| 91 | private: | ||
| 92 | void BuildDependencies(const cp_plugin_info_t *plugin); | ||
| 93 | }; | ||
| 94 | |||
| 95 | typedef std::vector<class AddonProps> VECADDONPROPS; | ||
| 96 | |||
| 97 | class CAddon : public IAddon | ||
| 98 | { | ||
| 99 | public: | ||
| 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; } | ||
| 201 | protected: | ||
| 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(); | ||
| 240 | private: | ||
| 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 | |||
| 263 | class CAddonLibrary : public CAddon | ||
| 264 | { | ||
| 265 | public: | ||
| 266 | CAddonLibrary(const AddonProps &props); | ||
| 267 | CAddonLibrary(const cp_extension_t *ext); | ||
| 268 | |||
| 269 | virtual AddonPtr Clone() const; | ||
| 270 | |||
| 271 | private: | ||
| 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 | |||
| 30 | namespace ADDON | ||
| 31 | { | ||
| 32 | |||
| 33 | CAddonCallbacks::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 | |||
| 54 | CAddonCallbacks::~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 | |||
| 69 | CB_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 | |||
| 82 | void 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 | |||
| 95 | CB_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 | |||
| 108 | void 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 | |||
| 121 | CB_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 | |||
| 134 | void 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 | |||
| 147 | CB_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 | |||
| 160 | void 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 | ||
| 30 | typedef intptr_t ssize_t; | ||
| 31 | #define _SSIZE_T_DEFINED | ||
| 32 | #endif // !_SSIZE_T_DEFINED | ||
| 33 | #endif // TARGET_WINDOWS | ||
| 34 | |||
| 35 | typedef void (*AddOnLogCallback)(void *addonData, const ADDON::addon_log_t loglevel, const char *msg); | ||
| 36 | typedef void (*AddOnQueueNotification)(void *addonData, const ADDON::queue_msg_t type, const char *msg); | ||
| 37 | typedef bool (*AddOnWakeOnLan)(const char* mac); | ||
| 38 | typedef bool (*AddOnGetSetting)(void *addonData, const char *settingName, void *settingValue); | ||
| 39 | typedef char* (*AddOnUnknownToUTF8)(const char *sourceDest); | ||
| 40 | typedef char* (*AddOnGetLocalizedString)(const void* addonData, long dwCode); | ||
| 41 | typedef char* (*AddOnGetDVDMenuLanguage)(const void* addonData); | ||
| 42 | typedef void (*AddOnFreeString)(const void* addonData, char* str); | ||
| 43 | |||
| 44 | typedef void* (*AddOnOpenFile)(const void* addonData, const char* strFileName, unsigned int flags); | ||
| 45 | typedef void* (*AddOnOpenFileForWrite)(const void* addonData, const char* strFileName, bool bOverWrite); | ||
| 46 | typedef ssize_t (*AddOnReadFile)(const void* addonData, void* file, void* lpBuf, size_t uiBufSize); | ||
| 47 | typedef bool (*AddOnReadFileString)(const void* addonData, void* file, char *szLine, int iLineLength); | ||
| 48 | typedef ssize_t (*AddOnWriteFile)(const void* addonData, void* file, const void* lpBuf, size_t uiBufSize); | ||
| 49 | typedef void (*AddOnFlushFile)(const void* addonData, void* file); | ||
| 50 | typedef int64_t (*AddOnSeekFile)(const void* addonData, void* file, int64_t iFilePosition, int iWhence); | ||
| 51 | typedef int (*AddOnTruncateFile)(const void* addonData, void* file, int64_t iSize); | ||
| 52 | typedef int64_t (*AddOnGetFilePosition)(const void* addonData, void* file); | ||
| 53 | typedef int64_t (*AddOnGetFileLength)(const void* addonData, void* file); | ||
| 54 | typedef void (*AddOnCloseFile)(const void* addonData, void* file); | ||
| 55 | typedef int (*AddOnGetFileChunkSize)(const void* addonData, void* file); | ||
| 56 | typedef bool (*AddOnFileExists)(const void* addonData, const char *strFileName, bool bUseCache); | ||
| 57 | typedef int (*AddOnStatFile)(const void* addonData, const char *strFileName, struct __stat64* buffer); | ||
| 58 | typedef bool (*AddOnDeleteFile)(const void* addonData, const char *strFileName); | ||
| 59 | typedef bool (*AddOnCanOpenDirectory)(const void* addonData, const char* strURL); | ||
| 60 | typedef bool (*AddOnCreateDirectory)(const void* addonData, const char *strPath); | ||
| 61 | typedef bool (*AddOnDirectoryExists)(const void* addonData, const char *strPath); | ||
| 62 | typedef bool (*AddOnRemoveDirectory)(const void* addonData, const char *strPath); | ||
| 63 | |||
| 64 | typedef 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 | |||
| 96 | typedef xbmc_codec_t (*CODECGetCodecByName)(const void* addonData, const char* strCodecName); | ||
| 97 | |||
| 98 | typedef struct CB_CODEC | ||
| 99 | { | ||
| 100 | CODECGetCodecByName GetCodecByName; | ||
| 101 | } CB_CODECLib; | ||
| 102 | |||
| 103 | typedef void (*GUILock)(); | ||
| 104 | typedef void (*GUIUnlock)(); | ||
| 105 | typedef int (*GUIGetScreenHeight)(); | ||
| 106 | typedef int (*GUIGetScreenWidth)(); | ||
| 107 | typedef int (*GUIGetVideoResolution)(); | ||
| 108 | typedef GUIHANDLE (*GUIWindow_New)(void *addonData, const char *xmlFilename, const char *defaultSkin, bool forceFallback, bool asDialog); | ||
| 109 | typedef void (*GUIWindow_Delete)(void *addonData, GUIHANDLE handle); | ||
| 110 | typedef void (*GUIWindow_SetCallbacks)(void *addonData, GUIHANDLE handle, GUIHANDLE clienthandle, bool (*)(GUIHANDLE handle), bool (*)(GUIHANDLE handle, int), bool (*)(GUIHANDLE handle, int), bool (*)(GUIHANDLE handle, int)); | ||
| 111 | typedef bool (*GUIWindow_Show)(void *addonData, GUIHANDLE handle); | ||
| 112 | typedef bool (*GUIWindow_Close)(void *addonData, GUIHANDLE handle); | ||
| 113 | typedef bool (*GUIWindow_DoModal)(void *addonData, GUIHANDLE handle); | ||
| 114 | typedef bool (*GUIWindow_SetFocusId)(void *addonData, GUIHANDLE handle, int iControlId); | ||
| 115 | typedef int (*GUIWindow_GetFocusId)(void *addonData, GUIHANDLE handle); | ||
| 116 | typedef bool (*GUIWindow_SetCoordinateResolution)(void *addonData, GUIHANDLE handle, int res); | ||
| 117 | typedef void (*GUIWindow_SetProperty)(void *addonData, GUIHANDLE handle, const char *key, const char *value); | ||
| 118 | typedef void (*GUIWindow_SetPropertyInt)(void *addonData, GUIHANDLE handle, const char *key, int value); | ||
| 119 | typedef void (*GUIWindow_SetPropertyBool)(void *addonData, GUIHANDLE handle, const char *key, bool value); | ||
| 120 | typedef void (*GUIWindow_SetPropertyDouble)(void *addonData, GUIHANDLE handle, const char *key, double value); | ||
| 121 | typedef const char* (*GUIWindow_GetProperty)(void *addonData, GUIHANDLE handle, const char *key); | ||
| 122 | typedef int (*GUIWindow_GetPropertyInt)(void *addonData, GUIHANDLE handle, const char *key); | ||
| 123 | typedef bool (*GUIWindow_GetPropertyBool)(void *addonData, GUIHANDLE handle, const char *key); | ||
| 124 | typedef double (*GUIWindow_GetPropertyDouble)(void *addonData, GUIHANDLE handle, const char *key); | ||
| 125 | typedef void (*GUIWindow_ClearProperties)(void *addonData, GUIHANDLE handle); | ||
| 126 | typedef int (*GUIWindow_GetListSize)(void *addonData, GUIHANDLE handle); | ||
| 127 | typedef void (*GUIWindow_ClearList)(void *addonData, GUIHANDLE handle); | ||
| 128 | typedef GUIHANDLE (*GUIWindow_AddItem)(void *addonData, GUIHANDLE handle, GUIHANDLE item, int itemPosition); | ||
| 129 | typedef GUIHANDLE (*GUIWindow_AddStringItem)(void *addonData, GUIHANDLE handle, const char *itemName, int itemPosition); | ||
| 130 | typedef void (*GUIWindow_RemoveItem)(void *addonData, GUIHANDLE handle, int itemPosition); | ||
| 131 | typedef GUIHANDLE (*GUIWindow_GetListItem)(void *addonData, GUIHANDLE handle, int listPos); | ||
| 132 | typedef void (*GUIWindow_SetCurrentListPosition)(void *addonData, GUIHANDLE handle, int listPos); | ||
| 133 | typedef int (*GUIWindow_GetCurrentListPosition)(void *addonData, GUIHANDLE handle); | ||
| 134 | typedef GUIHANDLE (*GUIWindow_GetControl_Spin)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 135 | typedef GUIHANDLE (*GUIWindow_GetControl_Button)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 136 | typedef GUIHANDLE (*GUIWindow_GetControl_RadioButton)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 137 | typedef GUIHANDLE (*GUIWindow_GetControl_Edit)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 138 | typedef GUIHANDLE (*GUIWindow_GetControl_Progress)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 139 | typedef GUIHANDLE (*GUIWindow_GetControl_RenderAddon)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 140 | typedef void (*GUIWindow_SetControlLabel)(void *addonData, GUIHANDLE handle, int controlId, const char *label); | ||
| 141 | typedef void (*GUIWindow_MarkDirtyRegion)(void *addonData, GUIHANDLE handle); | ||
| 142 | typedef void (*GUIControl_Spin_SetVisible)(void *addonData, GUIHANDLE spinhandle, bool yesNo); | ||
| 143 | typedef void (*GUIControl_Spin_SetText)(void *addonData, GUIHANDLE spinhandle, const char *label); | ||
| 144 | typedef void (*GUIControl_Spin_Clear)(void *addonData, GUIHANDLE spinhandle); | ||
| 145 | typedef void (*GUIControl_Spin_AddLabel)(void *addonData, GUIHANDLE spinhandle, const char *label, int iValue); | ||
| 146 | typedef int (*GUIControl_Spin_GetValue)(void *addonData, GUIHANDLE spinhandle); | ||
| 147 | typedef void (*GUIControl_Spin_SetValue)(void *addonData, GUIHANDLE spinhandle, int iValue); | ||
| 148 | typedef void (*GUIControl_RadioButton_SetVisible)(void *addonData, GUIHANDLE handle, bool yesNo); | ||
| 149 | typedef void (*GUIControl_RadioButton_SetText)(void *addonData, GUIHANDLE handle, const char *label); | ||
| 150 | typedef void (*GUIControl_RadioButton_SetSelected)(void *addonData, GUIHANDLE handle, bool yesNo); | ||
| 151 | typedef bool (*GUIControl_RadioButton_IsSelected)(void *addonData, GUIHANDLE handle); | ||
| 152 | typedef void (*GUIControl_Progress_SetPercentage)(void *addonData, GUIHANDLE handle, float fPercent); | ||
| 153 | typedef float (*GUIControl_Progress_GetPercentage)(void *addonData, GUIHANDLE handle); | ||
| 154 | typedef void (*GUIControl_Progress_SetInfo)(void *addonData, GUIHANDLE handle, int iInfo); | ||
| 155 | typedef int (*GUIControl_Progress_GetInfo)(void *addonData, GUIHANDLE handle); | ||
| 156 | typedef const char* (*GUIControl_Progress_GetDescription)(void *addonData, GUIHANDLE handle); | ||
| 157 | typedef GUIHANDLE (*GUIWindow_GetControl_Slider)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 158 | typedef void (*GUIControl_Slider_SetVisible)(void *addonData, GUIHANDLE handle, bool yesNo); | ||
| 159 | typedef const char *(*GUIControl_Slider_GetDescription)(void *addonData, GUIHANDLE handle); | ||
| 160 | typedef void (*GUIControl_Slider_SetIntRange)(void *addonData, GUIHANDLE handle, int iStart, int iEnd); | ||
| 161 | typedef void (*GUIControl_Slider_SetIntValue)(void *addonData, GUIHANDLE handle, int iValue); | ||
| 162 | typedef int (*GUIControl_Slider_GetIntValue)(void *addonData, GUIHANDLE handle); | ||
| 163 | typedef void (*GUIControl_Slider_SetIntInterval)(void *addonData, GUIHANDLE handle, int iInterval); | ||
| 164 | typedef void (*GUIControl_Slider_SetPercentage)(void *addonData, GUIHANDLE handle, float fPercent); | ||
| 165 | typedef float (*GUIControl_Slider_GetPercentage)(void *addonData, GUIHANDLE handle); | ||
| 166 | typedef void (*GUIControl_Slider_SetFloatRange)(void *addonData, GUIHANDLE handle, float fStart, float fEnd); | ||
| 167 | typedef void (*GUIControl_Slider_SetFloatValue)(void *addonData, GUIHANDLE handle, float fValue); | ||
| 168 | typedef float (*GUIControl_Slider_GetFloatValue)(void *addonData, GUIHANDLE handle); | ||
| 169 | typedef void (*GUIControl_Slider_SetFloatInterval)(void *addonData, GUIHANDLE handle, float fInterval); | ||
| 170 | typedef GUIHANDLE (*GUIWindow_GetControl_SettingsSlider)(void *addonData, GUIHANDLE handle, int controlId); | ||
| 171 | typedef void (*GUIControl_SettingsSlider_SetVisible)(void *addonData, GUIHANDLE handle, bool yesNo); | ||
| 172 | typedef void (*GUIControl_SettingsSlider_SetText)(void *addonData, GUIHANDLE handle, const char *label); | ||
| 173 | typedef const char *(*GUIControl_SettingsSlider_GetDescription)(void *addonData, GUIHANDLE handle); | ||
| 174 | typedef void (*GUIControl_SettingsSlider_SetIntRange)(void *addonData, GUIHANDLE handle, int iStart, int iEnd); | ||
| 175 | typedef void (*GUIControl_SettingsSlider_SetIntValue)(void *addonData, GUIHANDLE handle, int iValue); | ||
| 176 | typedef int (*GUIControl_SettingsSlider_GetIntValue)(void *addonData, GUIHANDLE handle); | ||
| 177 | typedef void (*GUIControl_SettingsSlider_SetIntInterval)(void *addonData, GUIHANDLE handle, int iInterval); | ||
| 178 | typedef void (*GUIControl_SettingsSlider_SetPercentage)(void *addonData, GUIHANDLE handle, float fPercent); | ||
| 179 | typedef float (*GUIControl_SettingsSlider_GetPercentage)(void *addonData, GUIHANDLE handle); | ||
| 180 | typedef void (*GUIControl_SettingsSlider_SetFloatRange)(void *addonData, GUIHANDLE handle, float fStart, float fEnd); | ||
| 181 | typedef void (*GUIControl_SettingsSlider_SetFloatValue)(void *addonData, GUIHANDLE handle, float fValue); | ||
| 182 | typedef float (*GUIControl_SettingsSlider_GetFloatValue)(void *addonData, GUIHANDLE handle); | ||
| 183 | typedef void (*GUIControl_SettingsSlider_SetFloatInterval)(void *addonData, GUIHANDLE handle, float fInterval); | ||
| 184 | typedef GUIHANDLE (*GUIListItem_Create)(void *addonData, const char *label, const char *label2, const char *iconImage, const char *thumbnailImage, const char *path); | ||
| 185 | typedef const char* (*GUIListItem_GetLabel)(void *addonData, GUIHANDLE handle); | ||
| 186 | typedef void (*GUIListItem_SetLabel)(void *addonData, GUIHANDLE handle, const char *label); | ||
| 187 | typedef const char* (*GUIListItem_GetLabel2)(void *addonData, GUIHANDLE handle); | ||
| 188 | typedef void (*GUIListItem_SetLabel2)(void *addonData, GUIHANDLE handle, const char *label); | ||
| 189 | typedef void (*GUIListItem_SetIconImage)(void *addonData, GUIHANDLE handle, const char *image); | ||
| 190 | typedef void (*GUIListItem_SetThumbnailImage)(void *addonData, GUIHANDLE handle, const char *image); | ||
| 191 | typedef void (*GUIListItem_SetInfo)(void *addonData, GUIHANDLE handle, const char *info); | ||
| 192 | typedef void (*GUIListItem_SetProperty)(void *addonData, GUIHANDLE handle, const char *key, const char *value); | ||
| 193 | typedef const char* (*GUIListItem_GetProperty)(void *addonData, GUIHANDLE handle, const char *key); | ||
| 194 | typedef void (*GUIListItem_SetPath)(void *addonData, GUIHANDLE handle, const char *path); | ||
| 195 | typedef 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)); | ||
| 196 | typedef void (*GUIRenderAddon_Delete)(void *addonData, GUIHANDLE handle); | ||
| 197 | typedef void (*GUIRenderAddon_MarkDirty)(void *addonData, GUIHANDLE handle); | ||
| 198 | |||
| 199 | typedef bool (*GUIDialog_Keyboard_ShowAndGetInputWithHead)(char &strTextString, unsigned int iMaxStringSize, const char *heading, bool allowEmptyResult, bool hiddenInput, unsigned int autoCloseMs); | ||
| 200 | typedef bool (*GUIDialog_Keyboard_ShowAndGetInput)(char &strTextString, unsigned int iMaxStringSize, bool allowEmptyResult, unsigned int autoCloseMs); | ||
| 201 | typedef bool (*GUIDialog_Keyboard_ShowAndGetNewPasswordWithHead)(char &newPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmptyResult, unsigned int autoCloseMs); | ||
| 202 | typedef bool (*GUIDialog_Keyboard_ShowAndGetNewPassword)(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs); | ||
| 203 | typedef bool (*GUIDialog_Keyboard_ShowAndVerifyNewPasswordWithHead)(char &strNewPassword, unsigned int iMaxStringSize, const char *strHeading, bool allowEmpty, unsigned int autoCloseMs); | ||
| 204 | typedef bool (*GUIDialog_Keyboard_ShowAndVerifyNewPassword)(char &strNewPassword, unsigned int iMaxStringSize, unsigned int autoCloseMs); | ||
| 205 | typedef int (*GUIDialog_Keyboard_ShowAndVerifyPassword)(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries, unsigned int autoCloseMs); | ||
| 206 | typedef bool (*GUIDialog_Keyboard_ShowAndGetFilter)(char &aTextString, unsigned int iMaxStringSize, bool searching, unsigned int autoCloseMs); | ||
| 207 | typedef bool (*GUIDialog_Keyboard_SendTextToActiveKeyboard)(const char *aTextString, bool closeKeyboard); | ||
| 208 | typedef bool (*GUIDialog_Keyboard_isKeyboardActivated)(); | ||
| 209 | |||
| 210 | typedef bool (*GUIDialog_Numeric_ShowAndVerifyNewPassword)(char &strNewPassword, unsigned int iMaxStringSize); | ||
| 211 | typedef int (*GUIDialog_Numeric_ShowAndVerifyPassword)(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, int iRetries); | ||
| 212 | typedef bool (*GUIDialog_Numeric_ShowAndVerifyInput)(char &strPassword, unsigned int iMaxStringSize, const char *strHeading, bool bGetUserInput); | ||
| 213 | typedef bool (*GUIDialog_Numeric_ShowAndGetTime)(tm &time, const char *strHeading); | ||
| 214 | typedef bool (*GUIDialog_Numeric_ShowAndGetDate)(tm &date, const char *strHeading); | ||
| 215 | typedef bool (*GUIDialog_Numeric_ShowAndGetIPAddress)(char &strIPAddress, unsigned int iMaxStringSize, const char *strHeading); | ||
| 216 | typedef bool (*GUIDialog_Numeric_ShowAndGetNumber)(char &strInput, unsigned int iMaxStringSize, const char *strHeading, unsigned int iAutoCloseTimeoutMs); | ||
| 217 | typedef bool (*GUIDialog_Numeric_ShowAndGetSeconds)(char &timeString, unsigned int iMaxStringSize, const char *strHeading); | ||
| 218 | |||
| 219 | typedef 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 | |||
| 221 | typedef void (*GUIDialog_OK_ShowAndGetInputSingleText)(const char *heading, const char *text); | ||
| 222 | typedef void (*GUIDialog_OK_ShowAndGetInputLineText)(const char *heading, const char *line0, const char *line1, const char *line2); | ||
| 223 | |||
| 224 | typedef bool (*GUIDialog_YesNo_ShowAndGetInputSingleText)(const char *heading, const char *text, bool& bCanceled, const char *noLabel, const char *yesLabel); | ||
| 225 | typedef bool (*GUIDialog_YesNo_ShowAndGetInputLineText)(const char *heading, const char *line0, const char *line1, const char *line2, const char *noLabel, const char *yesLabel); | ||
| 226 | typedef 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 | |||
| 228 | typedef void (*GUIDialog_TextViewer)(const char *heading, const char *text); | ||
| 229 | |||
| 230 | typedef int (*GUIDialog_Select)(const char *heading, const char *entries[], unsigned int size, int selected); | ||
| 231 | |||
| 232 | typedef 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 | |||
| 364 | typedef void (*PVRTransferEpgEntry)(void *userData, const ADDON_HANDLE handle, const EPG_TAG *epgentry); | ||
| 365 | typedef void (*PVRTransferChannelEntry)(void *userData, const ADDON_HANDLE handle, const PVR_CHANNEL *chan); | ||
| 366 | typedef void (*PVRTransferTimerEntry)(void *userData, const ADDON_HANDLE handle, const PVR_TIMER *timer); | ||
| 367 | typedef void (*PVRTransferRecordingEntry)(void *userData, const ADDON_HANDLE handle, const PVR_RECORDING *recording); | ||
| 368 | typedef void (*PVRAddMenuHook)(void *addonData, PVR_MENUHOOK *hook); | ||
| 369 | typedef void (*PVRRecording)(void *addonData, const char *Name, const char *FileName, bool On); | ||
| 370 | typedef void (*PVRTriggerChannelUpdate)(void *addonData); | ||
| 371 | typedef void (*PVRTriggerTimerUpdate)(void *addonData); | ||
| 372 | typedef void (*PVRTriggerRecordingUpdate)(void *addonData); | ||
| 373 | typedef void (*PVRTriggerChannelGroupsUpdate)(void *addonData); | ||
| 374 | typedef void (*PVRTriggerEpgUpdate)(void *addonData, unsigned int iChannelUid); | ||
| 375 | |||
| 376 | typedef void (*PVRTransferChannelGroup)(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group); | ||
| 377 | typedef void (*PVRTransferChannelGroupMember)(void *addonData, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP_MEMBER *member); | ||
| 378 | |||
| 379 | typedef void (*PVRFreeDemuxPacket)(void *addonData, DemuxPacket* pPacket); | ||
| 380 | typedef DemuxPacket* (*PVRAllocateDemuxPacket)(void *addonData, int iDataSize); | ||
| 381 | |||
| 382 | typedef 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 | |||
| 403 | typedef CB_AddOnLib* (*XBMCAddOnLib_RegisterMe)(void *addonData); | ||
| 404 | typedef void (*XBMCAddOnLib_UnRegisterMe)(void *addonData, CB_AddOnLib *cbTable); | ||
| 405 | typedef CB_CODECLib* (*XBMCCODECLib_RegisterMe)(void *addonData); | ||
| 406 | typedef void (*XBMCCODECLib_UnRegisterMe)(void *addonData, CB_CODECLib *cbTable); | ||
| 407 | typedef CB_GUILib* (*XBMCGUILib_RegisterMe)(void *addonData); | ||
| 408 | typedef void (*XBMCGUILib_UnRegisterMe)(void *addonData, CB_GUILib *cbTable); | ||
| 409 | typedef CB_PVRLib* (*XBMCPVRLib_RegisterMe)(void *addonData); | ||
| 410 | typedef void (*XBMCPVRLib_UnRegisterMe)(void *addonData, CB_PVRLib *cbTable); | ||
| 411 | |||
| 412 | typedef 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 | |||
| 427 | namespace ADDON | ||
| 428 | { | ||
| 429 | |||
| 430 | class CAddon; | ||
| 431 | class CAddonCallbacksAddon; | ||
| 432 | class CAddonCallbacksCodec; | ||
| 433 | class CAddonCallbacksGUI; | ||
| 434 | class CAddonCallbacksPVR; | ||
| 435 | |||
| 436 | class CAddonCallbacks | ||
| 437 | { | ||
| 438 | public: | ||
| 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 | |||
| 457 | private: | ||
| 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 | |||
| 37 | using namespace XFILE; | ||
| 38 | |||
| 39 | namespace ADDON | ||
| 40 | { | ||
| 41 | |||
| 42 | CAddonCallbacksAddon::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 | |||
| 79 | CAddonCallbacksAddon::~CAddonCallbacksAddon() | ||
| 80 | { | ||
| 81 | /* delete the callback table */ | ||
| 82 | delete m_callbacks; | ||
| 83 | } | ||
| 84 | |||
| 85 | void 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 | |||
| 126 | void 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 | |||
| 165 | bool CAddonCallbacksAddon::WakeOnLan(const char *mac) | ||
| 166 | { | ||
| 167 | return g_application.getNetwork().WakeOnLan(mac); | ||
| 168 | } | ||
| 169 | |||
| 170 | bool 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 | |||
| 255 | char* 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 | |||
| 266 | char* 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 | |||
| 286 | char* 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 | |||
| 298 | void CAddonCallbacksAddon::FreeString(const void* addonData, char* str) | ||
| 299 | { | ||
| 300 | free(str); | ||
| 301 | } | ||
| 302 | |||
| 303 | void* 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 | |||
| 317 | void* 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 | |||
| 331 | ssize_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 | |||
| 344 | bool 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 | |||
| 357 | ssize_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 | |||
| 370 | void 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 | |||
| 383 | int64_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 | |||
| 396 | int 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 | |||
| 409 | int64_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 | |||
| 422 | int64_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 | |||
| 435 | void 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 | |||
| 449 | int 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 | |||
| 462 | bool 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 | |||
| 471 | int 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 | |||
| 480 | bool 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 | |||
| 489 | bool 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 | |||
| 499 | bool 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 | |||
| 508 | bool 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 | |||
| 517 | bool 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 | |||
| 24 | namespace ADDON | ||
| 25 | { | ||
| 26 | |||
| 27 | class CAddonCallbacksAddon | ||
| 28 | { | ||
| 29 | public: | ||
| 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 | |||
| 68 | private: | ||
| 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 | |||
| 26 | extern "C" { | ||
| 27 | #include "libavcodec/avcodec.h" | ||
| 28 | #include "libavformat/avformat.h" | ||
| 29 | } | ||
| 30 | |||
| 31 | namespace ADDON | ||
| 32 | { | ||
| 33 | class CCodecIds | ||
| 34 | { | ||
| 35 | public: | ||
| 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 | |||
| 60 | private: | ||
| 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 | |||
| 94 | CAddonCallbacksCodec::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 | |||
| 103 | CAddonCallbacksCodec::~CAddonCallbacksCodec() | ||
| 104 | { | ||
| 105 | /* delete the callback table */ | ||
| 106 | delete m_callbacks; | ||
| 107 | } | ||
| 108 | |||
| 109 | xbmc_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 | |||
| 24 | namespace ADDON | ||
| 25 | { | ||
| 26 | |||
| 27 | class CAddonCallbacksCodec | ||
| 28 | { | ||
| 29 | public: | ||
| 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 | |||
| 40 | private: | ||
| 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 | |||
| 54 | using namespace std; | ||
| 55 | |||
| 56 | namespace ADDON | ||
| 57 | { | ||
| 58 | |||
| 59 | static int iXBMCGUILockRef = 0; | ||
| 60 | |||
| 61 | CAddonCallbacksGUI::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 | |||
| 206 | CAddonCallbacksGUI::~CAddonCallbacksGUI() | ||
| 207 | { | ||
| 208 | delete m_callbacks; | ||
| 209 | } | ||
| 210 | |||
| 211 | void CAddonCallbacksGUI::Lock() | ||
| 212 | { | ||
| 213 | if (iXBMCGUILockRef == 0) g_graphicsContext.Lock(); | ||
| 214 | iXBMCGUILockRef++; | ||
| 215 | } | ||
| 216 | |||
| 217 | void CAddonCallbacksGUI::Unlock() | ||
| 218 | { | ||
| 219 | if (iXBMCGUILockRef > 0) | ||
| 220 | { | ||
| 221 | iXBMCGUILockRef--; | ||
| 222 | if (iXBMCGUILockRef == 0) g_graphicsContext.Unlock(); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | int CAddonCallbacksGUI::GetScreenHeight() | ||
| 227 | { | ||
| 228 | return g_graphicsContext.GetHeight(); | ||
| 229 | } | ||
| 230 | |||
| 231 | int CAddonCallbacksGUI::GetScreenWidth() | ||
| 232 | { | ||
| 233 | return g_graphicsContext.GetWidth(); | ||
| 234 | } | ||
| 235 | |||
| 236 | int CAddonCallbacksGUI::GetVideoResolution() | ||
| 237 | { | ||
| 238 | return (int)g_graphicsContext.GetVideoResolution(); | ||
| 239 | } | ||
| 240 | |||
| 241 | GUIHANDLE 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 | |||
| 322 | void 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 | |||
| 360 | void 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 | |||
| 377 | bool 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 | |||
| 409 | bool 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 | |||
| 447 | bool 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 | |||
| 474 | bool 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 | |||
| 507 | int 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 | |||
| 541 | bool 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 | |||
| 571 | void 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 | |||
| 598 | void 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 | |||
| 625 | void 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 | |||
| 652 | void 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 | |||
| 679 | const 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 | |||
| 708 | int 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 | |||
| 737 | bool 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 | |||
| 766 | double 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 | |||
| 795 | void 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 | |||
| 819 | int 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 | |||
| 834 | void 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 | |||
| 849 | GUIHANDLE 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 | |||
| 864 | GUIHANDLE 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 | |||
| 879 | void 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 | |||
| 894 | GUIHANDLE 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 | |||
| 916 | void 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 | |||
| 931 | int 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 | |||
| 946 | GUIHANDLE 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 | |||
| 960 | GUIHANDLE 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 | |||
| 974 | GUIHANDLE 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 | |||
| 988 | GUIHANDLE 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 | |||
| 1002 | GUIHANDLE 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 | |||
| 1016 | GUIHANDLE 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 | |||
| 1032 | void 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 | |||
| 1045 | void 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 | |||
| 1056 | void 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 | |||
| 1066 | void 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 | |||
| 1076 | void 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 | |||
| 1086 | void 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 | |||
| 1096 | int 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 | |||
| 1106 | void 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 | |||
| 1116 | void 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 | |||
| 1126 | void 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 | |||
| 1136 | void 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 | |||
| 1146 | bool 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 | |||
| 1156 | void 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 | |||
| 1166 | float 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 | |||
| 1176 | void 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 | |||
| 1186 | int 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 | |||
| 1196 | const 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 | */ | ||
| 1213 | GUIHANDLE 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 | |||
| 1227 | void 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 | |||
| 1237 | const 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 | |||
| 1251 | void 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 | |||
| 1261 | void 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 | |||
| 1272 | int 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 | |||
| 1282 | void 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 | |||
| 1292 | void 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 | |||
| 1303 | float 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 | |||
| 1313 | void 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 | |||
| 1323 | void 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 | |||
| 1334 | float 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 | |||
| 1344 | void 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 | */ | ||
| 1357 | GUIHANDLE 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 | |||
| 1371 | void 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 | |||
| 1381 | void 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 | |||
| 1391 | const 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 | |||
| 1405 | void 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 | |||
| 1415 | void 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 | |||
| 1426 | int 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 | |||
| 1436 | void 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 | |||
| 1446 | void 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 | |||
| 1457 | float 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 | |||
| 1467 | void 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 | |||
| 1477 | void 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 | |||
| 1488 | float 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 | |||
| 1498 | void 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 | */ | ||
| 1511 | GUIHANDLE 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 | |||
| 1536 | const 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 | |||
| 1548 | void 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 | |||
| 1557 | const 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 | |||
| 1570 | void 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 | |||
| 1579 | void 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 | |||
| 1588 | void 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 | |||
| 1597 | void 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 | |||
| 1605 | void 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 | |||
| 1614 | const 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 | |||
| 1626 | void 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 | |||
| 1635 | void 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 | |||
| 1654 | void 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 | //@{ | ||
| 1669 | bool 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 | |||
| 1678 | bool 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 | |||
| 1687 | bool 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 | |||
| 1696 | bool 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 | |||
| 1705 | bool 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 | |||
| 1714 | bool 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 | |||
| 1723 | int 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 | |||
| 1732 | bool 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 | |||
| 1741 | bool CAddonCallbacksGUI::Dialog_Keyboard_SendTextToActiveKeyboard(const char *aTextString, bool closeKeyboard) | ||
| 1742 | { | ||
| 1743 | return CGUIKeyboardFactory::SendTextToActiveKeyboard(aTextString, closeKeyboard); | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | bool CAddonCallbacksGUI::Dialog_Keyboard_isKeyboardActivated() | ||
| 1747 | { | ||
| 1748 | return CGUIKeyboardFactory::isKeyboardActivated(); | ||
| 1749 | } | ||
| 1750 | //@} | ||
| 1751 | |||
| 1752 | /*! @name GUI Numeric functions */ | ||
| 1753 | //@{ | ||
| 1754 | bool 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 | |||
| 1763 | int 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 | |||
| 1772 | bool 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 | |||
| 1781 | bool 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 | |||
| 1795 | bool 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 | |||
| 1809 | bool 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 | |||
| 1818 | bool 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 | |||
| 1827 | bool 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 | //@{ | ||
| 1839 | bool 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 | //@{ | ||
| 1851 | void CAddonCallbacksGUI::Dialog_OK_ShowAndGetInputSingleText(const char *heading, const char *text) | ||
| 1852 | { | ||
| 1853 | CGUIDialogOK::ShowAndGetInput(heading, text); | ||
| 1854 | } | ||
| 1855 | |||
| 1856 | void 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 | //@{ | ||
| 1864 | bool 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 | |||
| 1869 | bool 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 | |||
| 1874 | bool 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 | //@{ | ||
| 1882 | void 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 | //@{ | ||
| 1893 | int 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 | |||
| 1910 | CGUIAddonWindow::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 | |||
| 1926 | CGUIAddonWindow::~CGUIAddonWindow(void) | ||
| 1927 | { | ||
| 1928 | } | ||
| 1929 | |||
| 1930 | bool 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 | |||
| 1939 | bool 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 | |||
| 2042 | void 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 | |||
| 2056 | void CGUIAddonWindow::FreeResources(bool forceUnLoad /*= FALSE */) | ||
| 2057 | { | ||
| 2058 | CGUIMediaWindow::FreeResources(forceUnLoad); | ||
| 2059 | } | ||
| 2060 | |||
| 2061 | void CGUIAddonWindow::Render() | ||
| 2062 | { | ||
| 2063 | g_TextureManager.AddTexturePath(m_mediaDir); | ||
| 2064 | CGUIMediaWindow::Render(); | ||
| 2065 | g_TextureManager.RemoveTexturePath(m_mediaDir); | ||
| 2066 | } | ||
| 2067 | |||
| 2068 | void CGUIAddonWindow::Update() | ||
| 2069 | { | ||
| 2070 | } | ||
| 2071 | |||
| 2072 | void 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 | |||
| 2090 | void CGUIAddonWindow::RemoveItem(int itemPosition) | ||
| 2091 | { | ||
| 2092 | m_vecItems->Remove(itemPosition); | ||
| 2093 | m_viewControl.SetItems(*m_vecItems); | ||
| 2094 | UpdateButtons(); | ||
| 2095 | } | ||
| 2096 | |||
| 2097 | int CGUIAddonWindow::GetCurrentListPosition() | ||
| 2098 | { | ||
| 2099 | return m_viewControl.GetSelectedItem(); | ||
| 2100 | } | ||
| 2101 | |||
| 2102 | void CGUIAddonWindow::SetCurrentListPosition(int item) | ||
| 2103 | { | ||
| 2104 | m_viewControl.SetSelectedItem(item); | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | int CGUIAddonWindow::GetListSize() | ||
| 2108 | { | ||
| 2109 | return m_vecItems->Size(); | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | CFileItemPtr CGUIAddonWindow::GetListItem(int position) | ||
| 2113 | { | ||
| 2114 | if (position < 0 || position >= m_vecItems->Size()) return CFileItemPtr(); | ||
| 2115 | return m_vecItems->Get(position); | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | void CGUIAddonWindow::ClearList() | ||
| 2119 | { | ||
| 2120 | ClearFileItems(); | ||
| 2121 | |||
| 2122 | m_viewControl.SetItems(*m_vecItems); | ||
| 2123 | UpdateButtons(); | ||
| 2124 | } | ||
| 2125 | |||
| 2126 | void 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 | |||
| 2132 | void CGUIAddonWindow::WaitForActionEvent(unsigned int timeout) | ||
| 2133 | { | ||
| 2134 | m_actionEvent.WaitMSec(timeout); | ||
| 2135 | m_actionEvent.Reset(); | ||
| 2136 | } | ||
| 2137 | |||
| 2138 | void CGUIAddonWindow::PulseActionEvent() | ||
| 2139 | { | ||
| 2140 | m_actionEvent.Set(); | ||
| 2141 | } | ||
| 2142 | |||
| 2143 | bool 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 | ||
| 2153 | and just call UpdateButtons(); | ||
| 2154 | */ | ||
| 2155 | void CGUIAddonWindow::SetupShares() | ||
| 2156 | { | ||
| 2157 | UpdateButtons(); | ||
| 2158 | } | ||
| 2159 | |||
| 2160 | |||
| 2161 | CGUIAddonWindowDialog::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 | |||
| 2168 | CGUIAddonWindowDialog::~CGUIAddonWindowDialog(void) | ||
| 2169 | { | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | bool 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 | |||
| 2184 | void 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 | |||
| 2193 | void 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 | |||
| 2224 | CGUIAddonRenderingControl::CGUIAddonRenderingControl(CGUIRenderingControl *pControl) | ||
| 2225 | { | ||
| 2226 | m_pControl = pControl; | ||
| 2227 | m_refCount = 1; | ||
| 2228 | } | ||
| 2229 | |||
| 2230 | bool 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 | |||
| 2243 | void CGUIAddonRenderingControl::Render() | ||
| 2244 | { | ||
| 2245 | if (CBRender) | ||
| 2246 | { | ||
| 2247 | g_graphicsContext.BeginPaint(); | ||
| 2248 | CBRender(m_clientHandle); | ||
| 2249 | g_graphicsContext.EndPaint(); | ||
| 2250 | } | ||
| 2251 | } | ||
| 2252 | |||
| 2253 | void 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 | |||
| 2264 | void CGUIAddonRenderingControl::Delete() | ||
| 2265 | { | ||
| 2266 | m_refCount--; | ||
| 2267 | if (m_refCount <= 0) | ||
| 2268 | delete this; | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | bool 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 | |||
| 28 | class CGUISpinControlEx; | ||
| 29 | class CGUIButtonControl; | ||
| 30 | class CGUIRadioButtonControl; | ||
| 31 | class CGUISliderControl; | ||
| 32 | class CGUISettingsSliderControl; | ||
| 33 | class CGUIEditControl; | ||
| 34 | class CGUIRenderingControl; | ||
| 35 | |||
| 36 | namespace ADDON | ||
| 37 | { | ||
| 38 | |||
| 39 | class CAddonCallbacksGUI | ||
| 40 | { | ||
| 41 | public: | ||
| 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 | |||
| 180 | private: | ||
| 181 | CB_GUILib *m_callbacks; | ||
| 182 | CAddon *m_addon; | ||
| 183 | }; | ||
| 184 | |||
| 185 | class CGUIAddonWindow : public CGUIMediaWindow | ||
| 186 | { | ||
| 187 | friend class CAddonCallbacksGUI; | ||
| 188 | |||
| 189 | public: | ||
| 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 | |||
| 209 | protected: | ||
| 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 | |||
| 225 | private: | ||
| 226 | CEvent m_actionEvent; | ||
| 227 | CAddon *m_addon; | ||
| 228 | std::string m_mediaDir; | ||
| 229 | }; | ||
| 230 | |||
| 231 | class CGUIAddonWindowDialog : public CGUIAddonWindow | ||
| 232 | { | ||
| 233 | public: | ||
| 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 | |||
| 246 | private: | ||
| 247 | bool m_bRunning; | ||
| 248 | }; | ||
| 249 | |||
| 250 | class CGUIAddonRenderingControl : public IRenderingCallback | ||
| 251 | { | ||
| 252 | friend class CAddonCallbacksGUI; | ||
| 253 | public: | ||
| 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(); | ||
| 261 | protected: | ||
| 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 | |||
| 37 | using namespace PVR; | ||
| 38 | using namespace EPG; | ||
| 39 | |||
| 40 | namespace ADDON | ||
| 41 | { | ||
| 42 | |||
| 43 | CAddonCallbacksPVR::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 | |||
| 66 | CAddonCallbacksPVR::~CAddonCallbacksPVR() | ||
| 67 | { | ||
| 68 | /* delete the callback table */ | ||
| 69 | delete m_callbacks; | ||
| 70 | } | ||
| 71 | |||
| 72 | CPVRClient *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 | |||
| 84 | void 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 | |||
| 110 | void 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 | |||
| 138 | void 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 | |||
| 157 | void 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 | |||
| 178 | void 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 | |||
| 199 | void 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 | |||
| 227 | void 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 | |||
| 249 | void 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 | |||
| 277 | void 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 | |||
| 283 | void 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 | |||
| 289 | void 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 | |||
| 295 | void 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 | |||
| 301 | void 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 | |||
| 314 | void CAddonCallbacksPVR::PVRFreeDemuxPacket(void *addonData, DemuxPacket* pPacket) | ||
| 315 | { | ||
| 316 | CDVDDemuxUtils::FreeDemuxPacket(pPacket); | ||
| 317 | } | ||
| 318 | |||
| 319 | DemuxPacket* 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 | |||
| 25 | namespace PVR | ||
| 26 | { | ||
| 27 | class CPVRClient; | ||
| 28 | } | ||
| 29 | |||
| 30 | namespace 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 | */ | ||
| 38 | class CAddonCallbacksPVR | ||
| 39 | { | ||
| 40 | public: | ||
| 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 | |||
| 159 | private: | ||
| 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 | |||
| 30 | using namespace ADDON; | ||
| 31 | using namespace std; | ||
| 32 | |||
| 33 | CAddonDatabase::CAddonDatabase() | ||
| 34 | { | ||
| 35 | } | ||
| 36 | |||
| 37 | CAddonDatabase::~CAddonDatabase() | ||
| 38 | { | ||
| 39 | } | ||
| 40 | |||
| 41 | bool CAddonDatabase::Open() | ||
| 42 | { | ||
| 43 | return CDatabase::Open(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void 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 | |||
| 81 | void 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 | |||
| 95 | void 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 | |||
| 108 | int 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 | |||
| 156 | AddonVersion 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 | |||
| 189 | bool 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 | |||
| 227 | bool 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 | |||
| 250 | bool 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 | |||
| 314 | bool 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 | |||
| 340 | void 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 | |||
| 358 | void 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 | |||
| 383 | int 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 | |||
| 416 | int 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 | |||
| 439 | CDateTime 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 | |||
| 463 | AddonVersion 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 | |||
| 485 | bool 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 | |||
| 505 | bool 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 | |||
| 530 | bool 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 | |||
| 549 | bool 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 | |||
| 581 | void 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 | |||
| 607 | bool 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 | |||
| 657 | bool 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 | |||
| 666 | bool 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 | |||
| 674 | bool 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 | |||
| 694 | bool 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 | |||
| 702 | std::string CAddonDatabase::IsAddonBroken(const std::string &addonID) | ||
| 703 | { | ||
| 704 | return GetSingleValue(PrepareSQL("SELECT reason FROM broken WHERE addonID='%s'", addonID.c_str())); | ||
| 705 | } | ||
| 706 | |||
| 707 | bool 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 | |||
| 726 | bool 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 | |||
| 746 | bool 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 | |||
| 753 | bool 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 | |||
| 772 | bool 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 | |||
| 782 | bool 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 | |||
| 792 | bool 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 | |||
| 27 | class CAddonDatabase : public CDatabase | ||
| 28 | { | ||
| 29 | public: | ||
| 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); | ||
| 139 | protected: | ||
| 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 | |||
| 39 | namespace 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 | |||
| 92 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 93 | CAddonDll<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 | |||
| 119 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 120 | CAddonDll<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 | |||
| 132 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 133 | CAddonDll<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 | |||
| 145 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 146 | CAddonDll<TheDll, TheStruct, TheProps>::~CAddonDll() | ||
| 147 | { | ||
| 148 | if (m_initialized) | ||
| 149 | Destroy(); | ||
| 150 | } | ||
| 151 | |||
| 152 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 153 | AddonPtr CAddonDll<TheDll, TheStruct, TheProps>::Clone() const | ||
| 154 | { | ||
| 155 | return AddonPtr(new CAddonDll<TheDll, TheStruct, TheProps>(*this)); | ||
| 156 | } | ||
| 157 | |||
| 158 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 159 | bool 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 | |||
| 225 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 226 | ADDON_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 | |||
| 274 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 275 | void 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 | |||
| 310 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 311 | void 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 | |||
| 341 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 342 | bool CAddonDll<TheDll, TheStruct, TheProps>::DllLoaded(void) const | ||
| 343 | { | ||
| 344 | return m_pDll != NULL; | ||
| 345 | } | ||
| 346 | |||
| 347 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 348 | ADDON_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 | |||
| 361 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 362 | bool 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 | |||
| 407 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 408 | TiXmlElement 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 | |||
| 442 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 443 | void 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 | |||
| 451 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 452 | std::string CAddonDll<TheDll, TheStruct, TheProps>::GetSetting(const std::string& key) | ||
| 453 | { | ||
| 454 | return CAddon::GetSetting(key); | ||
| 455 | } | ||
| 456 | |||
| 457 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 458 | ADDON_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 | |||
| 550 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 551 | void 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 | |||
| 563 | template<class TheDll, typename TheStruct, typename TheProps> | ||
| 564 | void 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 | |||
| 46 | using namespace std; | ||
| 47 | using namespace XFILE; | ||
| 48 | using namespace ADDON; | ||
| 49 | |||
| 50 | |||
| 51 | struct 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 | |||
| 59 | CAddonInstaller::CAddonInstaller() | ||
| 60 | : m_repoUpdateJob(0) | ||
| 61 | { } | ||
| 62 | |||
| 63 | CAddonInstaller::~CAddonInstaller() | ||
| 64 | { } | ||
| 65 | |||
| 66 | CAddonInstaller &CAddonInstaller::Get() | ||
| 67 | { | ||
| 68 | static CAddonInstaller addonInstaller; | ||
| 69 | return addonInstaller; | ||
| 70 | } | ||
| 71 | |||
| 72 | void 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 | |||
| 99 | void 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 | |||
| 114 | bool CAddonInstaller::IsDownloading() const | ||
| 115 | { | ||
| 116 | CSingleLock lock(m_critSection); | ||
| 117 | return !m_downloadJobs.empty(); | ||
| 118 | } | ||
| 119 | |||
| 120 | void 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 | |||
| 141 | bool 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 | |||
| 153 | bool 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 | |||
| 167 | bool 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 | |||
| 195 | bool 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 | |||
| 216 | bool 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 | |||
| 248 | bool 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 | |||
| 283 | void 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 | |||
| 293 | bool 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 | |||
| 304 | bool 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 | |||
| 350 | CDateTime 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 | |||
| 369 | void 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 | |||
| 422 | bool CAddonInstaller::HasJob(const std::string& ID) const | ||
| 423 | { | ||
| 424 | CSingleLock lock(m_critSection); | ||
| 425 | return m_downloadJobs.find(ID) != m_downloadJobs.end(); | ||
| 426 | } | ||
| 427 | |||
| 428 | void 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 | |||
| 482 | int64_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 | |||
| 503 | CAddonInstallJob::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 | |||
| 510 | AddonPtr 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 | |||
| 534 | bool 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 | |||
| 555 | bool 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 | |||
| 680 | bool 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 | |||
| 695 | bool 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 | |||
| 730 | bool CAddonInstallJob::OnPreInstall() | ||
| 731 | { | ||
| 732 | return m_addon->OnPreInstall(); | ||
| 733 | } | ||
| 734 | |||
| 735 | bool 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 | |||
| 744 | bool 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 | |||
| 870 | void 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 | |||
| 880 | void 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 | |||
| 916 | std::string CAddonInstallJob::AddonID() const | ||
| 917 | { | ||
| 918 | return m_addon ? m_addon->ID() : ""; | ||
| 919 | } | ||
| 920 | |||
| 921 | CAddonUnInstallJob::CAddonUnInstallJob(const AddonPtr &addon) | ||
| 922 | : m_addon(addon) | ||
| 923 | { } | ||
| 924 | |||
| 925 | bool 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 | |||
| 946 | bool 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 | |||
| 956 | void 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 | |||
| 27 | class CAddonDatabase; | ||
| 28 | |||
| 29 | enum { | ||
| 30 | AUTO_UPDATES_ON = 0, | ||
| 31 | AUTO_UPDATES_NOTIFY, | ||
| 32 | AUTO_UPDATES_NEVER, | ||
| 33 | AUTO_UPDATES_MAX | ||
| 34 | }; | ||
| 35 | |||
| 36 | class CAddonInstaller : public IJobCallback | ||
| 37 | { | ||
| 38 | public: | ||
| 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 | |||
| 124 | private: | ||
| 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 | |||
| 161 | class CAddonInstallJob : public CFileOperationJob | ||
| 162 | { | ||
| 163 | public: | ||
| 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 | |||
| 187 | private: | ||
| 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 | |||
| 213 | class CAddonUnInstallJob : public CFileOperationJob | ||
| 214 | { | ||
| 215 | public: | ||
| 216 | CAddonUnInstallJob(const ADDON::AddonPtr &addon); | ||
| 217 | |||
| 218 | virtual bool DoWork(); | ||
| 219 | |||
| 220 | private: | ||
| 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 | |||
| 54 | using namespace std; | ||
| 55 | using namespace XFILE; | ||
| 56 | |||
| 57 | namespace ADDON | ||
| 58 | { | ||
| 59 | |||
| 60 | cp_log_severity_t clog_to_cp(int lvl); | ||
| 61 | void cp_fatalErrorHandler(const char *msg); | ||
| 62 | void cp_logger(cp_log_severity_t level, const char *msg, const char *apid, void *user_data); | ||
| 63 | |||
| 64 | /********************************************************** | ||
| 65 | * CAddonMgr | ||
| 66 | * | ||
| 67 | */ | ||
| 68 | |||
| 69 | map<TYPE, IAddonMgrCallback*> CAddonMgr::m_managers; | ||
| 70 | |||
| 71 | AddonPtr 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 | |||
| 183 | bool 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 | |||
| 213 | CAddonMgr::CAddonMgr() | ||
| 214 | { | ||
| 215 | m_cpluff = NULL; | ||
| 216 | } | ||
| 217 | |||
| 218 | CAddonMgr::~CAddonMgr() | ||
| 219 | { | ||
| 220 | DeInit(); | ||
| 221 | } | ||
| 222 | |||
| 223 | CAddonMgr &CAddonMgr::Get() | ||
| 224 | { | ||
| 225 | static CAddonMgr sAddonMgr; | ||
| 226 | return sAddonMgr; | ||
| 227 | } | ||
| 228 | |||
| 229 | IAddonMgrCallback* 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 | |||
| 237 | bool 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 | |||
| 248 | void CAddonMgr::UnregisterAddonMgrCallback(TYPE type) | ||
| 249 | { | ||
| 250 | m_managers.erase(type); | ||
| 251 | } | ||
| 252 | |||
| 253 | bool 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 | |||
| 322 | void 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 | |||
| 332 | bool 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 | |||
| 340 | bool 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 | |||
| 353 | void CAddonMgr::AddToUpdateableAddons(AddonPtr &pAddon) | ||
| 354 | { | ||
| 355 | CSingleLock lock(m_critSection); | ||
| 356 | m_updateableAddons.push_back(pAddon); | ||
| 357 | } | ||
| 358 | |||
| 359 | void 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 | |||
| 370 | struct 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 | |||
| 384 | bool 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 | |||
| 396 | bool 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 | |||
| 432 | bool CAddonMgr::HasOutdatedAddons() | ||
| 433 | { | ||
| 434 | VECADDONS dummy; | ||
| 435 | return GetAllOutdatedAddons(dummy); | ||
| 436 | } | ||
| 437 | |||
| 438 | bool 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 | |||
| 471 | bool 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 | ||
| 501 | bool 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 | |||
| 536 | bool 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 | |||
| 568 | std::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 | |||
| 577 | void 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 | |||
| 590 | void 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 | |||
| 600 | bool 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 | |||
| 612 | bool 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 | |||
| 625 | bool 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 | |||
| 652 | bool CAddonMgr::IsAddonInstalled(const std::string& ID) | ||
| 653 | { | ||
| 654 | AddonPtr tmp; | ||
| 655 | return IsAddonInstalled(ID, tmp); | ||
| 656 | } | ||
| 657 | |||
| 658 | bool CAddonMgr::IsAddonInstalled(const std::string& ID, AddonPtr& addon) | ||
| 659 | { | ||
| 660 | return GetAddon(ID, addon, ADDON_UNKNOWN, false); | ||
| 661 | } | ||
| 662 | |||
| 663 | bool 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 | |||
| 680 | bool 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 | |||
| 697 | std::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 | |||
| 718 | AddonPtr 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 | |||
| 770 | bool 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 | |||
| 811 | const 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 | |||
| 819 | bool 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 | |||
| 834 | const 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 | |||
| 846 | std::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 | |||
| 855 | bool 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 | |||
| 867 | AddonPtr 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 | ||
| 892 | bool 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 | |||
| 905 | bool 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 | |||
| 937 | bool 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 | |||
| 959 | bool 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 | |||
| 982 | void 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 | |||
| 1002 | int cp_to_clog(cp_log_severity_t lvl) | ||
| 1003 | { | ||
| 1004 | if (lvl >= CP_LOG_ERROR) | ||
| 1005 | return LOGINFO; | ||
| 1006 | return LOGDEBUG; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | cp_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 | |||
| 1016 | void cp_fatalErrorHandler(const char *msg) | ||
| 1017 | { | ||
| 1018 | CLog::Log(LOGERROR, "ADDONS: CPluffFatalError(%s)", msg); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | void 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 | |||
| 30 | class DllLibCPluff; | ||
| 31 | extern "C" | ||
| 32 | { | ||
| 33 | #include "lib/cpluff/libcpluff/cpluff.h" | ||
| 34 | } | ||
| 35 | |||
| 36 | namespace 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 | |||
| 33 | namespace 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 | |||
| 44 | CCriticalSection CAddonStatusHandler::m_critSection; | ||
| 45 | |||
| 46 | CAddonStatusHandler::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 | |||
| 67 | CAddonStatusHandler::~CAddonStatusHandler() | ||
| 68 | { | ||
| 69 | StopThread(); | ||
| 70 | } | ||
| 71 | |||
| 72 | void CAddonStatusHandler::OnStartup() | ||
| 73 | { | ||
| 74 | SetPriority(GetMinPriority()); | ||
| 75 | } | ||
| 76 | |||
| 77 | void CAddonStatusHandler::OnExit() | ||
| 78 | { | ||
| 79 | } | ||
| 80 | |||
| 81 | void 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 | |||
| 28 | namespace 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 | |||
| 29 | namespace 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 | |||
| 24 | namespace 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 | |||
| 21 | namespace ADDON | ||
| 22 | { | ||
| 23 | |||
| 24 | CAudioEncoder::CAudioEncoder(const cp_extension_t* ext) | ||
| 25 | : AudioEncoderDll(ext), | ||
| 26 | extension(CAddonMgr::Get().GetExtValue(ext->configuration, "@extension")), | ||
| 27 | m_context(NULL) | ||
| 28 | { | ||
| 29 | } | ||
| 30 | |||
| 31 | AddonPtr CAudioEncoder::Clone() const | ||
| 32 | { | ||
| 33 | // Copy constructor is generated by compiler and calls parent copy constructor | ||
| 34 | return AddonPtr(new CAudioEncoder(*this)); | ||
| 35 | } | ||
| 36 | |||
| 37 | bool 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 | |||
| 62 | int 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 | |||
| 70 | bool 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 | |||
| 84 | void 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 | |||
| 25 | typedef DllAddon<AudioEncoder, AUDIOENC_PROPS> DllAudioEncoder; | ||
| 26 | namespace 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 | |||
| 32 | using namespace std; | ||
| 33 | |||
| 34 | namespace ADDON | ||
| 35 | { | ||
| 36 | |||
| 37 | CContextItemAddon::CContextItemAddon(const AddonProps &props) | ||
| 38 | : CAddon(props) | ||
| 39 | { } | ||
| 40 | |||
| 41 | CContextItemAddon::~CContextItemAddon() | ||
| 42 | { } | ||
| 43 | |||
| 44 | CContextItemAddon::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 | |||
| 69 | bool CContextItemAddon::OnPreInstall() | ||
| 70 | { | ||
| 71 | return CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); | ||
| 72 | } | ||
| 73 | |||
| 74 | void 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 | |||
| 89 | void CContextItemAddon::OnPreUnInstall() | ||
| 90 | { | ||
| 91 | CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); | ||
| 92 | } | ||
| 93 | |||
| 94 | void CContextItemAddon::OnDisabled() | ||
| 95 | { | ||
| 96 | CContextMenuManager::Get().Unregister(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); | ||
| 97 | } | ||
| 98 | void CContextItemAddon::OnEnabled() | ||
| 99 | { | ||
| 100 | CContextMenuManager::Get().Register(std::dynamic_pointer_cast<CContextItemAddon>(shared_from_this())); | ||
| 101 | } | ||
| 102 | |||
| 103 | bool 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 | |||
| 26 | class CFileItem; | ||
| 27 | typedef std::shared_ptr<CFileItem> CFileItemPtr; | ||
| 28 | |||
| 29 | namespace INFO | ||
| 30 | { | ||
| 31 | class InfoBool; | ||
| 32 | typedef std::shared_ptr<InfoBool> InfoPtr; | ||
| 33 | } | ||
| 34 | |||
| 35 | namespace 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 | |||
| 25 | template <typename TheStruct, typename Props> | ||
| 26 | class DllAddonInterface | ||
| 27 | { | ||
| 28 | public: | ||
| 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 | |||
| 42 | template <typename TheStruct, typename Props> | ||
| 43 | class DllAddon : public DllDynamic, public DllAddonInterface<TheStruct, Props> | ||
| 44 | { | ||
| 45 | public: | ||
| 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 | |||
| 24 | extern "C" { | ||
| 25 | #include "lib/cpluff/libcpluff/cpluff.h" | ||
| 26 | } | ||
| 27 | |||
| 28 | class DllLibCPluffInterface | ||
| 29 | { | ||
| 30 | public: | ||
| 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 | |||
| 58 | class 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 | |||
| 25 | class 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 | |||
| 53 | using namespace std; | ||
| 54 | using namespace ADDON; | ||
| 55 | using namespace XFILE; | ||
| 56 | |||
| 57 | CGUIDialogAddonInfo::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 | |||
| 64 | CGUIDialogAddonInfo::~CGUIDialogAddonInfo(void) | ||
| 65 | { | ||
| 66 | } | ||
| 67 | |||
| 68 | bool 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; | ||
| 127 | default: | ||
| 128 | break; | ||
| 129 | } | ||
| 130 | |||
| 131 | return CGUIDialog::OnMessage(message); | ||
| 132 | } | ||
| 133 | |||
| 134 | bool 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 | |||
| 144 | void CGUIDialogAddonInfo::OnInitWindow() | ||
| 145 | { | ||
| 146 | UpdateControls(); | ||
| 147 | CGUIDialog::OnInitWindow(); | ||
| 148 | m_changelog = false; | ||
| 149 | } | ||
| 150 | |||
| 151 | void 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 | |||
| 177 | void 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 | |||
| 184 | void CGUIDialogAddonInfo::OnInstall() | ||
| 185 | { | ||
| 186 | CAddonInstaller::Get().Install(m_addon->ID()); | ||
| 187 | Close(); | ||
| 188 | } | ||
| 189 | |||
| 190 | void CGUIDialogAddonInfo::OnLaunch() | ||
| 191 | { | ||
| 192 | if (!m_localAddon) | ||
| 193 | return; | ||
| 194 | |||
| 195 | CBuiltins::Execute("RunAddon(" + m_localAddon->ID() + ")"); | ||
| 196 | Close(); | ||
| 197 | } | ||
| 198 | |||
| 199 | bool 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 | |||
| 225 | void 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 | |||
| 250 | void 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 | |||
| 267 | void CGUIDialogAddonInfo::OnSettings() | ||
| 268 | { | ||
| 269 | CGUIDialogAddonSettings::ShowAndGetInput(m_localAddon); | ||
| 270 | } | ||
| 271 | |||
| 272 | void 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 | |||
| 305 | void 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 | |||
| 343 | bool 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 | |||
| 355 | bool 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 | |||
| 399 | void 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 | |||
| 428 | void 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 | |||
| 27 | class CGUIDialogAddonInfo : | ||
| 28 | public CGUIDialog, | ||
| 29 | public IJobCallback | ||
| 30 | { | ||
| 31 | public: | ||
| 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); | ||
| 44 | protected: | ||
| 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 | |||
| 56 | using namespace std; | ||
| 57 | using namespace ADDON; | ||
| 58 | using 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 | |||
| 78 | CGUIDialogAddonSettings::CGUIDialogAddonSettings() | ||
| 79 | : CGUIDialogBoxBase(WINDOW_DIALOG_ADDON_SETTINGS, "DialogAddonSettings.xml") | ||
| 80 | { | ||
| 81 | m_currentSection = 0; | ||
| 82 | m_totalSections = 1; | ||
| 83 | m_saveToDisk = false; | ||
| 84 | } | ||
| 85 | |||
| 86 | CGUIDialogAddonSettings::~CGUIDialogAddonSettings(void) | ||
| 87 | { | ||
| 88 | } | ||
| 89 | |||
| 90 | bool 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 | |||
| 152 | bool 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 | |||
| 184 | void 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. | ||
| 194 | bool 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 | |||
| 228 | bool 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 | |||
| 507 | void 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 | |||
| 553 | void 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 | |||
| 566 | void 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 | |||
| 579 | void 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 | |||
| 590 | void 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 | |||
| 646 | void 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 | |||
| 910 | std::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 | |||
| 927 | vector<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 | ||
| 960 | void 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 | |||
| 987 | bool 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 | |||
| 1073 | bool 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 | |||
| 1094 | std::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 | ||
| 1105 | void 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 | |||
| 1140 | const 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 | |||
| 1152 | void 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 | |||
| 1183 | std::string CGUIDialogAddonSettings::GetCurrentID() const | ||
| 1184 | { | ||
| 1185 | if (m_addon) | ||
| 1186 | return m_addon->ID(); | ||
| 1187 | return ""; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | int 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 | |||
| 25 | class CGUIDialogAddonSettings : public CGUIDialogBoxBase | ||
| 26 | { | ||
| 27 | public: | ||
| 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; | ||
| 41 | protected: | ||
| 42 | virtual void OnInitWindow(); | ||
| 43 | virtual int GetDefaultLabelID(int controlId) const; | ||
| 44 | |||
| 45 | private: | ||
| 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 | |||
| 33 | using namespace XFILE; | ||
| 34 | using namespace ADDON; | ||
| 35 | |||
| 36 | CGUIViewStateAddonBrowser::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 | |||
| 55 | void CGUIViewStateAddonBrowser::SaveViewState() | ||
| 56 | { | ||
| 57 | SaveViewToDb(m_items.GetPath(), WINDOW_ADDON_BROWSER); | ||
| 58 | } | ||
| 59 | |||
| 60 | std::string CGUIViewStateAddonBrowser::GetExtensions() | ||
| 61 | { | ||
| 62 | return ""; | ||
| 63 | } | ||
| 64 | |||
| 65 | VECSOURCES& 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 | |||
| 25 | class CGUIViewStateAddonBrowser : public CGUIViewState | ||
| 26 | { | ||
| 27 | public: | ||
| 28 | CGUIViewStateAddonBrowser(const CFileItemList& items); | ||
| 29 | |||
| 30 | protected: | ||
| 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 | |||
| 58 | using namespace ADDON; | ||
| 59 | using namespace XFILE; | ||
| 60 | using namespace std; | ||
| 61 | |||
| 62 | CGUIWindowAddonBrowser::CGUIWindowAddonBrowser(void) | ||
| 63 | : CGUIMediaWindow(WINDOW_ADDON_BROWSER, "AddonBrowser.xml") | ||
| 64 | { | ||
| 65 | } | ||
| 66 | |||
| 67 | CGUIWindowAddonBrowser::~CGUIWindowAddonBrowser() | ||
| 68 | { | ||
| 69 | } | ||
| 70 | |||
| 71 | bool 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 | |||
| 161 | void 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 | |||
| 188 | bool 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 | |||
| 231 | class 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 | |||
| 245 | class UpdateRepos : public IRunnable | ||
| 246 | { | ||
| 247 | virtual void Run() | ||
| 248 | { | ||
| 249 | CAddonInstaller::Get().UpdateRepos(true, true); | ||
| 250 | } | ||
| 251 | }; | ||
| 252 | |||
| 253 | bool 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 | |||
| 307 | void 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 | |||
| 336 | static 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 | |||
| 349 | bool 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 | |||
| 422 | void 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 | |||
| 439 | bool 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 | |||
| 452 | int 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 | |||
| 459 | int 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 | |||
| 466 | int 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 | |||
| 479 | int 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 | |||
| 672 | std::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 | |||
| 27 | class CFileItem; | ||
| 28 | class CFileItemList; | ||
| 29 | |||
| 30 | class CGUIWindowAddonBrowser : public CGUIMediaWindow | ||
| 31 | { | ||
| 32 | public: | ||
| 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 | |||
| 63 | protected: | ||
| 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); | ||
| 76 | private: | ||
| 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 | |||
| 28 | class TiXmlElement; | ||
| 29 | |||
| 30 | namespace 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 @@ | |||
| 1 | SRCS=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 | |||
| 27 | LIB=addons.a | ||
| 28 | |||
| 29 | include ../../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 | |||
| 24 | using namespace std; | ||
| 25 | |||
| 26 | namespace ADDON | ||
| 27 | { | ||
| 28 | |||
| 29 | CPluginSource::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 | |||
| 39 | CPluginSource::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 | |||
| 52 | AddonPtr CPluginSource::Clone() const | ||
| 53 | { | ||
| 54 | return AddonPtr(new CPluginSource(*this)); | ||
| 55 | } | ||
| 56 | |||
| 57 | void 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 | |||
| 73 | CPluginSource::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 | |||
| 87 | bool 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 | |||
| 24 | namespace ADDON | ||
| 25 | { | ||
| 26 | |||
| 27 | class CPluginSource : public CAddon | ||
| 28 | { | ||
| 29 | public: | ||
| 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); | ||
| 49 | private: | ||
| 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 | |||
| 39 | using namespace std; | ||
| 40 | using namespace XFILE; | ||
| 41 | using namespace ADDON; | ||
| 42 | |||
| 43 | AddonPtr CRepository::Clone() const | ||
| 44 | { | ||
| 45 | return AddonPtr(new CRepository(*this)); | ||
| 46 | } | ||
| 47 | |||
| 48 | CRepository::CRepository(const AddonProps& props) : | ||
| 49 | CAddon(props) | ||
| 50 | { | ||
| 51 | } | ||
| 52 | |||
| 53 | CRepository::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 | |||
| 98 | CRepository::CRepository(const CRepository &rhs) | ||
| 99 | : CAddon(rhs), m_dirs(rhs.m_dirs) | ||
| 100 | { | ||
| 101 | } | ||
| 102 | |||
| 103 | CRepository::~CRepository() | ||
| 104 | { | ||
| 105 | } | ||
| 106 | |||
| 107 | string 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 | |||
| 131 | string 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 | |||
| 154 | bool 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 | |||
| 196 | void 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 | |||
| 204 | void CRepository::OnPostUnInstall() | ||
| 205 | { | ||
| 206 | CAddonDatabase database; | ||
| 207 | database.Open(); | ||
| 208 | database.DeleteRepository(ID()); | ||
| 209 | } | ||
| 210 | |||
| 211 | CRepositoryUpdateJob::CRepositoryUpdateJob(const VECADDONS &repos) | ||
| 212 | : m_repos(repos) | ||
| 213 | { | ||
| 214 | } | ||
| 215 | |||
| 216 | void 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 | |||
| 231 | bool 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 | |||
| 331 | bool 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 | |||
| 25 | namespace 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 | |||
| 47 | using namespace std; | ||
| 48 | using namespace XFILE; | ||
| 49 | using namespace MUSIC_GRABBER; | ||
| 50 | using namespace VIDEO; | ||
| 51 | |||
| 52 | namespace ADDON | ||
| 53 | { | ||
| 54 | |||
| 55 | typedef struct | ||
| 56 | { | ||
| 57 | const char* name; | ||
| 58 | CONTENT_TYPE type; | ||
| 59 | int pretty; | ||
| 60 | } ContentMapping; | ||
| 61 | |||
| 62 | static 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 | |||
| 71 | std::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 | |||
| 87 | CONTENT_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 | |||
| 98 | TYPE 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 | ||
| 118 | static 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 | |||
| 129 | CScraper::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 | |||
| 162 | AddonPtr CScraper::Clone() const | ||
| 163 | { | ||
| 164 | return AddonPtr(new CScraper(*this)); | ||
| 165 | } | ||
| 166 | |||
| 167 | CScraper::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 | |||
| 176 | bool CScraper::Supports(const CONTENT_TYPE &content) const | ||
| 177 | { | ||
| 178 | return Type() == ScraperTypeFromContent(content); | ||
| 179 | } | ||
| 180 | |||
| 181 | bool 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 | |||
| 197 | std::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 | |||
| 211 | void 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) | ||
| 241 | vector<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 | ||
| 310 | vector<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 | |||
| 327 | std::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 | |||
| 349 | bool 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 | |||
| 396 | bool 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 | |||
| 413 | bool 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 | ||
| 423 | CScraperUrl 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 | |||
| 488 | CScraperUrl 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 | |||
| 550 | static 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 | ||
| 557 | std::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) | ||
| 687 | std::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) | ||
| 784 | std::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) | ||
| 864 | EPISODELIST 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 | ||
| 929 | bool 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 | ||
| 970 | bool 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 | ||
| 997 | bool 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 | |||
| 27 | class CAlbum; | ||
| 28 | class CArtist; | ||
| 29 | class CVideoInfoTag; | ||
| 30 | |||
| 31 | namespace MUSIC_GRABBER | ||
| 32 | { | ||
| 33 | class CMusicAlbumInfo; | ||
| 34 | class CMusicArtistInfo; | ||
| 35 | } | ||
| 36 | |||
| 37 | typedef enum | ||
| 38 | { | ||
| 39 | CONTENT_MOVIES, | ||
| 40 | CONTENT_TVSHOWS, | ||
| 41 | CONTENT_MUSICVIDEOS, | ||
| 42 | CONTENT_ALBUMS, | ||
| 43 | CONTENT_ARTISTS, | ||
| 44 | CONTENT_NONE, | ||
| 45 | } CONTENT_TYPE; | ||
| 46 | |||
| 47 | namespace XFILE | ||
| 48 | { | ||
| 49 | class CCurlFile; | ||
| 50 | } | ||
| 51 | |||
| 52 | class CScraperUrl; | ||
| 53 | |||
| 54 | namespace ADDON | ||
| 55 | { | ||
| 56 | class CScraper; | ||
| 57 | typedef std::shared_ptr<CScraper> ScraperPtr; | ||
| 58 | |||
| 59 | std::string TranslateContent(const CONTENT_TYPE &content, bool pretty=false); | ||
| 60 | CONTENT_TYPE TranslateContent(const std::string &string); | ||
| 61 | TYPE ScraperTypeFromContent(const CONTENT_TYPE &content); | ||
| 62 | |||
| 63 | // thrown as exception to signal abort or show error dialog | ||
| 64 | class CScraperError | ||
| 65 | { | ||
| 66 | public: | ||
| 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 | |||
| 75 | private: | ||
| 76 | bool m_fAborted; | ||
| 77 | std::string m_sTitle; | ||
| 78 | std::string m_sMessage; | ||
| 79 | }; | ||
| 80 | |||
| 81 | class CScraper : public CAddon | ||
| 82 | { | ||
| 83 | public: | ||
| 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 | |||
| 150 | private: | ||
| 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 | |||
| 32 | namespace ADDON | ||
| 33 | { | ||
| 34 | |||
| 35 | CScreenSaver::CScreenSaver(const char *addonID) | ||
| 36 | : ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>(AddonProps(addonID, ADDON_UNKNOWN, "", "")) | ||
| 37 | { | ||
| 38 | } | ||
| 39 | |||
| 40 | AddonPtr CScreenSaver::Clone() const | ||
| 41 | { | ||
| 42 | // Copy constructor is generated by compiler and calls parent copy constructor | ||
| 43 | return AddonPtr(new CScreenSaver(*this)); | ||
| 44 | } | ||
| 45 | |||
| 46 | bool 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 | |||
| 83 | void CScreenSaver::Start() | ||
| 84 | { | ||
| 85 | // notify screen saver that they should start | ||
| 86 | if (Initialized()) m_pStruct->Start(); | ||
| 87 | } | ||
| 88 | |||
| 89 | void CScreenSaver::Render() | ||
| 90 | { | ||
| 91 | // ask screensaver to render itself | ||
| 92 | if (Initialized()) m_pStruct->Render(); | ||
| 93 | } | ||
| 94 | |||
| 95 | void CScreenSaver::GetInfo(SCR_INFO *info) | ||
| 96 | { | ||
| 97 | // get info from screensaver | ||
| 98 | if (Initialized()) m_pStruct->GetInfo(info); | ||
| 99 | } | ||
| 100 | |||
| 101 | void 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 | |||
| 25 | typedef DllAddon<ScreenSaver, SCR_PROPS> DllScreenSaver; | ||
| 26 | |||
| 27 | namespace ADDON | ||
| 28 | { | ||
| 29 | |||
| 30 | class CScreenSaver : public ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS> | ||
| 31 | { | ||
| 32 | public: | ||
| 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 | |||
| 26 | using namespace std; | ||
| 27 | |||
| 28 | namespace ADDON | ||
| 29 | { | ||
| 30 | |||
| 31 | CService::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 | |||
| 42 | CService::CService(const AddonProps &props) | ||
| 43 | : CAddon(props), m_type(UNKNOWN), m_startOption(LOGIN) | ||
| 44 | { | ||
| 45 | BuildServiceType(); | ||
| 46 | } | ||
| 47 | |||
| 48 | AddonPtr CService::Clone() const | ||
| 49 | { | ||
| 50 | return AddonPtr(new CService(*this)); | ||
| 51 | } | ||
| 52 | |||
| 53 | bool 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 | |||
| 73 | bool 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 | |||
| 94 | void 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 | |||
| 116 | void CService::OnDisabled() | ||
| 117 | { | ||
| 118 | Stop(); | ||
| 119 | } | ||
| 120 | |||
| 121 | void CService::OnEnabled() | ||
| 122 | { | ||
| 123 | Start(); | ||
| 124 | } | ||
| 125 | |||
| 126 | bool 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 | |||
| 139 | void 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 | |||
| 153 | void 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 | |||
| 23 | namespace 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 | |||
| 41 | using namespace std; | ||
| 42 | using namespace XFILE; | ||
| 43 | |||
| 44 | std::shared_ptr<ADDON::CSkinInfo> g_SkinInfo; | ||
| 45 | |||
| 46 | namespace ADDON | ||
| 47 | { | ||
| 48 | |||
| 49 | CSkinInfo::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 | |||
| 54 | CSkinInfo::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 | |||
| 101 | CSkinInfo::~CSkinInfo() | ||
| 102 | { | ||
| 103 | } | ||
| 104 | |||
| 105 | AddonPtr CSkinInfo::Clone() const | ||
| 106 | { | ||
| 107 | return AddonPtr(new CSkinInfo(*this)); | ||
| 108 | } | ||
| 109 | |||
| 110 | struct 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 | |||
| 126 | void 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 | |||
| 149 | std::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 | |||
| 180 | bool CSkinInfo::HasSkinFile(const std::string &strFile) const | ||
| 181 | { | ||
| 182 | return CFile::Exists(GetSkinPath(strFile)); | ||
| 183 | } | ||
| 184 | |||
| 185 | void 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 | |||
| 193 | void 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 | |||
| 201 | int 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 | |||
| 214 | bool 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 | |||
| 230 | void 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 | |||
| 240 | bool 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 | |||
| 260 | int CSkinInfo::GetFirstWindow() const | ||
| 261 | { | ||
| 262 | int startWindow = GetStartWindow(); | ||
| 263 | if (HasSkinFile("Startup.xml")) | ||
| 264 | startWindow = WINDOW_STARTUP_ANIM; | ||
| 265 | return startWindow; | ||
| 266 | } | ||
| 267 | |||
| 268 | bool 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 | |||
| 274 | const INFO::CSkinVariableString* CSkinInfo::CreateSkinVariable(const std::string& name, int context) | ||
| 275 | { | ||
| 276 | return m_includes.CreateSkinVariable(name, context); | ||
| 277 | } | ||
| 278 | |||
| 279 | bool 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 | |||
| 290 | void 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 | |||
| 307 | void CSkinInfo::SettingOptionsSkinColorsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, 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 | |||
| 348 | void CSkinInfo::SettingOptionsSkinFontsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, 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 | |||
| 397 | void CSkinInfo::SettingOptionsSkinSoundFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, 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 | |||
| 437 | void CSkinInfo::SettingOptionsSkinThemesFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, 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 | |||
| 466 | void CSkinInfo::SettingOptionsStartupWindowsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t, 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 | |||
| 30 | class CSetting; | ||
| 31 | |||
| 32 | namespace ADDON | ||
| 33 | { | ||
| 34 | |||
| 35 | class CSkinInfo : public CAddon | ||
| 36 | { | ||
| 37 | public: | ||
| 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 ¤t, void *data); | ||
| 116 | static void SettingOptionsSkinFontsFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, void *data); | ||
| 117 | static void SettingOptionsSkinSoundFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, void *data); | ||
| 118 | static void SettingOptionsSkinThemesFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t, void *data); | ||
| 119 | static void SettingOptionsStartupWindowsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t, void *data); | ||
| 120 | |||
| 121 | virtual bool OnPreInstall(); | ||
| 122 | virtual void OnPostInstall(bool restart, bool update, bool modal); | ||
| 123 | protected: | ||
| 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 | |||
| 155 | extern 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 | |||
| 41 | using namespace std; | ||
| 42 | using namespace MUSIC_INFO; | ||
| 43 | using namespace ADDON; | ||
| 44 | |||
| 45 | CAudioBuffer::CAudioBuffer(int iSize) | ||
| 46 | { | ||
| 47 | m_iLen = iSize; | ||
| 48 | m_pBuffer = new float[iSize]; | ||
| 49 | } | ||
| 50 | |||
| 51 | CAudioBuffer::~CAudioBuffer() | ||
| 52 | { | ||
| 53 | delete [] m_pBuffer; | ||
| 54 | } | ||
| 55 | |||
| 56 | const float* CAudioBuffer::Get() const | ||
| 57 | { | ||
| 58 | return m_pBuffer; | ||
| 59 | } | ||
| 60 | |||
| 61 | void 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 | |||
| 69 | bool 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 | |||
| 119 | void 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 | |||
| 136 | void 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 | |||
| 156 | void 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 | |||
| 174 | void CVisualisation::Stop() | ||
| 175 | { | ||
| 176 | CAEFactory::UnregisterAudioCallback(); | ||
| 177 | if (Initialized()) | ||
| 178 | { | ||
| 179 | CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Stop(); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | void 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 | |||
| 198 | bool 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 | |||
| 245 | void 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 | |||
| 259 | void 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 | |||
| 304 | void 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 | |||
| 319 | void 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 | |||
| 336 | bool 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 | |||
| 363 | bool CVisualisation::GetPresetList(std::vector<std::string> &vecpresets) | ||
| 364 | { | ||
| 365 | vecpresets = m_presets; | ||
| 366 | return !m_presets.empty(); | ||
| 367 | } | ||
| 368 | |||
| 369 | bool 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 | |||
| 396 | bool CVisualisation::GetSubModuleList(std::vector<std::string> &vecmodules) | ||
| 397 | { | ||
| 398 | vecmodules = m_submodules; | ||
| 399 | return !m_submodules.empty(); | ||
| 400 | } | ||
| 401 | |||
| 402 | bool 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 | |||
| 429 | std::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 | |||
| 436 | bool 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 | |||
| 448 | void 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 | |||
| 465 | unsigned 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 | |||
| 479 | std::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 | |||
| 34 | class CCriticalSection; | ||
| 35 | |||
| 36 | typedef DllAddon<Visualisation, VIS_PROPS> DllVisualisation; | ||
| 37 | |||
| 38 | class CAudioBuffer | ||
| 39 | { | ||
| 40 | public: | ||
| 41 | CAudioBuffer(int iSize); | ||
| 42 | virtual ~CAudioBuffer(); | ||
| 43 | const float* Get() const; | ||
| 44 | void Set(const float* psBuffer, int iSize); | ||
| 45 | private: | ||
| 46 | CAudioBuffer(); | ||
| 47 | float* m_pBuffer; | ||
| 48 | int m_iLen; | ||
| 49 | }; | ||
| 50 | |||
| 51 | namespace 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 | |||
| 27 | using namespace ADDON; | ||
| 28 | |||
| 29 | CWebinterface::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 | |||
| 35 | CWebinterface::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 | |||
| 53 | CWebinterface::~CWebinterface() | ||
| 54 | { } | ||
| 55 | |||
| 56 | std::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 | |||
| 64 | std::string CWebinterface::GetBaseLocation() const | ||
| 65 | { | ||
| 66 | if (m_type == WebinterfaceTypeWsgi) | ||
| 67 | return "/addons/" + ID(); | ||
| 68 | |||
| 69 | return ""; | ||
| 70 | } | ||
| 71 | |||
| 72 | AddonPtr 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 | |||
| 26 | namespace 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 @@ | |||
| 1 | BINDINGS =xbmc/addons/include/xbmc_addon_cpp_dll.h | ||
| 2 | BINDINGS+=xbmc/addons/include/xbmc_addon_dll.h | ||
| 3 | BINDINGS+=xbmc/addons/include/xbmc_addon_types.h | ||
| 4 | BINDINGS+=xbmc/addons/include/xbmc_audioenc_dll.h | ||
| 5 | BINDINGS+=xbmc/addons/include/xbmc_audioenc_types.h | ||
| 6 | BINDINGS+=xbmc/addons/include/xbmc_codec_types.h | ||
| 7 | BINDINGS+=xbmc/addons/include/xbmc_epg_types.h | ||
| 8 | BINDINGS+=xbmc/addons/include/xbmc_pvr_dll.h | ||
| 9 | BINDINGS+=xbmc/addons/include/xbmc_pvr_types.h | ||
| 10 | BINDINGS+=xbmc/addons/include/xbmc_scr_dll.h | ||
| 11 | BINDINGS+=xbmc/addons/include/xbmc_scr_types.h | ||
| 12 | BINDINGS+=xbmc/addons/include/xbmc_vis_dll.h | ||
| 13 | BINDINGS+=xbmc/addons/include/xbmc_vis_types.h | ||
| 14 | BINDINGS+=xbmc/addons/include/xbmc_stream_utils.hpp | ||
| 15 | BINDINGS+=addons/library.xbmc.addon/libXBMC_addon.h | ||
| 16 | BINDINGS+=addons/library.xbmc.gui/libXBMC_gui.h | ||
| 17 | BINDINGS+=addons/library.xbmc.pvr/libXBMC_pvr.h | ||
| 18 | BINDINGS+=addons/library.xbmc.codec/libXBMC_codec.h | ||
| 19 | BINDINGS+=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 @@ | |||
| 1 | NOTE: | ||
| 2 | |||
| 3 | This directory contains independent Headers to build Add-on's | ||
| 4 | without the whole XBMC source tree. The Add-on itself can add | ||
| 5 | this headers to his source tree without dependencies to any | ||
| 6 | XBMC related classes or functions. | ||
| 7 | |||
| 8 | Also this headers are never changed without a API Version | ||
| 9 | change. | ||
| 10 | |||
| 11 | The current PVR API version can be found in xbmc_pvr_types.h: | ||
| 12 | XBMC_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 | |||
| 30 | class DllSetting | ||
| 31 | { | ||
| 32 | public: | ||
| 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 | |||
| 101 | class DllUtils | ||
| 102 | { | ||
| 103 | public: | ||
| 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 | ||
| 38 | extern "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 | ||
| 25 | extern "C" { | ||
| 26 | #endif | ||
| 27 | |||
| 28 | enum 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 | |||
| 39 | typedef 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 | */ | ||
| 52 | struct 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 | }; | ||
| 58 | typedef 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 | |||
| 29 | extern "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 | |||
| 38 | extern "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 | ||
| 25 | extern "C" { | ||
| 26 | #endif | ||
| 27 | |||
| 28 | typedef unsigned int xbmc_codec_id_t; | ||
| 29 | |||
| 30 | typedef 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 | |||
| 41 | typedef 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 | ||
| 65 | extern "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 | |||
| 33 | extern "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 | ||
| 49 | struct 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 | ||
| 84 | extern "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 | |||
| 28 | extern "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 | |||
| 25 | extern "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 | |||
| 26 | namespace 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 | |||
| 27 | extern "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 | |||
| 29 | extern "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 @@ | |||
| 1 | SRCS= \ | ||
| 2 | TestAddonVersion.cpp | ||
| 3 | |||
| 4 | LIB=addonsTest.a | ||
| 5 | |||
| 6 | INCLUDES += -I../../../lib/gtest/include | ||
| 7 | |||
| 8 | include ../../../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 | |||
| 25 | using namespace ADDON; | ||
| 26 | |||
| 27 | class TestAddonVersion : public testing::Test | ||
| 28 | { | ||
| 29 | public: | ||
| 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 | |||
| 70 | TEST_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 | |||
| 141 | TEST_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 | |||
| 162 | TEST_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 | |||
| 183 | TEST_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 | |||
| 196 | TEST_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 | |||
| 24 | void CDemuxStreamTeletext::GetStreamInfo(std::string& strInfo) | ||
| 25 | { | ||
| 26 | strInfo = "Teletext Data Stream"; | ||
| 27 | } | ||
| 28 | |||
| 29 | void 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 | |||
| 62 | int 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 | |||
| 75 | int 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 | |||
| 88 | int 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 | |||
| 101 | int 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 | |||
| 114 | CDemuxStreamAudio* 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 | |||
| 128 | CDemuxStreamVideo* 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 | |||
| 142 | CDemuxStreamSubtitle* 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 | |||
| 156 | CDemuxStreamTeletext* 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 | |||
| 170 | void CDemuxStream::GetStreamName( std::string& strInfo ) | ||
| 171 | { | ||
| 172 | strInfo = ""; | ||
| 173 | } | ||
| 174 | |||
| 175 | AVDiscard CDemuxStream::GetDiscard() | ||
| 176 | { | ||
| 177 | return AVDISCARD_NONE; | ||
| 178 | } | ||
| 179 | |||
| 180 | void 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 | |||
| 27 | class 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 | |||
| 38 | extern "C" { | ||
| 39 | #include "libavcodec/avcodec.h" | ||
| 40 | } | ||
| 41 | |||
| 42 | #ifndef __GNUC__ | ||
| 43 | #pragma warning(pop) | ||
| 44 | #endif | ||
| 45 | |||
| 46 | enum AVDiscard; | ||
| 47 | |||
| 48 | enum 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 | |||
| 58 | enum 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 | */ | ||
| 73 | class CDemuxStream | ||
| 74 | { | ||
| 75 | public: | ||
| 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 | |||
| 147 | class CDemuxStreamVideo : public CDemuxStream | ||
| 148 | { | ||
| 149 | public: | ||
| 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 | |||
| 183 | class CDemuxStreamAudio : public CDemuxStream | ||
| 184 | { | ||
| 185 | public: | ||
| 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 | |||
| 207 | class CDemuxStreamSubtitle : public CDemuxStream | ||
| 208 | { | ||
| 209 | public: | ||
| 210 | CDemuxStreamSubtitle() : CDemuxStream() | ||
| 211 | { | ||
| 212 | type = STREAM_SUBTITLE; | ||
| 213 | } | ||
| 214 | }; | ||
| 215 | |||
| 216 | class CDemuxStreamTeletext : public CDemuxStream | ||
| 217 | { | ||
| 218 | public: | ||
| 219 | CDemuxStreamTeletext() : CDemuxStream() | ||
| 220 | { | ||
| 221 | type = STREAM_TELETEXT; | ||
| 222 | } | ||
| 223 | virtual void GetStreamInfo(std::string& strInfo); | ||
| 224 | }; | ||
| 225 | |||
| 226 | class CDVDDemux | ||
| 227 | { | ||
| 228 | public: | ||
| 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 | |||
| 30 | using namespace std; | ||
| 31 | |||
| 32 | class CDemuxStreamAudioBXA | ||
| 33 | : public CDemuxStreamAudio | ||
| 34 | { | ||
| 35 | CDVDDemuxBXA *m_parent; | ||
| 36 | string m_codec; | ||
| 37 | public: | ||
| 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 | |||
| 49 | CDVDDemuxBXA::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 | |||
| 57 | CDVDDemuxBXA::~CDVDDemuxBXA() | ||
| 58 | { | ||
| 59 | Dispose(); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool 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 | |||
| 98 | void 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 | |||
| 109 | void CDVDDemuxBXA::Reset() | ||
| 110 | { | ||
| 111 | CDVDInputStream* pInputStream = m_pInput; | ||
| 112 | Dispose(); | ||
| 113 | Open(pInputStream); | ||
| 114 | } | ||
| 115 | |||
| 116 | void CDVDDemuxBXA::Abort() | ||
| 117 | { | ||
| 118 | if(m_pInput) | ||
| 119 | return m_pInput->Abort(); | ||
| 120 | } | ||
| 121 | |||
| 122 | void CDVDDemuxBXA::Flush() | ||
| 123 | { | ||
| 124 | } | ||
| 125 | |||
| 126 | #define BXA_READ_SIZE 4096 | ||
| 127 | DemuxPacket* 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 | |||
| 168 | CDemuxStream* CDVDDemuxBXA::GetStream(int iStreamId) | ||
| 169 | { | ||
| 170 | if(iStreamId != 0) | ||
| 171 | return NULL; | ||
| 172 | |||
| 173 | return m_stream; | ||
| 174 | } | ||
| 175 | |||
| 176 | int CDVDDemuxBXA::GetNrOfStreams() | ||
| 177 | { | ||
| 178 | return (m_stream == NULL ? 0 : 1); | ||
| 179 | } | ||
| 180 | |||
| 181 | std::string CDVDDemuxBXA::GetFileName() | ||
| 182 | { | ||
| 183 | if(m_pInput) | ||
| 184 | return m_pInput->GetFileName(); | ||
| 185 | else | ||
| 186 | return ""; | ||
| 187 | } | ||
| 188 | |||
| 189 | void 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 | |||
| 35 | typedef 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 | |||
| 53 | class CDemuxStreamAudioBXA; | ||
| 54 | |||
| 55 | class CDVDDemuxBXA : public CDVDDemux | ||
| 56 | { | ||
| 57 | public: | ||
| 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 | |||
| 76 | protected: | ||
| 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 | |||
| 29 | class CBitstream | ||
| 30 | { | ||
| 31 | public: | ||
| 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 | |||
| 69 | private: | ||
| 70 | uint8_t *m_data; | ||
| 71 | int m_offset; | ||
| 72 | int m_len; | ||
| 73 | bool m_error; | ||
| 74 | }; | ||
| 75 | |||
| 76 | class CCaptionBlock | ||
| 77 | { | ||
| 78 | public: | ||
| 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 | |||
| 93 | bool reorder_sort (CCaptionBlock *lhs, CCaptionBlock *rhs) | ||
| 94 | { | ||
| 95 | return (lhs->m_pts > rhs->m_pts); | ||
| 96 | } | ||
| 97 | |||
| 98 | CDVDDemuxCC::CDVDDemuxCC(AVCodecID codec) | ||
| 99 | { | ||
| 100 | m_hasData = false; | ||
| 101 | m_curPts = 0; | ||
| 102 | m_ccDecoder = NULL; | ||
| 103 | m_codec = codec; | ||
| 104 | } | ||
| 105 | |||
| 106 | CDVDDemuxCC::~CDVDDemuxCC() | ||
| 107 | { | ||
| 108 | Dispose(); | ||
| 109 | } | ||
| 110 | |||
| 111 | CDemuxStream* CDVDDemuxCC::GetStream(int iStreamId) | ||
| 112 | { | ||
| 113 | return &m_streams[iStreamId]; | ||
| 114 | } | ||
| 115 | |||
| 116 | int CDVDDemuxCC::GetNrOfStreams() | ||
| 117 | { | ||
| 118 | return m_streams.size(); | ||
| 119 | } | ||
| 120 | |||
| 121 | DemuxPacket* 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 | |||
| 277 | void 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 | |||
| 330 | bool CDVDDemuxCC::OpenDecoder() | ||
| 331 | { | ||
| 332 | m_ccDecoder = new CDecoderCC708(); | ||
| 333 | m_ccDecoder->Init(Handler, this); | ||
| 334 | return true; | ||
| 335 | } | ||
| 336 | |||
| 337 | void 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 | |||
| 356 | DemuxPacket* 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 | |||
| 25 | class CCaptionBlock; | ||
| 26 | class CDecoderCC708; | ||
| 27 | |||
| 28 | class CDVDDemuxCC : public CDVDDemux | ||
| 29 | { | ||
| 30 | public: | ||
| 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 | |||
| 48 | protected: | ||
| 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 | |||
| 29 | using namespace std; | ||
| 30 | |||
| 31 | class CDemuxStreamAudioCDDA | ||
| 32 | : public CDemuxStreamAudio | ||
| 33 | { | ||
| 34 | public: | ||
| 35 | void GetStreamInfo(string& strInfo) | ||
| 36 | { | ||
| 37 | strInfo = "pcm"; | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 41 | CDVDDemuxCDDA::CDVDDemuxCDDA() : CDVDDemux() | ||
| 42 | { | ||
| 43 | m_pInput = NULL; | ||
| 44 | m_stream = NULL; | ||
| 45 | m_bytes = 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | CDVDDemuxCDDA::~CDVDDemuxCDDA() | ||
| 49 | { | ||
| 50 | Dispose(); | ||
| 51 | } | ||
| 52 | |||
| 53 | bool 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 | |||
| 79 | void CDVDDemuxCDDA::Dispose() | ||
| 80 | { | ||
| 81 | delete m_stream; | ||
| 82 | m_stream = NULL; | ||
| 83 | |||
| 84 | m_pInput = NULL; | ||
| 85 | m_bytes = 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | void CDVDDemuxCDDA::Reset() | ||
| 89 | { | ||
| 90 | CDVDInputStream* pInputStream = m_pInput; | ||
| 91 | Dispose(); | ||
| 92 | Open(pInputStream); | ||
| 93 | } | ||
| 94 | |||
| 95 | void CDVDDemuxCDDA::Abort() | ||
| 96 | { | ||
| 97 | if(m_pInput) | ||
| 98 | return m_pInput->Abort(); | ||
| 99 | } | ||
| 100 | |||
| 101 | void CDVDDemuxCDDA::Flush() | ||
| 102 | { | ||
| 103 | } | ||
| 104 | |||
| 105 | #define CDDA_READ_SIZE 4096 | ||
| 106 | DemuxPacket* 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 | |||
| 147 | bool 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 | |||
| 164 | int 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 | |||
| 172 | CDemuxStream* CDVDDemuxCDDA::GetStream(int iStreamId) | ||
| 173 | { | ||
| 174 | if(iStreamId != 0) | ||
| 175 | return NULL; | ||
| 176 | |||
| 177 | return m_stream; | ||
| 178 | } | ||
| 179 | |||
| 180 | int CDVDDemuxCDDA::GetNrOfStreams() | ||
| 181 | { | ||
| 182 | return (m_stream == NULL ? 0 : 1); | ||
| 183 | } | ||
| 184 | |||
| 185 | std::string CDVDDemuxCDDA::GetFileName() | ||
| 186 | { | ||
| 187 | if(m_pInput) | ||
| 188 | return m_pInput->GetFileName(); | ||
| 189 | else | ||
| 190 | return ""; | ||
| 191 | } | ||
| 192 | |||
| 193 | void 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 | |||
| 31 | class CDemuxStreamAudioCDDA; | ||
| 32 | |||
| 33 | class CDVDDemuxCDDA : public CDVDDemux | ||
| 34 | { | ||
| 35 | public: | ||
| 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 | |||
| 54 | protected: | ||
| 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 | |||
| 55 | extern "C" { | ||
| 56 | #include "libavutil/opt.h" | ||
| 57 | } | ||
| 58 | |||
| 59 | struct 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 | ||
| 68 | static 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 | |||
| 79 | void 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 | |||
| 87 | void 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 | |||
| 96 | void 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 | |||
| 105 | void 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 | |||
| 113 | void 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 | |||
| 121 | static 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 | /* | ||
| 133 | static int dvd_file_open(URLContext *h, const char *filename, int flags) | ||
| 134 | { | ||
| 135 | return -1; | ||
| 136 | } | ||
| 137 | */ | ||
| 138 | |||
| 139 | static 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 | /* | ||
| 148 | static int dvd_file_write(URLContext *h, uint8_t* buf, int size) | ||
| 149 | { | ||
| 150 | return -1; | ||
| 151 | } | ||
| 152 | */ | ||
| 153 | static 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 | |||
| 168 | CDVDDemuxFFmpeg::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 | |||
| 184 | CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg() | ||
| 185 | { | ||
| 186 | Dispose(); | ||
| 187 | ff_flush_avutil_log_buffers(); | ||
| 188 | } | ||
| 189 | |||
| 190 | bool 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 | |||
| 202 | bool 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 | |||
| 504 | void 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 | |||
| 534 | void CDVDDemuxFFmpeg::Reset() | ||
| 535 | { | ||
| 536 | CDVDInputStream* pInputStream = m_pInput; | ||
| 537 | Dispose(); | ||
| 538 | Open(pInputStream, m_streaminfo); | ||
| 539 | } | ||
| 540 | |||
| 541 | void 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 | |||
| 553 | void CDVDDemuxFFmpeg::Abort() | ||
| 554 | { | ||
| 555 | m_timeout.SetExpired(); | ||
| 556 | } | ||
| 557 | |||
| 558 | void 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 | |||
| 594 | AVDictionary *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 | |||
| 636 | double 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 | |||
| 661 | DemuxPacket* 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 | |||
| 878 | bool 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 | |||
| 945 | bool 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 | |||
| 959 | void 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 | |||
| 976 | int 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 | */ | ||
| 990 | CDemuxStream* 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 | */ | ||
| 1001 | CDemuxStream* 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 | |||
| 1010 | int CDVDDemuxFFmpeg::GetNrOfStreams() | ||
| 1011 | { | ||
| 1012 | return m_stream_index.size(); | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | static 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 | |||
| 1031 | void 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 | |||
| 1075 | void 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 | |||
| 1084 | CDemuxStream* 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 | */ | ||
| 1339 | void 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 | |||
| 1363 | std::string CDVDDemuxFFmpeg::GetFileName() | ||
| 1364 | { | ||
| 1365 | if(m_pInput) | ||
| 1366 | return m_pInput->GetFileName(); | ||
| 1367 | else | ||
| 1368 | return ""; | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | int 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 | |||
| 1383 | int 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 | |||
| 1404 | void 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 | |||
| 1423 | int64_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 | |||
| 1437 | bool 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 | |||
| 1469 | void 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 | |||
| 1519 | bool 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 | |||
| 1545 | std::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 | |||
| 1570 | std::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 | |||
| 1582 | void 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 | |||
| 1655 | bool 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 | |||
| 1696 | void 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 | |||
| 1712 | void 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 | |||
| 29 | extern "C" { | ||
| 30 | #include "libavformat/avformat.h" | ||
| 31 | } | ||
| 32 | |||
| 33 | class CDVDDemuxFFmpeg; | ||
| 34 | class CURL; | ||
| 35 | |||
| 36 | class CDemuxStreamVideoFFmpeg | ||
| 37 | : public CDemuxStreamVideo | ||
| 38 | { | ||
| 39 | CDVDDemuxFFmpeg *m_parent; | ||
| 40 | AVStream* m_stream; | ||
| 41 | public: | ||
| 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 | |||
| 50 | class CDemuxStreamAudioFFmpeg | ||
| 51 | : public CDemuxStreamAudio | ||
| 52 | { | ||
| 53 | CDVDDemuxFFmpeg *m_parent; | ||
| 54 | AVStream* m_stream; | ||
| 55 | public: | ||
| 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 | |||
| 66 | class CDemuxStreamSubtitleFFmpeg | ||
| 67 | : public CDemuxStreamSubtitle | ||
| 68 | { | ||
| 69 | CDVDDemuxFFmpeg *m_parent; | ||
| 70 | AVStream* m_stream; | ||
| 71 | public: | ||
| 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 | |||
| 86 | struct StereoModeConversionMap; | ||
| 87 | |||
| 88 | class CDVDDemuxFFmpeg : public CDVDDemux | ||
| 89 | { | ||
| 90 | public: | ||
| 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 | |||
| 122 | protected: | ||
| 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 | |||
| 33 | extern "C" { | ||
| 34 | #include "lib/libhts/net.h" | ||
| 35 | #include "lib/libhts/htsmsg.h" | ||
| 36 | #include "lib/libhts/htsmsg_binary.h" | ||
| 37 | } | ||
| 38 | |||
| 39 | using namespace std; | ||
| 40 | using namespace HTSP; | ||
| 41 | |||
| 42 | class CDemuxStreamVideoHTSP | ||
| 43 | : public CDemuxStreamVideo | ||
| 44 | { | ||
| 45 | CDVDDemuxHTSP *m_parent; | ||
| 46 | string m_codec; | ||
| 47 | public: | ||
| 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 | |||
| 63 | class CDemuxStreamAudioHTSP | ||
| 64 | : public CDemuxStreamAudio | ||
| 65 | { | ||
| 66 | CDVDDemuxHTSP *m_parent; | ||
| 67 | string m_codec; | ||
| 68 | public: | ||
| 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 | |||
| 80 | CDVDDemuxHTSP::CDVDDemuxHTSP() | ||
| 81 | : CDVDDemux() | ||
| 82 | , m_Input(NULL) | ||
| 83 | , m_StatusCount(0) | ||
| 84 | { | ||
| 85 | } | ||
| 86 | |||
| 87 | CDVDDemuxHTSP::~CDVDDemuxHTSP() | ||
| 88 | { | ||
| 89 | Dispose(); | ||
| 90 | } | ||
| 91 | |||
| 92 | bool 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 | |||
| 113 | void CDVDDemuxHTSP::Dispose() | ||
| 114 | { | ||
| 115 | } | ||
| 116 | |||
| 117 | void CDVDDemuxHTSP::Reset() | ||
| 118 | { | ||
| 119 | } | ||
| 120 | |||
| 121 | |||
| 122 | void CDVDDemuxHTSP::Flush() | ||
| 123 | { | ||
| 124 | } | ||
| 125 | |||
| 126 | bool 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 | |||
| 139 | htsmsg_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 | |||
| 162 | DemuxPacket* 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 | |||
| 233 | void 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 | } | ||
| 344 | void 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 | |||
| 351 | void 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 | |||
| 366 | CDemuxStream* 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 | |||
| 374 | int CDVDDemuxHTSP::GetNrOfStreams() | ||
| 375 | { | ||
| 376 | return m_Streams.size(); | ||
| 377 | } | ||
| 378 | |||
| 379 | std::string CDVDDemuxHTSP::GetFileName() | ||
| 380 | { | ||
| 381 | if(m_Input) | ||
| 382 | return m_Input->GetFileName(); | ||
| 383 | else | ||
| 384 | return ""; | ||
| 385 | } | ||
| 386 | |||
| 387 | void 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 | |||
| 25 | class CDVDInputStreamHTSP; | ||
| 26 | typedef struct htsmsg htsmsg_t; | ||
| 27 | |||
| 28 | class CDVDDemuxHTSP : public CDVDDemux | ||
| 29 | { | ||
| 30 | public: | ||
| 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 | |||
| 51 | protected: | ||
| 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 | |||
| 31 | using namespace PVR; | ||
| 32 | |||
| 33 | CDemuxStreamPVRInternal::CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent) | ||
| 34 | : m_parent(parent) | ||
| 35 | , m_parser(NULL) | ||
| 36 | , m_context(NULL) | ||
| 37 | , m_parser_split(false) | ||
| 38 | { | ||
| 39 | } | ||
| 40 | |||
| 41 | CDemuxStreamPVRInternal::~CDemuxStreamPVRInternal() | ||
| 42 | { | ||
| 43 | DisposeParser(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void 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 | |||
| 60 | void 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 | |||
| 75 | void 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 | |||
| 99 | void CDemuxStreamSubtitlePVRClient::GetStreamInfo(std::string& strInfo) | ||
| 100 | { | ||
| 101 | } | ||
| 102 | |||
| 103 | CDVDDemuxPVRClient::CDVDDemuxPVRClient() : CDVDDemux() | ||
| 104 | { | ||
| 105 | m_pInput = NULL; | ||
| 106 | for (int i = 0; i < MAX_STREAMS; i++) m_streams[i] = NULL; | ||
| 107 | } | ||
| 108 | |||
| 109 | CDVDDemuxPVRClient::~CDVDDemuxPVRClient() | ||
| 110 | { | ||
| 111 | Dispose(); | ||
| 112 | } | ||
| 113 | |||
| 114 | bool 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 | |||
| 125 | void 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 | |||
| 136 | void 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 | |||
| 144 | void 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 | |||
| 154 | void CDVDDemuxPVRClient::Abort() | ||
| 155 | { | ||
| 156 | if(m_pInput) | ||
| 157 | m_pvrClient->DemuxAbort(); | ||
| 158 | } | ||
| 159 | |||
| 160 | void CDVDDemuxPVRClient::Flush() | ||
| 161 | { | ||
| 162 | if(m_pInput && g_PVRManager.IsStarted()) | ||
| 163 | m_pvrClient->DemuxFlush(); | ||
| 164 | } | ||
| 165 | |||
| 166 | void 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 | |||
| 272 | DemuxPacket* 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 | |||
| 305 | CDemuxStream* CDVDDemuxPVRClient::GetStream(int iStreamId) | ||
| 306 | { | ||
| 307 | if (iStreamId < 0 || iStreamId >= MAX_STREAMS) return NULL; | ||
| 308 | return m_streams[iStreamId]; | ||
| 309 | } | ||
| 310 | |||
| 311 | void 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 | |||
| 445 | int CDVDDemuxPVRClient::GetNrOfStreams() | ||
| 446 | { | ||
| 447 | int i = 0; | ||
| 448 | while (i < MAX_STREAMS && m_streams[i]) i++; | ||
| 449 | return i; | ||
| 450 | } | ||
| 451 | |||
| 452 | std::string CDVDDemuxPVRClient::GetFileName() | ||
| 453 | { | ||
| 454 | if(m_pInput) | ||
| 455 | return m_pInput->GetFileName(); | ||
| 456 | else | ||
| 457 | return ""; | ||
| 458 | } | ||
| 459 | |||
| 460 | void 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 | |||
| 482 | bool 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 | |||
| 489 | void 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 | |||
| 26 | extern "C" { | ||
| 27 | #include "libavcodec/avcodec.h" | ||
| 28 | #include "libavformat/avformat.h" | ||
| 29 | } | ||
| 30 | |||
| 31 | class CDVDDemuxPVRClient; | ||
| 32 | struct PVR_STREAM_PROPERTIES; | ||
| 33 | |||
| 34 | class CDemuxStreamPVRInternal | ||
| 35 | { | ||
| 36 | public: | ||
| 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 | |||
| 48 | class CDemuxStreamVideoPVRClient | ||
| 49 | : public CDemuxStreamVideo | ||
| 50 | , public CDemuxStreamPVRInternal | ||
| 51 | { | ||
| 52 | public: | ||
| 53 | CDemuxStreamVideoPVRClient(CDVDDemuxPVRClient *parent) | ||
| 54 | : CDemuxStreamPVRInternal(parent) | ||
| 55 | {} | ||
| 56 | virtual void GetStreamInfo(std::string& strInfo); | ||
| 57 | }; | ||
| 58 | |||
| 59 | class CDemuxStreamAudioPVRClient | ||
| 60 | : public CDemuxStreamAudio | ||
| 61 | , public CDemuxStreamPVRInternal | ||
| 62 | { | ||
| 63 | public: | ||
| 64 | CDemuxStreamAudioPVRClient(CDVDDemuxPVRClient *parent) | ||
| 65 | : CDemuxStreamPVRInternal(parent) | ||
| 66 | {} | ||
| 67 | virtual void GetStreamInfo(std::string& strInfo); | ||
| 68 | }; | ||
| 69 | |||
| 70 | class CDemuxStreamSubtitlePVRClient | ||
| 71 | : public CDemuxStreamSubtitle | ||
| 72 | , public CDemuxStreamPVRInternal | ||
| 73 | { | ||
| 74 | public: | ||
| 75 | CDemuxStreamSubtitlePVRClient(CDVDDemuxPVRClient *parent) | ||
| 76 | : CDemuxStreamPVRInternal(parent) | ||
| 77 | {} | ||
| 78 | virtual void GetStreamInfo(std::string& strInfo); | ||
| 79 | }; | ||
| 80 | |||
| 81 | |||
| 82 | class CDVDDemuxPVRClient : public CDVDDemux | ||
| 83 | { | ||
| 84 | friend class CDemuxStreamPVRInternal; | ||
| 85 | |||
| 86 | public: | ||
| 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 | |||
| 105 | protected: | ||
| 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 | |||
| 113 | private: | ||
| 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 | ||
| 42 | void CDemuxStreamAudioShoutcast::GetStreamInfo(std::string& strInfo) | ||
| 43 | { | ||
| 44 | strInfo = "Shoutcast"; | ||
| 45 | } | ||
| 46 | |||
| 47 | CDVDDemuxShoutcast::CDVDDemuxShoutcast() : CDVDDemux() | ||
| 48 | { | ||
| 49 | m_pInput = NULL; | ||
| 50 | m_pDemuxStream = NULL; | ||
| 51 | m_iMetaStreamInterval = 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | CDVDDemuxShoutcast::~CDVDDemuxShoutcast() | ||
| 55 | { | ||
| 56 | Dispose(); | ||
| 57 | } | ||
| 58 | |||
| 59 | bool 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 | |||
| 100 | void CDVDDemuxShoutcast::Dispose() | ||
| 101 | { | ||
| 102 | if (m_pDemuxStream) delete m_pDemuxStream; | ||
| 103 | m_pDemuxStream = NULL; | ||
| 104 | |||
| 105 | m_pInput = NULL; | ||
| 106 | } | ||
| 107 | |||
| 108 | void CDVDDemuxShoutcast::Reset() | ||
| 109 | { | ||
| 110 | CDVDInputStream* pInputStream = m_pInput; | ||
| 111 | Dispose(); | ||
| 112 | Open(pInputStream); | ||
| 113 | } | ||
| 114 | |||
| 115 | void CDVDDemuxShoutcast::Flush() | ||
| 116 | { | ||
| 117 | } | ||
| 118 | |||
| 119 | DemuxPacket* 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 | |||
| 172 | bool CDVDDemuxShoutcast::SeekTime(int time, bool backwords, double* startpts) | ||
| 173 | { | ||
| 174 | return false; | ||
| 175 | } | ||
| 176 | |||
| 177 | int CDVDDemuxShoutcast::GetStreamLength() | ||
| 178 | { | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | CDemuxStream* CDVDDemuxShoutcast::GetStream(int iStreamId) | ||
| 183 | { | ||
| 184 | return m_pDemuxStream; | ||
| 185 | } | ||
| 186 | |||
| 187 | int CDVDDemuxShoutcast::GetNrOfStreams() | ||
| 188 | { | ||
| 189 | return 1; | ||
| 190 | } | ||
| 191 | |||
| 192 | std::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 | |||
| 25 | class CDemuxStreamAudioShoutcast : public CDemuxStreamAudio | ||
| 26 | { | ||
| 27 | public: | ||
| 28 | virtual void GetStreamInfo(std::string& strInfo); | ||
| 29 | }; | ||
| 30 | |||
| 31 | #define SHOUTCAST_BUFFER_SIZE 1024 * 32 | ||
| 32 | |||
| 33 | class CDVDDemuxShoutcast : public CDVDDemux | ||
| 34 | { | ||
| 35 | public: | ||
| 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 | |||
| 54 | protected: | ||
| 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 | |||
| 28 | extern "C" { | ||
| 29 | #include "libavcodec/avcodec.h" | ||
| 30 | } | ||
| 31 | |||
| 32 | void 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 | |||
| 46 | DemuxPacket* 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 | |||
| 25 | class CDVDDemuxUtils | ||
| 26 | { | ||
| 27 | public: | ||
| 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 | |||
| 33 | using namespace std; | ||
| 34 | |||
| 35 | CDVDDemuxVobsub::CDVDDemuxVobsub() | ||
| 36 | { | ||
| 37 | } | ||
| 38 | |||
| 39 | CDVDDemuxVobsub::~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 | |||
| 48 | bool 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 | |||
| 122 | void CDVDDemuxVobsub::Reset() | ||
| 123 | { | ||
| 124 | Flush(); | ||
| 125 | } | ||
| 126 | |||
| 127 | void CDVDDemuxVobsub::Flush() | ||
| 128 | { | ||
| 129 | m_Demuxer->Flush(); | ||
| 130 | } | ||
| 131 | |||
| 132 | bool 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 | |||
| 148 | DemuxPacket* 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 | |||
| 172 | bool CDVDDemuxVobsub::ParseLangIdx(SState& state, char* line) | ||
| 173 | { | ||
| 174 | return true; | ||
| 175 | } | ||
| 176 | |||
| 177 | bool 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 | |||
| 196 | bool 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 | |||
| 224 | bool CDVDDemuxVobsub::ParseExtra(SState& state, char* line) | ||
| 225 | { | ||
| 226 | state.extra += line; | ||
| 227 | state.extra += '\n'; | ||
| 228 | return true; | ||
| 229 | } | ||
| 230 | |||
| 231 | bool 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, ×tamp.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 | |||
| 28 | class CDVDOverlayCodecFFmpeg; | ||
| 29 | class CDVDInputStream; | ||
| 30 | class CDVDDemuxFFmpeg; | ||
| 31 | |||
| 32 | class CDVDDemuxVobsub : public CDVDDemux | ||
| 33 | { | ||
| 34 | public: | ||
| 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 | |||
| 50 | private: | ||
| 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 | |||
| 39 | using namespace std; | ||
| 40 | using namespace PVR; | ||
| 41 | |||
| 42 | CDVDDemux* 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 | |||
| 23 | class CDVDDemux; | ||
| 24 | class CDVDInputStream; | ||
| 25 | |||
| 26 | class CDVDFactoryDemuxer | ||
| 27 | { | ||
| 28 | public: | ||
| 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 @@ | |||
| 1 | INCLUDES+=-I@abs_top_srcdir@/xbmc/cores/dvdplayer | ||
| 2 | |||
| 3 | SRCS = DVDDemux.cpp | ||
| 4 | SRCS += DVDDemuxBXA.cpp | ||
| 5 | SRCS += DVDDemuxCDDA.cpp | ||
| 6 | SRCS += DVDDemuxFFmpeg.cpp | ||
| 7 | SRCS += DVDDemuxHTSP.cpp | ||
| 8 | SRCS += DVDDemuxPVRClient.cpp | ||
| 9 | SRCS += DVDDemuxShoutcast.cpp | ||
| 10 | SRCS += DVDDemuxUtils.cpp | ||
| 11 | SRCS += DVDDemuxVobsub.cpp | ||
| 12 | SRCS += DVDDemuxCC.cpp | ||
| 13 | SRCS += DVDFactoryDemuxer.cpp | ||
| 14 | |||
| 15 | LIB = DVDDemuxers.a | ||
| 16 | |||
| 17 | include @abs_top_srcdir@/Makefile.include | ||
| 18 | -include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS))) | ||
| 19 | |||
