PageRenderTime 154ms CodeModel.GetById 28ms RepoModel.GetById 2ms app.codeStats 0ms

/xbmc/guilib/TextureBundleXBT.cpp

https://gitlab.com/sloshedpuppie/LetsGoRetro
C++ | 318 lines | 233 code | 53 blank | 32 comment | 52 complexity | 1e754225ef791fa337652a65cfafd7a8 MD5 | raw file
  1. /*
  2. * Copyright (C) 2005-2015 Team Kodi
  3. * http://kodi.tv
  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 Kodi; see the file COPYING. If not, see
  17. * <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include "system.h"
  21. #include "TextureBundleXBT.h"
  22. #include "Texture.h"
  23. #include "GraphicContext.h"
  24. #include "utils/log.h"
  25. #include "addons/Skin.h"
  26. #include "settings/Settings.h"
  27. #include "filesystem/SpecialProtocol.h"
  28. #include "filesystem/XbtManager.h"
  29. #include "utils/URIUtils.h"
  30. #include "utils/StringUtils.h"
  31. #include "XBTF.h"
  32. #include <lzo/lzo1x.h>
  33. #ifdef TARGET_WINDOWS
  34. #pragma comment(lib,"liblzo2.lib")
  35. #endif
  36. CTextureBundleXBT::CTextureBundleXBT(void)
  37. {
  38. m_themeBundle = false;
  39. m_TimeStamp = 0;
  40. }
  41. CTextureBundleXBT::~CTextureBundleXBT(void)
  42. {
  43. Cleanup();
  44. }
  45. bool CTextureBundleXBT::OpenBundle()
  46. {
  47. Cleanup();
  48. // Find the correct texture file (skin or theme)
  49. if (m_themeBundle)
  50. {
  51. // if we are the theme bundle, we only load if the user has chosen
  52. // a valid theme (or the skin has a default one)
  53. std::string theme = CSettings::GetInstance().GetString(CSettings::SETTING_LOOKANDFEEL_SKINTHEME);
  54. if (!theme.empty() && !StringUtils::EqualsNoCase(theme, "SKINDEFAULT"))
  55. {
  56. std::string themeXBT(URIUtils::ReplaceExtension(theme, ".xbt"));
  57. m_path = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media");
  58. m_path = URIUtils::AddFileToFolder(m_path, themeXBT);
  59. }
  60. else
  61. {
  62. return false;
  63. }
  64. }
  65. else
  66. {
  67. m_path = URIUtils::AddFileToFolder(g_graphicsContext.GetMediaDir(), "media/Textures.xbt");
  68. }
  69. m_path = CSpecialProtocol::TranslatePathConvertCase(m_path);
  70. // Load the texture file
  71. if (!XFILE::CXbtManager::GetInstance().GetReader(CURL(m_path), m_XBTFReader))
  72. {
  73. return false;
  74. }
  75. CLog::Log(LOGDEBUG, "%s - Opened bundle %s", __FUNCTION__, m_path.c_str());
  76. m_TimeStamp = m_XBTFReader->GetLastModificationTimestamp();
  77. if (lzo_init() != LZO_E_OK)
  78. {
  79. return false;
  80. }
  81. return true;
  82. }
  83. bool CTextureBundleXBT::HasFile(const std::string& Filename)
  84. {
  85. if ((m_XBTFReader == nullptr || !m_XBTFReader->IsOpen()) && !OpenBundle())
  86. return false;
  87. if (m_XBTFReader->GetLastModificationTimestamp() > m_TimeStamp)
  88. {
  89. CLog::Log(LOGINFO, "Texture bundle has changed, reloading");
  90. if (!OpenBundle())
  91. return false;
  92. }
  93. std::string name = Normalize(Filename);
  94. return m_XBTFReader->Exists(name);
  95. }
  96. void CTextureBundleXBT::GetTexturesFromPath(const std::string &path, std::vector<std::string> &textures)
  97. {
  98. if (path.size() > 1 && path[1] == ':')
  99. return;
  100. if ((m_XBTFReader == nullptr || !m_XBTFReader->IsOpen()) && !OpenBundle())
  101. return;
  102. std::string testPath = Normalize(path);
  103. URIUtils::AddSlashAtEnd(testPath);
  104. std::vector<CXBTFFile> files = m_XBTFReader->GetFiles();
  105. for (size_t i = 0; i < files.size(); i++)
  106. {
  107. std::string path = files[i].GetPath();
  108. if (StringUtils::StartsWithNoCase(path, testPath))
  109. textures.push_back(path);
  110. }
  111. }
  112. bool CTextureBundleXBT::LoadTexture(const std::string& Filename, CBaseTexture** ppTexture,
  113. int &width, int &height)
  114. {
  115. std::string name = Normalize(Filename);
  116. CXBTFFile file;
  117. if (!m_XBTFReader->Get(name, file))
  118. return false;
  119. if (file.GetFrames().empty())
  120. return false;
  121. CXBTFFrame& frame = file.GetFrames().at(0);
  122. if (!ConvertFrameToTexture(Filename, frame, ppTexture))
  123. {
  124. return false;
  125. }
  126. width = frame.GetWidth();
  127. height = frame.GetHeight();
  128. return true;
  129. }
  130. int CTextureBundleXBT::LoadAnim(const std::string& Filename, CBaseTexture*** ppTextures,
  131. int &width, int &height, int& nLoops, int** ppDelays)
  132. {
  133. std::string name = Normalize(Filename);
  134. CXBTFFile file;
  135. if (!m_XBTFReader->Get(name, file))
  136. return false;
  137. if (file.GetFrames().empty())
  138. return false;
  139. size_t nTextures = file.GetFrames().size();
  140. *ppTextures = new CBaseTexture*[nTextures];
  141. *ppDelays = new int[nTextures];
  142. for (size_t i = 0; i < nTextures; i++)
  143. {
  144. CXBTFFrame& frame = file.GetFrames().at(i);
  145. if (!ConvertFrameToTexture(Filename, frame, &((*ppTextures)[i])))
  146. {
  147. return false;
  148. }
  149. (*ppDelays)[i] = frame.GetDuration();
  150. }
  151. width = file.GetFrames().at(0).GetWidth();
  152. height = file.GetFrames().at(0).GetHeight();
  153. nLoops = file.GetLoop();
  154. return nTextures;
  155. }
  156. bool CTextureBundleXBT::ConvertFrameToTexture(const std::string& name, CXBTFFrame& frame, CBaseTexture** ppTexture)
  157. {
  158. // found texture - allocate the necessary buffers
  159. unsigned char *buffer = new unsigned char [(size_t)frame.GetPackedSize()];
  160. if (buffer == NULL)
  161. {
  162. CLog::Log(LOGERROR, "Out of memory loading texture: %s (need %" PRIu64" bytes)", name.c_str(), frame.GetPackedSize());
  163. return false;
  164. }
  165. // load the compressed texture
  166. if (!m_XBTFReader->Load(frame, buffer))
  167. {
  168. CLog::Log(LOGERROR, "Error loading texture: %s", name.c_str());
  169. delete[] buffer;
  170. return false;
  171. }
  172. // check if it's packed with lzo
  173. if (frame.IsPacked())
  174. { // unpack
  175. unsigned char *unpacked = new unsigned char[(size_t)frame.GetUnpackedSize()];
  176. if (unpacked == NULL)
  177. {
  178. CLog::Log(LOGERROR, "Out of memory unpacking texture: %s (need %" PRIu64" bytes)", name.c_str(), frame.GetUnpackedSize());
  179. delete[] buffer;
  180. return false;
  181. }
  182. lzo_uint s = (lzo_uint)frame.GetUnpackedSize();
  183. if (lzo1x_decompress_safe(buffer, (lzo_uint)frame.GetPackedSize(), unpacked, &s, NULL) != LZO_E_OK ||
  184. s != frame.GetUnpackedSize())
  185. {
  186. CLog::Log(LOGERROR, "Error loading texture: %s: Decompression error", name.c_str());
  187. delete[] buffer;
  188. delete[] unpacked;
  189. return false;
  190. }
  191. delete[] buffer;
  192. buffer = unpacked;
  193. }
  194. // create an xbmc texture
  195. *ppTexture = new CTexture();
  196. (*ppTexture)->LoadFromMemory(frame.GetWidth(), frame.GetHeight(), 0, frame.GetFormat(), frame.HasAlpha(), buffer);
  197. delete[] buffer;
  198. return true;
  199. }
  200. void CTextureBundleXBT::Cleanup()
  201. {
  202. if (m_XBTFReader != nullptr && m_XBTFReader->IsOpen())
  203. {
  204. XFILE::CXbtManager::GetInstance().Release(CURL(m_path));
  205. CLog::Log(LOGDEBUG, "%s - Closed %sbundle", __FUNCTION__, m_themeBundle ? "theme " : "");
  206. }
  207. }
  208. void CTextureBundleXBT::SetThemeBundle(bool themeBundle)
  209. {
  210. m_themeBundle = themeBundle;
  211. }
  212. // normalize to how it's stored within the bundle
  213. // lower case + using forward slash rather than back slash
  214. std::string CTextureBundleXBT::Normalize(const std::string &name)
  215. {
  216. std::string newName(name);
  217. StringUtils::Trim(newName);
  218. StringUtils::ToLower(newName);
  219. StringUtils::Replace(newName, '\\','/');
  220. return newName;
  221. }
  222. uint8_t* CTextureBundleXBT::UnpackFrame(const CXBTFReader& reader, const CXBTFFrame& frame)
  223. {
  224. uint8_t* packedBuffer = new uint8_t[static_cast<size_t>(frame.GetPackedSize())];
  225. if (packedBuffer == nullptr)
  226. {
  227. CLog::Log(LOGERROR, "CTextureBundleXBT: out of memory loading frame with %" PRIu64" packed bytes", frame.GetPackedSize());
  228. return nullptr;
  229. }
  230. // load the compressed texture
  231. if (!reader.Load(frame, packedBuffer))
  232. {
  233. CLog::Log(LOGERROR, "CTextureBundleXBT: error loading frame");
  234. delete[] packedBuffer;
  235. return nullptr;
  236. }
  237. // if the frame isn't packed there's nothing else to be done
  238. if (!frame.IsPacked())
  239. return packedBuffer;
  240. uint8_t* unpackedBuffer = new uint8_t[static_cast<size_t>(frame.GetUnpackedSize())];
  241. if (unpackedBuffer == nullptr)
  242. {
  243. CLog::Log(LOGERROR, "CTextureBundleXBT: out of memory loading frame with %" PRIu64" unpacked bytes", frame.GetPackedSize());
  244. delete[] packedBuffer;
  245. return nullptr;
  246. }
  247. // make sure lzo is initialized
  248. if (lzo_init() != LZO_E_OK)
  249. {
  250. CLog::Log(LOGERROR, "CTextureBundleXBT: failed to initialize lzo");
  251. delete[] packedBuffer;
  252. delete[] unpackedBuffer;
  253. return nullptr;
  254. }
  255. lzo_uint size = static_cast<lzo_uint>(frame.GetUnpackedSize());
  256. if (lzo1x_decompress_safe(packedBuffer, static_cast<lzo_uint>(frame.GetPackedSize()), unpackedBuffer, &size, nullptr) != LZO_E_OK || size != frame.GetUnpackedSize())
  257. {
  258. CLog::Log(LOGERROR, "CTextureBundleXBT: failed to decompress frame with %" PRIu64" unpacked bytes to %" PRIu64" bytes", frame.GetPackedSize(), frame.GetUnpackedSize());
  259. delete[] packedBuffer;
  260. delete[] unpackedBuffer;
  261. return nullptr;
  262. }
  263. delete[] packedBuffer;
  264. return unpackedBuffer;
  265. }