summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/Archive.cpp
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
committermanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
commitbe933ef2241d79558f91796cc5b3a161f72ebf9c (patch)
treefe3ab2f130e20c99001f2d7a81d610c78c96a3f4 /xbmc/utils/Archive.cpp
parent5f8335c1e49ce108ef3481863833c98efa00411b (diff)
downloadkodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.gz
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.bz2
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.zip
sync with upstream
Diffstat (limited to 'xbmc/utils/Archive.cpp')
-rw-r--r--xbmc/utils/Archive.cpp461
1 files changed, 461 insertions, 0 deletions
diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp
new file mode 100644
index 0000000..1b8392b
--- /dev/null
+++ b/xbmc/utils/Archive.cpp
@@ -0,0 +1,461 @@
1/*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#include "Archive.h"
10
11#include "IArchivable.h"
12#include "filesystem/File.h"
13#include "utils/Variant.h"
14#include "utils/log.h"
15
16#include <algorithm>
17#include <cstdint>
18#include <cstring>
19#include <stdexcept>
20
21#ifdef __GNUC__
22#pragma GCC diagnostic ignored "-Wlong-long"
23#endif
24
25using namespace XFILE;
26
27//arbitrarily chosen, should be plenty big enough for our strings
28//without causing random bad things happening
29//not very bad, just tiny bad
30#define MAX_STRING_SIZE 100*1024*1024
31
32CArchive::CArchive(CFile* pFile, int mode)
33{
34 m_pFile = pFile;
35 m_iMode = mode;
36
37 m_pBuffer = std::unique_ptr<uint8_t[]>(new uint8_t[CARCHIVE_BUFFER_MAX]);
38 memset(m_pBuffer.get(), 0, CARCHIVE_BUFFER_MAX);
39 if (mode == load)
40 {
41 m_BufferPos = m_pBuffer.get() + CARCHIVE_BUFFER_MAX;
42 m_BufferRemain = 0;
43 }
44 else
45 {
46 m_BufferPos = m_pBuffer.get();
47 m_BufferRemain = CARCHIVE_BUFFER_MAX;
48 }
49}
50
51CArchive::~CArchive()
52{
53 FlushBuffer();
54}
55
56void CArchive::Close()
57{
58 FlushBuffer();
59}
60
61bool CArchive::IsLoading() const
62{
63 return (m_iMode == load);
64}
65
66bool CArchive::IsStoring() const
67{
68 return (m_iMode == store);
69}
70
71CArchive& CArchive::operator<<(float f)
72{
73 return streamout(&f, sizeof(f));
74}
75
76CArchive& CArchive::operator<<(double d)
77{
78 return streamout(&d, sizeof(d));
79}
80
81CArchive& CArchive::operator<<(short int s)
82{
83 return streamout(&s, sizeof(s));
84}
85
86CArchive& CArchive::operator<<(unsigned short int us)
87{
88 return streamout(&us, sizeof(us));
89}
90
91CArchive& CArchive::operator<<(int i)
92{
93 return streamout(&i, sizeof(i));
94}
95
96CArchive& CArchive::operator<<(unsigned int ui)
97{
98 return streamout(&ui, sizeof(ui));
99}
100
101CArchive& CArchive::operator<<(long int l)
102{
103 return streamout(&l, sizeof(l));
104}
105
106CArchive& CArchive::operator<<(unsigned long int ul)
107{
108 return streamout(&ul, sizeof(ul));
109}
110
111CArchive& CArchive::operator<<(long long int ll)
112{
113 return streamout(&ll, sizeof(ll));
114}
115
116CArchive& CArchive::operator<<(unsigned long long int ull)
117{
118 return streamout(&ull, sizeof(ull));
119}
120
121CArchive& CArchive::operator<<(bool b)
122{
123 return streamout(&b, sizeof(b));
124}
125
126CArchive& CArchive::operator<<(char c)
127{
128 return streamout(&c, sizeof(c));
129}
130
131CArchive& CArchive::operator<<(const std::string& str)
132{
133 auto size = static_cast<uint32_t>(str.size());
134 if (size > MAX_STRING_SIZE)
135 throw std::out_of_range("String too large, over 100MB");
136
137 *this << size;
138
139 return streamout(str.data(), size * sizeof(char));
140}
141
142CArchive& CArchive::operator<<(const std::wstring& wstr)
143{
144 if (wstr.size() > MAX_STRING_SIZE)
145 throw std::out_of_range("String too large, over 100MB");
146
147 auto size = static_cast<uint32_t>(wstr.size());
148
149 *this << size;
150
151 return streamout(wstr.data(), size * sizeof(wchar_t));
152}
153
154CArchive& CArchive::operator<<(const KODI::TIME::SystemTime& time)
155{
156 return streamout(&time, sizeof(KODI::TIME::SystemTime));
157}
158
159CArchive& CArchive::operator<<(IArchivable& obj)
160{
161 obj.Archive(*this);
162
163 return *this;
164}
165
166CArchive& CArchive::operator<<(const CVariant& variant)
167{
168 *this << static_cast<int>(variant.type());
169 switch (variant.type())
170 {
171 case CVariant::VariantTypeInteger:
172 *this << variant.asInteger();
173 break;
174 case CVariant::VariantTypeUnsignedInteger:
175 *this << variant.asUnsignedInteger();
176 break;
177 case CVariant::VariantTypeBoolean:
178 *this << variant.asBoolean();
179 break;
180 case CVariant::VariantTypeString:
181 *this << variant.asString();
182 break;
183 case CVariant::VariantTypeWideString:
184 *this << variant.asWideString();
185 break;
186 case CVariant::VariantTypeDouble:
187 *this << variant.asDouble();
188 break;
189 case CVariant::VariantTypeArray:
190 *this << variant.size();
191 for (auto i = variant.begin_array(); i != variant.end_array(); ++i)
192 *this << *i;
193 break;
194 case CVariant::VariantTypeObject:
195 *this << variant.size();
196 for (auto itr = variant.begin_map(); itr != variant.end_map(); ++itr)
197 {
198 *this << itr->first;
199 *this << itr->second;
200 }
201 break;
202 case CVariant::VariantTypeNull:
203 case CVariant::VariantTypeConstNull:
204 default:
205 break;
206 }
207
208 return *this;
209}
210
211CArchive& CArchive::operator<<(const std::vector<std::string>& strArray)
212{
213 if (std::numeric_limits<uint32_t>::max() < strArray.size())
214 throw std::out_of_range("Array too large, over 2^32 in size");
215
216 *this << static_cast<uint32_t>(strArray.size());
217
218 for (auto&& item : strArray)
219 *this << item;
220
221 return *this;
222}
223
224CArchive& CArchive::operator<<(const std::vector<int>& iArray)
225{
226 if (std::numeric_limits<uint32_t>::max() < iArray.size())
227 throw std::out_of_range("Array too large, over 2^32 in size");
228
229 *this << static_cast<uint32_t>(iArray.size());
230
231 for (auto&& item : iArray)
232 *this << item;
233
234 return *this;
235}
236
237CArchive& CArchive::operator>>(std::string& str)
238{
239 uint32_t iLength = 0;
240 *this >> iLength;
241
242 if (iLength > MAX_STRING_SIZE)
243 throw std::out_of_range("String too large, over 100MB");
244
245 auto s = std::unique_ptr<char[]>(new char[iLength]);
246 streamin(s.get(), iLength * sizeof(char));
247 str.assign(s.get(), iLength);
248
249 return *this;
250}
251
252CArchive& CArchive::operator>>(std::wstring& wstr)
253{
254 uint32_t iLength = 0;
255 *this >> iLength;
256
257 if (iLength > MAX_STRING_SIZE)
258 throw std::out_of_range("String too large, over 100MB");
259
260 auto p = std::unique_ptr<wchar_t[]>(new wchar_t[iLength]);
261 streamin(p.get(), iLength * sizeof(wchar_t));
262 wstr.assign(p.get(), iLength);
263
264 return *this;
265}
266
267CArchive& CArchive::operator>>(KODI::TIME::SystemTime& time)
268{
269 return streamin(&time, sizeof(KODI::TIME::SystemTime));
270}
271
272CArchive& CArchive::operator>>(IArchivable& obj)
273{
274 obj.Archive(*this);
275
276 return *this;
277}
278
279CArchive& CArchive::operator>>(CVariant& variant)
280{
281 int type;
282 *this >> type;
283 variant = CVariant(static_cast<CVariant::VariantType>(type));
284
285 switch (variant.type())
286 {
287 case CVariant::VariantTypeInteger:
288 {
289 int64_t value;
290 *this >> value;
291 variant = value;
292 break;
293 }
294 case CVariant::VariantTypeUnsignedInteger:
295 {
296 uint64_t value;
297 *this >> value;
298 variant = value;
299 break;
300 }
301 case CVariant::VariantTypeBoolean:
302 {
303 bool value;
304 *this >> value;
305 variant = value;
306 break;
307 }
308 case CVariant::VariantTypeString:
309 {
310 std::string value;
311 *this >> value;
312 variant = value;
313 break;
314 }
315 case CVariant::VariantTypeWideString:
316 {
317 std::wstring value;
318 *this >> value;
319 variant = value;
320 break;
321 }
322 case CVariant::VariantTypeDouble:
323 {
324 double value;
325 *this >> value;
326 variant = value;
327 break;
328 }
329 case CVariant::VariantTypeArray:
330 {
331 unsigned int size;
332 *this >> size;
333 for (; size > 0; size--)
334 {
335 CVariant value;
336 *this >> value;
337 variant.append(value);
338 }
339 break;
340 }
341 case CVariant::VariantTypeObject:
342 {
343 unsigned int size;
344 *this >> size;
345 for (; size > 0; size--)
346 {
347 std::string name;
348 CVariant value;
349 *this >> name;
350 *this >> value;
351 variant[name] = value;
352 }
353 break;
354 }
355 case CVariant::VariantTypeNull:
356 case CVariant::VariantTypeConstNull:
357 default:
358 break;
359 }
360
361 return *this;
362}
363
364CArchive& CArchive::operator>>(std::vector<std::string>& strArray)
365{
366 uint32_t size;
367 *this >> size;
368 strArray.clear();
369 for (uint32_t index = 0; index < size; index++)
370 {
371 std::string str;
372 *this >> str;
373 strArray.push_back(std::move(str));
374 }
375
376 return *this;
377}
378
379CArchive& CArchive::operator>>(std::vector<int>& iArray)
380{
381 uint32_t size;
382 *this >> size;
383 iArray.clear();
384 for (uint32_t index = 0; index < size; index++)
385 {
386 int i;
387 *this >> i;
388 iArray.push_back(i);
389 }
390
391 return *this;
392}
393
394void CArchive::FlushBuffer()
395{
396 if (m_iMode == store && m_BufferPos != m_pBuffer.get())
397 {
398 if (m_pFile->Write(m_pBuffer.get(), m_BufferPos - m_pBuffer.get()) != m_BufferPos - m_pBuffer.get())
399 CLog::Log(LOGERROR, "%s: Error flushing buffer", __FUNCTION__);
400 else
401 {
402 m_BufferPos = m_pBuffer.get();
403 m_BufferRemain = CARCHIVE_BUFFER_MAX;
404 }
405 }
406}
407
408CArchive &CArchive::streamout_bufferwrap(const uint8_t *ptr, size_t size)
409{
410 do
411 {
412 auto chunkSize = std::min(size, m_BufferRemain);
413 m_BufferPos = std::copy(ptr, ptr + chunkSize, m_BufferPos);
414 ptr += chunkSize;
415 size -= chunkSize;
416 m_BufferRemain -= chunkSize;
417 if (m_BufferRemain == 0)
418 FlushBuffer();
419 } while (size > 0);
420 return *this;
421}
422
423void CArchive::FillBuffer()
424{
425 if (m_iMode == load && m_BufferRemain == 0)
426 {
427 auto read = m_pFile->Read(m_pBuffer.get(), CARCHIVE_BUFFER_MAX);
428 if (read > 0)
429 {
430 m_BufferRemain = read;
431 m_BufferPos = m_pBuffer.get();
432 }
433 }
434}
435
436CArchive &CArchive::streamin_bufferwrap(uint8_t *ptr, size_t size)
437{
438 auto orig_ptr = ptr;
439 auto orig_size = size;
440 do
441 {
442 if (m_BufferRemain == 0)
443 {
444 FillBuffer();
445 if (m_BufferRemain < CARCHIVE_BUFFER_MAX && m_BufferRemain < size)
446 {
447 CLog::Log(LOGERROR, "%s: can't stream in: requested %lu bytes, was read %lu bytes", __FUNCTION__,
448 static_cast<unsigned long>(orig_size), static_cast<unsigned long>(ptr - orig_ptr + m_BufferRemain));
449
450 memset(orig_ptr, 0, orig_size);
451 return *this;
452 }
453 }
454 auto chunkSize = std::min(size, m_BufferRemain);
455 ptr = std::copy(m_BufferPos, m_BufferPos + chunkSize, ptr);
456 m_BufferPos += chunkSize;
457 m_BufferRemain -= chunkSize;
458 size -= chunkSize;
459 } while (size > 0);
460 return *this;
461}