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