1 /*
2  *  Copyright (C) 2015-2020 Garrett Brown
3  *  Copyright (C) 2015-2020 Team Kodi
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSE.md for more information.
7  */
8 
9 #include "StorageManager.h"
10 #include "JustABunchOfFiles.h"
11 #include "StorageUtils.h"
12 #include "buttonmapper/ButtonMapper.h"
13 #include "log/Log.h"
14 #include "storage/api/DatabaseJoystickAPI.h"
15 //#include "storage/retroarch/DatabaseRetroarch.h" // TODO
16 #include "storage/xml/DatabaseXml.h"
17 
18 #include "addon.h"
19 
20 #include <kodi/tools/StringUtils.h>
21 
22 using namespace JOYSTICK;
23 
24 // Resources folder for add-on and user data
25 #define USER_RESOURCES_FOLDER   "resources"
26 #define ADDON_RESOURCES_FOLDER  "resources"
27 
28 // Subdirectory under resources folder for storing button maps
29 #define BUTTONMAP_FOLDER        "buttonmaps"
30 
CStorageManager(void)31 CStorageManager::CStorageManager(void) :
32   m_peripheralLib(nullptr)
33 {
34 }
35 
~CStorageManager()36 CStorageManager::~CStorageManager()
37 {
38   Deinitialize();
39 }
40 
Get(void)41 CStorageManager& CStorageManager::Get(void)
42 {
43   static CStorageManager _instance;
44   return _instance;
45 }
46 
Initialize(CPeripheralJoystick * peripheralLib)47 bool CStorageManager::Initialize(CPeripheralJoystick* peripheralLib)
48 {
49   std::string strUserPath = peripheralLib->UserPath();
50   std::string strAddonPath = peripheralLib->AddonPath();
51 
52   if (peripheralLib == NULL || strUserPath.empty() || strAddonPath.empty())
53     return false;
54 
55   m_peripheralLib = peripheralLib;
56 
57   m_buttonMapper.reset(new CButtonMapper(peripheralLib));
58 
59   if (!m_buttonMapper->Initialize(m_familyManager))
60     return false;
61 
62   // Remove slash at end
63   kodi::tools::StringUtils::TrimRight(strUserPath, "\\/");
64   kodi::tools::StringUtils::TrimRight(strAddonPath, "\\/");
65 
66   strUserPath += "/" USER_RESOURCES_FOLDER;
67   strAddonPath += "/" ADDON_RESOURCES_FOLDER;
68 
69   // Ensure resources path exists in user data
70   CStorageUtils::EnsureDirectoryExists(strUserPath);
71 
72   std::string strUserButtonMapPath = strUserPath + "/" BUTTONMAP_FOLDER;
73   std::string strAddonButtonMapPath = strAddonPath + "/" BUTTONMAP_FOLDER;
74 
75   // Ensure button map path exists in user data
76   CStorageUtils::EnsureDirectoryExists(strUserButtonMapPath);
77 
78   m_databases.push_back(DatabasePtr(new CDatabaseXml(strUserButtonMapPath, true, m_buttonMapper->GetCallbacks(), this)));
79   //m_databases.push_back(DatabasePtr(new CDatabaseRetroArch(strUserButtonMapPath, true, &m_controllerMapper))); // TODO
80   m_databases.push_back(DatabasePtr(new CDatabaseXml(strAddonButtonMapPath, false, m_buttonMapper->GetCallbacks(), this)));
81   //m_databases.push_back(DatabasePtr(new CDatabaseRetroArch(strAddonButtonMapPath, false))); // TODO
82 
83   m_databases.push_back(DatabasePtr(new CDatabaseJoystickAPI(m_buttonMapper->GetCallbacks())));
84 
85   for (auto& database : m_databases)
86     m_buttonMapper->RegisterDatabase(database);
87 
88   m_familyManager.Initialize(strAddonPath);
89 
90   return true;
91 }
92 
Deinitialize(void)93 void CStorageManager::Deinitialize(void)
94 {
95   m_familyManager.Deinitialize();
96   m_databases.clear();
97   m_buttonMapper.reset();
98   m_peripheralLib = nullptr;
99 }
100 
GetFeatures(const kodi::addon::Joystick & joystick,const std::string & strControllerId,FeatureVector & features)101 void CStorageManager::GetFeatures(const kodi::addon::Joystick& joystick,
102                                   const std::string& strControllerId,
103                                   FeatureVector& features)
104 {
105   if (m_buttonMapper)
106     m_buttonMapper->GetFeatures(joystick, strControllerId, features);
107 }
108 
MapFeatures(const kodi::addon::Joystick & joystick,const std::string & strControllerId,const FeatureVector & features)109 bool CStorageManager::MapFeatures(const kodi::addon::Joystick& joystick,
110                                   const std::string& strControllerId,
111                                   const FeatureVector& features)
112 {
113   bool bSuccess = false;
114 
115   for (DatabaseVector::const_iterator it = m_databases.begin(); it != m_databases.end(); ++it)
116     bSuccess |= (*it)->MapFeatures(joystick, strControllerId, features);
117 
118   return bSuccess;
119 }
120 
GetIgnoredPrimitives(const kodi::addon::Joystick & joystick,PrimitiveVector & primitives)121 void CStorageManager::GetIgnoredPrimitives(const kodi::addon::Joystick& joystick, PrimitiveVector& primitives)
122 {
123   for (DatabaseVector::const_iterator it = m_databases.begin(); it != m_databases.end(); ++it)
124   {
125     if ((*it)->GetIgnoredPrimitives(joystick, primitives))
126       break;
127   }
128 }
129 
SetIgnoredPrimitives(const kodi::addon::Joystick & joystick,const PrimitiveVector & primitives)130 bool CStorageManager::SetIgnoredPrimitives(const kodi::addon::Joystick& joystick, const PrimitiveVector& primitives)
131 {
132   bool bSuccess = false;
133 
134   for (DatabaseVector::const_iterator it = m_databases.begin(); it != m_databases.end(); ++it)
135     bSuccess |= (*it)->SetIgnoredPrimitives(joystick, primitives);
136 
137   return bSuccess;
138 }
139 
SaveButtonMap(const kodi::addon::Joystick & joystick)140 bool CStorageManager::SaveButtonMap(const kodi::addon::Joystick& joystick)
141 {
142   bool bModified = false;
143 
144   for (DatabaseVector::const_iterator it = m_databases.begin(); it != m_databases.end(); ++it)
145     bModified |= (*it)->SaveButtonMap(joystick);
146 
147   return bModified;
148 }
149 
RevertButtonMap(const kodi::addon::Joystick & joystick)150 bool CStorageManager::RevertButtonMap(const kodi::addon::Joystick& joystick)
151 {
152   bool bModified = false;
153 
154   for (DatabaseVector::const_iterator it = m_databases.begin(); it != m_databases.end(); ++it)
155     bModified |= (*it)->RevertButtonMap(joystick);
156 
157   return bModified;
158 }
159 
ResetButtonMap(const kodi::addon::Joystick & joystick,const std::string & strControllerId)160 bool CStorageManager::ResetButtonMap(const kodi::addon::Joystick& joystick, const std::string& strControllerId)
161 {
162   bool bModified = false;
163 
164   for (DatabaseVector::const_iterator it = m_databases.begin(); it != m_databases.end(); ++it)
165     bModified |= (*it)->ResetButtonMap(joystick, strControllerId);
166 
167   return bModified;
168 }
169 
RefreshButtonMaps(const std::string & strDeviceName)170 void CStorageManager::RefreshButtonMaps(const std::string& strDeviceName /* = "" */)
171 {
172   // Request the frontend to refresh its button maps
173   if (m_peripheralLib)
174     m_peripheralLib->RefreshButtonMaps(strDeviceName);
175 }
176 
FeatureType(const std::string & strControllerId,const std::string & featureName)177 JOYSTICK_FEATURE_TYPE CStorageManager::FeatureType(const std::string& strControllerId, const std::string &featureName)
178 {
179   if (m_peripheralLib)
180     return m_peripheralLib->FeatureType(strControllerId, featureName);
181 
182   return JOYSTICK_FEATURE_TYPE_UNKNOWN;
183 }
184