[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / filesystem / XbtFile.cpp
blob92586b7f82ade11988f764163017f08dd47f7bed
1 /*
2 * Copyright (C) 2015-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "XbtFile.h"
11 #include "URL.h"
12 #include "filesystem/File.h"
13 #include "filesystem/XbtManager.h"
14 #include "guilib/TextureBundleXBT.h"
15 #include "guilib/XBTFReader.h"
16 #include "utils/StringUtils.h"
18 #include <algorithm>
19 #include <climits>
20 #include <cstring>
21 #include <memory>
22 #include <string>
23 #include <utility>
25 namespace XFILE
28 CXbtFile::CXbtFile()
29 : m_url(),
30 m_xbtfReader(nullptr),
31 m_xbtfFile(),
32 m_frameStartPositions(),
33 m_unpackedFrames()
34 { }
36 CXbtFile::~CXbtFile()
38 Close();
41 bool CXbtFile::Open(const CURL& url)
43 if (m_open)
44 return false;
46 CURL xbtUrl(url);
47 xbtUrl.SetOptions("");
49 if (!GetReaderAndFile(url, m_xbtfReader, m_xbtfFile))
50 return false;
52 m_url = url;
53 m_open = true;
55 uint64_t frameStartPosition = 0;
56 const auto& frames = m_xbtfFile.GetFrames();
57 for (const auto& frame : frames)
59 m_frameStartPositions.push_back(frameStartPosition);
61 frameStartPosition += frame.GetUnpackedSize();
64 m_frameIndex = 0;
65 m_positionWithinFrame = 0;
66 m_positionTotal = 0;
68 m_unpackedFrames.resize(frames.size());
70 return true;
73 void CXbtFile::Close()
75 m_unpackedFrames.clear();
76 m_frameIndex = 0;
77 m_positionWithinFrame = 0;
78 m_positionTotal = 0;
79 m_frameStartPositions.clear();
80 m_open = false;
83 bool CXbtFile::Exists(const CURL& url)
85 CXBTFFile dummy;
86 return GetFile(url, dummy);
89 int64_t CXbtFile::GetPosition()
91 if (!m_open)
92 return -1;
94 return m_positionTotal;
97 int64_t CXbtFile::GetLength()
99 if (!m_open)
100 return -1;
102 return static_cast<int>(m_xbtfFile.GetUnpackedSize());
105 int CXbtFile::Stat(struct __stat64 *buffer)
107 if (!m_open)
108 return -1;
110 return Stat(m_url, buffer);
113 int CXbtFile::Stat(const CURL& url, struct __stat64* buffer)
115 if (!buffer)
116 return -1;
118 *buffer = {};
120 // check if the file exists
121 CXBTFReaderPtr reader;
122 CXBTFFile file;
123 if (!GetReaderAndFile(url, reader, file))
125 // check if the URL points to the XBT file itself
126 if (!url.GetFileName().empty() || !CFile::Exists(url.GetHostName()))
127 return -1;
129 // stat the XBT file itself
130 if (XFILE::CFile::Stat(url.GetHostName(), buffer) != 0)
131 return -1;
133 buffer->st_mode = _S_IFDIR;
134 return 0;
137 // stat the XBT file itself
138 if (XFILE::CFile::Stat(url.GetHostName(), buffer) != 0)
139 return -1;
141 buffer->st_size = file.GetUnpackedSize();
143 return 0;
146 ssize_t CXbtFile::Read(void* lpBuf, size_t uiBufSize)
148 if (lpBuf == nullptr || !m_open)
149 return -1;
151 // nothing to read
152 if (m_xbtfFile.GetFrames().empty() || m_positionTotal >= GetLength())
153 return 0;
155 // we can't read more than is left
156 if (static_cast<int64_t>(uiBufSize) > GetLength() - m_positionTotal)
157 uiBufSize = static_cast<ssize_t>(GetLength() - m_positionTotal);
159 // we can't read more than we can signal with the return value
160 if (uiBufSize > SSIZE_MAX)
161 uiBufSize = SSIZE_MAX;
163 const auto& frames = m_xbtfFile.GetFrames();
165 size_t remaining = uiBufSize;
166 while (remaining > 0)
168 const CXBTFFrame& frame = frames[m_frameIndex];
170 // check if we have already unpacked the current frame
171 if (m_unpackedFrames[m_frameIndex].empty())
173 // unpack the data from the current frame
174 std::vector<uint8_t> unpackedFrame =
175 CTextureBundleXBT::UnpackFrame(*m_xbtfReader.get(), frame);
176 if (unpackedFrame.empty())
178 Close();
179 return -1;
182 m_unpackedFrames[m_frameIndex] = std::move(unpackedFrame);
185 // determine how many bytes we need to copy from the current frame
186 uint64_t remainingBytesInFrame = frame.GetUnpackedSize() - m_positionWithinFrame;
187 size_t bytesToCopy = remaining;
188 if (remainingBytesInFrame <= SIZE_MAX)
189 bytesToCopy = std::min(remaining, static_cast<size_t>(remainingBytesInFrame));
191 // copy the data
192 memcpy(lpBuf, m_unpackedFrames[m_frameIndex].data() + m_positionWithinFrame, bytesToCopy);
193 m_positionWithinFrame += bytesToCopy;
194 m_positionTotal += bytesToCopy;
195 remaining -= bytesToCopy;
197 // check if we need to go to the next frame and there is a next frame
198 if (m_positionWithinFrame >= frame.GetUnpackedSize() && m_frameIndex < frames.size() - 1)
200 m_positionWithinFrame = 0;
201 m_frameIndex += 1;
205 return uiBufSize;
208 int64_t CXbtFile::Seek(int64_t iFilePosition, int iWhence)
210 if (!m_open)
211 return -1;
213 int64_t newPosition = m_positionTotal;
214 switch (iWhence)
216 case SEEK_SET:
217 newPosition = iFilePosition;
218 break;
220 case SEEK_CUR:
221 newPosition += iFilePosition;
222 break;
224 case SEEK_END:
225 newPosition = GetLength() + iFilePosition;
226 break;
228 // unsupported seek mode
229 default:
230 return -1;
233 // can't seek before the beginning or after the end of the file
234 if (newPosition < 0 || newPosition >= GetLength())
235 return -1;
237 // seeking backwards doesn't require additional work
238 if (newPosition <= m_positionTotal)
240 m_positionTotal = newPosition;
241 return m_positionTotal;
244 // when seeking forward we need to unpack all frames we seek past
245 const auto& frames = m_xbtfFile.GetFrames();
246 while (m_positionTotal < newPosition)
248 const CXBTFFrame& frame = frames[m_frameIndex];
250 // check if we have already unpacked the current frame
251 if (m_unpackedFrames[m_frameIndex].empty())
253 // unpack the data from the current frame
254 std::vector<uint8_t> unpackedFrame =
255 CTextureBundleXBT::UnpackFrame(*m_xbtfReader.get(), frame);
256 if (unpackedFrame.empty())
258 Close();
259 return -1;
262 m_unpackedFrames[m_frameIndex] = std::move(unpackedFrame);
265 int64_t remainingBytesToSeek = newPosition - m_positionTotal;
266 // check if the new position is within the current frame
267 uint64_t remainingBytesInFrame = frame.GetUnpackedSize() - m_positionWithinFrame;
268 if (static_cast<uint64_t>(remainingBytesToSeek) < remainingBytesInFrame)
270 m_positionWithinFrame += remainingBytesToSeek;
271 break;
274 // otherwise move to the end of the frame
275 m_positionTotal += remainingBytesInFrame;
276 m_positionWithinFrame += remainingBytesInFrame;
278 // and go to the next frame if there is a next frame
279 if (m_frameIndex < frames.size() - 1)
281 m_positionWithinFrame = 0;
282 m_frameIndex += 1;
286 m_positionTotal = newPosition;
287 return m_positionTotal;
290 uint32_t CXbtFile::GetImageWidth() const
292 CXBTFFrame frame;
293 if (!GetFirstFrame(frame))
294 return false;
296 return frame.GetWidth();
299 uint32_t CXbtFile::GetImageHeight() const
301 CXBTFFrame frame;
302 if (!GetFirstFrame(frame))
303 return false;
305 return frame.GetHeight();
308 uint32_t CXbtFile::GetImageFormat() const
310 CXBTFFrame frame;
311 if (!GetFirstFrame(frame))
312 return false;
314 return frame.GetFormat();
317 bool CXbtFile::HasImageAlpha() const
319 CXBTFFrame frame;
320 if (!GetFirstFrame(frame))
321 return false;
323 return frame.HasAlpha();
326 bool CXbtFile::GetFirstFrame(CXBTFFrame& frame) const
328 if (!m_open)
329 return false;
331 const auto& frames = m_xbtfFile.GetFrames();
332 if (frames.empty())
333 return false;
335 frame = frames.at(0);
336 return true;
339 bool CXbtFile::GetReader(const CURL& url, CXBTFReaderPtr& reader)
341 CURL xbtUrl(url);
342 xbtUrl.SetOptions("");
344 return CXbtManager::GetInstance().GetReader(xbtUrl, reader);
347 bool CXbtFile::GetReaderAndFile(const CURL& url, CXBTFReaderPtr& reader, CXBTFFile& file)
349 if (!GetReader(url, reader))
350 return false;
352 CURL xbtUrl(url);
353 xbtUrl.SetOptions("");
355 // CXBTFReader stores all filenames in lower case
356 std::string fileName = xbtUrl.GetFileName();
357 StringUtils::ToLower(fileName);
359 return reader->Get(fileName, file);
362 bool CXbtFile::GetFile(const CURL& url, CXBTFFile& file)
364 CXBTFReaderPtr reader;
365 return GetReaderAndFile(url, reader, file);