~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Common/ChunkFile.h

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C) 2003 Dolphin Project.
 
2
 
 
3
// This program is free software: you can redistribute it and/or modify
 
4
// it under the terms of the GNU General Public License as published by
 
5
// the Free Software Foundation, version 2.0 or later versions.
 
6
 
 
7
// This program is distributed in the hope that it will be useful,
 
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
// GNU General Public License 2.0 for more details.
 
11
 
 
12
// A copy of the GPL 2.0 should have been included with the program.
 
13
// If not, see http://www.gnu.org/licenses/
 
14
 
 
15
// Official SVN repository and contact information can be found at
 
16
// http://code.google.com/p/dolphin-emu/
 
17
 
 
18
#pragma once
 
19
 
 
20
// Extremely simple serialization framework.
 
21
// Currently mis-named, a native ChunkFile is something different (a RIFF file)
 
22
 
 
23
// (mis)-features:
 
24
// + Super fast
 
25
// + Very simple
 
26
// + Same code is used for serialization and deserializaition (in most cases)
 
27
// + Sections can be versioned for backwards/forwards compatibility
 
28
// - Serialization code for anything complex has to be manually written.
 
29
 
 
30
#include <map>
 
31
#include <unordered_map>
 
32
#include <deque>
 
33
#include <list>
 
34
#include <set>
 
35
#if defined(MACGNUSTD)
 
36
#include <tr1/type_traits>
 
37
#else
 
38
#include <type_traits>
 
39
#endif
 
40
 
 
41
#include "Common.h"
 
42
#include "FileUtil.h"
 
43
#ifdef SHARED_SNAPPY
 
44
#include <snappy-c.h>
 
45
#else
 
46
#include "../ext/snappy/snappy-c.h"
 
47
#endif
 
48
 
 
49
#if defined(MACGNUSTD)
 
50
namespace std {
 
51
        using tr1::is_pointer;
 
52
}
 
53
#endif
 
54
 
 
55
template <class T>
 
56
struct LinkedListItem : public T
 
57
{
 
58
        LinkedListItem<T> *next;
 
59
};
 
60
 
 
61
class PointerWrap;
 
62
 
 
63
class PointerWrapSection
 
64
{
 
65
public:
 
66
        PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) {
 
67
        }
 
68
        ~PointerWrapSection();
 
69
        
 
70
        bool operator == (const int &v) const { return ver_ == v; }
 
71
        bool operator != (const int &v) const { return ver_ != v; }
 
72
        bool operator <= (const int &v) const { return ver_ <= v; }
 
73
        bool operator >= (const int &v) const { return ver_ >= v; }
 
74
        bool operator <  (const int &v) const { return ver_ < v; }
 
75
        bool operator >  (const int &v) const { return ver_ > v; }
 
76
 
 
77
        operator bool() const  {
 
78
                return ver_ > 0;
 
79
        }
 
80
 
 
81
private:
 
82
        PointerWrap &p_;
 
83
        int ver_;
 
84
        const char *title_;
 
85
};
 
86
 
 
87
// Wrapper class
 
88
class PointerWrap
 
89
{
 
90
        // This makes it a compile error if you forget to define DoState() on non-POD.
 
91
        // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
 
92
#ifdef _MSC_VER
 
93
        template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value>
 
94
#else
 
95
        template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
 
96
#endif
 
97
        struct DoHelper
 
98
        {
 
99
                static void DoArray(PointerWrap *p, T *x, int count)
 
100
                {
 
101
                        for (int i = 0; i < count; ++i)
 
102
                                p->Do(x[i]);
 
103
                }
 
104
 
 
105
                static void Do(PointerWrap *p, T &x)
 
106
                {
 
107
                        p->DoClass(x);
 
108
                }
 
109
        };
 
110
 
 
111
        template<typename T>
 
112
        struct DoHelper<T, true, false>
 
113
        {
 
114
                static void DoArray(PointerWrap *p, T *x, int count)
 
115
                {
 
116
                        p->DoVoid((void *)x, sizeof(T) * count);
 
117
                }
 
118
 
 
119
                static void Do(PointerWrap *p, T &x)
 
120
                {
 
121
                        p->DoVoid((void *)&x, sizeof(x));
 
122
                }
 
123
        };
 
124
 
 
125
public:
 
126
        enum Mode {
 
127
                MODE_READ = 1, // load
 
128
                MODE_WRITE, // save
 
129
                MODE_MEASURE, // calculate size
 
130
                MODE_VERIFY, // compare
 
131
        };
 
132
 
 
133
        enum Error {
 
134
                ERROR_NONE = 0,
 
135
                ERROR_WARNING = 1,
 
136
                ERROR_FAILURE = 2,
 
137
        };
 
138
 
 
139
        u8 **ptr;
 
140
        Mode mode;
 
141
        Error error;
 
142
 
 
143
public:
 
144
        PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
 
145
        PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
 
146
 
 
147
        PointerWrapSection Section(const char *title, int ver);
 
148
 
 
149
        // The returned object can be compared against the version that was loaded.
 
150
        // This can be used to support versions as old as minVer.
 
151
        // Version = 0 means the section was not found.
 
152
        PointerWrapSection Section(const char *title, int minVer, int ver);
 
153
 
 
154
        void SetMode(Mode mode_) {mode = mode_;}
 
155
        Mode GetMode() const {return mode;}
 
156
        u8 **GetPPtr() {return ptr;}
 
157
        void SetError(Error error_);
 
158
 
 
159
        // Same as DoVoid, except doesn't advance pointer if it doesn't match on read.
 
160
        bool ExpectVoid(void *data, int size);
 
161
        void DoVoid(void *data, int size);
 
162
        
 
163
        template<class K, class T>
 
164
        void Do(std::map<K, T *> &x)
 
165
        {
 
166
                if (mode == MODE_READ)
 
167
                {
 
168
                        for (auto it = x.begin(), end = x.end(); it != end; ++it)
 
169
                        {
 
170
                                if (it->second != NULL)
 
171
                                        delete it->second;
 
172
                        }
 
173
                }
 
174
                T *dv = NULL;
 
175
                DoMap(x, dv);
 
176
        }
 
177
 
 
178
        template<class K, class T>
 
179
        void Do(std::map<K, T> &x)
 
180
        {
 
181
                T dv = T();
 
182
                DoMap(x, dv);
 
183
        }
 
184
 
 
185
        template<class K, class T>
 
186
        void Do(std::unordered_map<K, T *> &x)
 
187
        {
 
188
                if (mode == MODE_READ)
 
189
                {
 
190
                        for (auto it = x.begin(), end = x.end(); it != end; ++it)
 
191
                        {
 
192
                                if (it->second != NULL)
 
193
                                        delete it->second;
 
194
                        }
 
195
                }
 
196
                T *dv = NULL;
 
197
                DoMap(x, dv);
 
198
        }
 
199
 
 
200
        template<class K, class T>
 
201
        void Do(std::unordered_map<K, T> &x)
 
202
        {
 
203
                T dv = T();
 
204
                DoMap(x, dv);
 
205
        }
 
206
 
 
207
        template<class M>
 
208
        void DoMap(M &x, typename M::mapped_type &default_val)
 
209
        {
 
210
                unsigned int number = (unsigned int)x.size();
 
211
                Do(number);
 
212
                switch (mode) {
 
213
                case MODE_READ:
 
214
                        {
 
215
                                x.clear();
 
216
                                while (number > 0)
 
217
                                {
 
218
                                        typename M::key_type first = typename M::key_type();
 
219
                                        Do(first);
 
220
                                        typename M::mapped_type second = default_val;
 
221
                                        Do(second);
 
222
                                        x[first] = second;
 
223
                                        --number;
 
224
                                }
 
225
                        }
 
226
                        break;
 
227
                case MODE_WRITE:
 
228
                case MODE_MEASURE:
 
229
                case MODE_VERIFY:
 
230
                        {
 
231
                                typename M::iterator itr = x.begin();
 
232
                                while (number > 0)
 
233
                                {
 
234
                                        typename M::key_type first = itr->first;
 
235
                                        Do(first);
 
236
                                        Do(itr->second);
 
237
                                        --number;
 
238
                                        ++itr;
 
239
                                }
 
240
                        }
 
241
                        break;
 
242
                }
 
243
        }
 
244
 
 
245
        template<class K, class T>
 
246
        void Do(std::multimap<K, T *> &x)
 
247
        {
 
248
                if (mode == MODE_READ)
 
249
                {
 
250
                        for (auto it = x.begin(), end = x.end(); it != end; ++it)
 
251
                        {
 
252
                                if (it->second != NULL)
 
253
                                        delete it->second;
 
254
                        }
 
255
                }
 
256
                T *dv = NULL;
 
257
                DoMultimap(x, dv);
 
258
        }
 
259
 
 
260
        template<class K, class T>
 
261
        void Do(std::multimap<K, T> &x)
 
262
        {
 
263
                T dv = T();
 
264
                DoMultimap(x, dv);
 
265
        }
 
266
 
 
267
        template<class K, class T>
 
268
        void Do(std::unordered_multimap<K, T *> &x)
 
269
        {
 
270
                if (mode == MODE_READ)
 
271
                {
 
272
                        for (auto it = x.begin(), end = x.end(); it != end; ++it)
 
273
                        {
 
274
                                if (it->second != NULL)
 
275
                                        delete it->second;
 
276
                        }
 
277
                }
 
278
                T *dv = NULL;
 
279
                DoMultimap(x, dv);
 
280
        }
 
281
 
 
282
        template<class K, class T>
 
283
        void Do(std::unordered_multimap<K, T> &x)
 
284
        {
 
285
                T dv = T();
 
286
                DoMultimap(x, dv);
 
287
        }
 
288
 
 
289
        template<class M>
 
290
        void DoMultimap(M &x, typename M::mapped_type &default_val)
 
291
        {
 
292
                unsigned int number = (unsigned int)x.size();
 
293
                Do(number);
 
294
                switch (mode) {
 
295
                case MODE_READ:
 
296
                        {
 
297
                                x.clear();
 
298
                                while (number > 0)
 
299
                                {
 
300
                                        typename M::key_type first = typename M::key_type();
 
301
                                        Do(first);
 
302
                                        typename M::mapped_type second = default_val;
 
303
                                        Do(second);
 
304
                                        x.insert(std::make_pair(first, second));
 
305
                                        --number;
 
306
                                }
 
307
                        }
 
308
                        break;
 
309
                case MODE_WRITE:
 
310
                case MODE_MEASURE:
 
311
                case MODE_VERIFY:
 
312
                        {
 
313
                                typename M::iterator itr = x.begin();
 
314
                                while (number > 0)
 
315
                                {
 
316
                                        Do(itr->first);
 
317
                                        Do(itr->second);
 
318
                                        --number;
 
319
                                        ++itr;
 
320
                                }
 
321
                        }
 
322
                        break;
 
323
                }
 
324
        }
 
325
 
 
326
        // Store vectors.
 
327
        template<class T>
 
328
        void Do(std::vector<T *> &x)
 
329
        {
 
330
                T *dv = NULL;
 
331
                DoVector(x, dv);
 
332
        }
 
333
 
 
334
        template<class T>
 
335
        void Do(std::vector<T> &x)
 
336
        {
 
337
                T dv = T();
 
338
                DoVector(x, dv);
 
339
        }
 
340
 
 
341
        template<class T>
 
342
        void Do(std::vector<T> &x, T &default_val)
 
343
        {
 
344
                DoVector(x, default_val);
 
345
        }
 
346
 
 
347
        template<class T>
 
348
        void DoVector(std::vector<T> &x, T &default_val)
 
349
        {
 
350
                u32 vec_size = (u32)x.size();
 
351
                Do(vec_size);
 
352
                x.resize(vec_size, default_val);
 
353
                if (vec_size > 0)
 
354
                        DoArray(&x[0], vec_size);
 
355
        }
 
356
 
 
357
        // Store deques.
 
358
        template<class T>
 
359
        void Do(std::deque<T *> &x)
 
360
        {
 
361
                T *dv = NULL;
 
362
                DoDeque(x, dv);
 
363
        }
 
364
 
 
365
        template<class T>
 
366
        void Do(std::deque<T> &x)
 
367
        {
 
368
                T dv = T();
 
369
                DoDeque(x, dv);
 
370
        }
 
371
 
 
372
        template<class T>
 
373
        void DoDeque(std::deque<T> &x, T &default_val)
 
374
        {
 
375
                u32 deq_size = (u32)x.size();
 
376
                Do(deq_size);
 
377
                x.resize(deq_size, default_val);
 
378
                u32 i;
 
379
                for(i = 0; i < deq_size; i++)
 
380
                        Do(x[i]);
 
381
        }
 
382
 
 
383
        // Store STL lists.
 
384
        template<class T>
 
385
        void Do(std::list<T *> &x)
 
386
        {
 
387
                T *dv = NULL;
 
388
                Do(x, dv);
 
389
        }
 
390
 
 
391
        template<class T>
 
392
        void Do(std::list<T> &x)
 
393
        {
 
394
                T dv = T();
 
395
                DoList(x, dv);
 
396
        }
 
397
 
 
398
        template<class T>
 
399
        void Do(std::list<T> &x, T &default_val)
 
400
        {
 
401
                DoList(x, default_val);
 
402
        }
 
403
 
 
404
        template<class T>
 
405
        void DoList(std::list<T> &x, T &default_val)
 
406
        {
 
407
                u32 list_size = (u32)x.size();
 
408
                Do(list_size);
 
409
                x.resize(list_size, default_val);
 
410
 
 
411
                typename std::list<T>::iterator itr, end;
 
412
                for (itr = x.begin(), end = x.end(); itr != end; ++itr)
 
413
                        Do(*itr);
 
414
        }
 
415
 
 
416
        // Store STL sets.
 
417
        template <class T>
 
418
        void Do(std::set<T *> &x)
 
419
        {
 
420
                if (mode == MODE_READ)
 
421
                {
 
422
                        for (auto it = x.begin(), end = x.end(); it != end; ++it)
 
423
                        {
 
424
                                if (*it != NULL)
 
425
                                        delete *it;
 
426
                        }
 
427
                }
 
428
                DoSet(x);
 
429
        }
 
430
 
 
431
        template <class T>
 
432
        void Do(std::set<T> &x)
 
433
        {
 
434
                DoSet(x);
 
435
        }
 
436
 
 
437
        template <class T>
 
438
        void DoSet(std::set<T> &x)
 
439
        {
 
440
                unsigned int number = (unsigned int)x.size();
 
441
                Do(number);
 
442
 
 
443
                switch (mode)
 
444
                {
 
445
                case MODE_READ:
 
446
                        {
 
447
                                x.clear();
 
448
                                while (number-- > 0)
 
449
                                {
 
450
                                        T it = T();
 
451
                                        Do(it);
 
452
                                        x.insert(it);
 
453
                                }
 
454
                        }
 
455
                        break;
 
456
                case MODE_WRITE:
 
457
                case MODE_MEASURE:
 
458
                case MODE_VERIFY:
 
459
                        {
 
460
                                typename std::set<T>::iterator itr = x.begin();
 
461
                                while (number-- > 0)
 
462
                                        Do(*itr++);
 
463
                        }
 
464
                        break;
 
465
 
 
466
                default:
 
467
                        ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode);
 
468
                }
 
469
        }
 
470
 
 
471
        // Store strings.
 
472
        void Do(std::string &x);
 
473
        void Do(std::wstring &x);
 
474
 
 
475
        void Do(tm &t);
 
476
 
 
477
        template<typename T, typename F>
 
478
        void Do(swap_struct_t<T, F> &x) {
 
479
                T v = x.swap();
 
480
                Do(v);
 
481
                x = v;
 
482
        }
 
483
 
 
484
        template<class T>
 
485
        void DoClass(T &x) {
 
486
                x.DoState(*this);
 
487
        }
 
488
 
 
489
        template<class T>
 
490
        void DoClass(T *&x) {
 
491
                if (mode == MODE_READ)
 
492
                {
 
493
                        if (x != NULL)
 
494
                                delete x;
 
495
                        x = new T();
 
496
                }
 
497
                x->DoState(*this);
 
498
        }
 
499
 
 
500
        template<class T>
 
501
        void DoArray(T *x, int count) {
 
502
                DoHelper<T>::DoArray(this, x, count);
 
503
        }
 
504
 
 
505
        template<class T>
 
506
        void Do(T &x) {
 
507
                DoHelper<T>::Do(this, x);
 
508
        }
 
509
 
 
510
        template<class T>
 
511
        void DoPointer(T* &x, T*const base) {
 
512
                // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range
 
513
                s32 offset = x - base;
 
514
                Do(offset);
 
515
                if (mode == MODE_READ)
 
516
                        x = base + offset;
 
517
        }
 
518
 
 
519
        template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)>
 
520
        void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0)
 
521
        {
 
522
                LinkedListItem<T>* list_cur = list_start;
 
523
                LinkedListItem<T>* prev = 0;
 
524
 
 
525
                while (true)
 
526
                {
 
527
                        u8 shouldExist = (list_cur ? 1 : 0);
 
528
                        Do(shouldExist);
 
529
                        if (shouldExist == 1)
 
530
                        {
 
531
                                LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
 
532
                                TDo(*this, (T*)cur);
 
533
                                if (!list_cur)
 
534
                                {
 
535
                                        if (mode == MODE_READ)
 
536
                                        {
 
537
                                                cur->next = 0;
 
538
                                                list_cur = cur;
 
539
                                                if (prev)
 
540
                                                        prev->next = cur;
 
541
                                                else
 
542
                                                        list_start = cur;
 
543
                                        }
 
544
                                        else
 
545
                                        {
 
546
                                                TFree(cur);
 
547
                                                continue;
 
548
                                        }
 
549
                                }
 
550
                        }
 
551
                        else
 
552
                        {
 
553
                                if (shouldExist != 0)
 
554
                                {
 
555
                                        WARN_LOG(COMMON, "Savestate failure: incorrect item marker %d", shouldExist);
 
556
                                        SetError(ERROR_FAILURE);
 
557
                                }
 
558
                                if (mode == MODE_READ)
 
559
                                {
 
560
                                        if (prev)
 
561
                                                prev->next = 0;
 
562
                                        if (list_end)
 
563
                                                *list_end = prev;
 
564
                                        if (list_cur)
 
565
                                        {
 
566
                                                if (list_start == list_cur)
 
567
                                                        list_start = 0;
 
568
                                                do
 
569
                                                {
 
570
                                                        LinkedListItem<T>* next = list_cur->next;
 
571
                                                        TFree(list_cur);
 
572
                                                        list_cur = next;
 
573
                                                }
 
574
                                                while (list_cur);
 
575
                                        }
 
576
                                }
 
577
                                break;
 
578
                        }
 
579
                        prev = list_cur;
 
580
                        list_cur = list_cur->next;
 
581
                }
 
582
        }
 
583
 
 
584
        void DoMarker(const char *prevName, u32 arbitraryNumber = 0x42);
 
585
};
 
586
 
 
587
class CChunkFileReader
 
588
{
 
589
public:
 
590
        enum Error {
 
591
                ERROR_NONE,
 
592
                ERROR_BAD_FILE,
 
593
                ERROR_BROKEN_STATE,
 
594
        };
 
595
 
 
596
        // May fail badly if ptr doesn't point to valid data.
 
597
        template<class T>
 
598
        static Error LoadPtr(u8 *ptr, T &_class)
 
599
        {
 
600
                PointerWrap p(&ptr, PointerWrap::MODE_READ);
 
601
                _class.DoState(p);
 
602
 
 
603
                if (p.error != p.ERROR_FAILURE) {
 
604
                        return ERROR_NONE;
 
605
                } else {
 
606
                        return ERROR_BROKEN_STATE;
 
607
                }
 
608
        }
 
609
 
 
610
        template<class T>
 
611
        static size_t MeasurePtr(T &_class)
 
612
        {
 
613
                u8 *ptr = 0;
 
614
                PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
 
615
                _class.DoState(p);
 
616
                return (size_t)ptr;
 
617
        }
 
618
 
 
619
        // Expects ptr to have at least MeasurePtr bytes at ptr.
 
620
        template<class T>
 
621
        static Error SavePtr(u8 *ptr, T &_class)
 
622
        {
 
623
                PointerWrap p(&ptr, PointerWrap::MODE_WRITE);
 
624
                _class.DoState(p);
 
625
 
 
626
                if (p.error != p.ERROR_FAILURE) {
 
627
                        return ERROR_NONE;
 
628
                } else {
 
629
                        return ERROR_BROKEN_STATE;
 
630
                }
 
631
        }
 
632
 
 
633
        // Load file template
 
634
        template<class T>
 
635
        static Error Load(const std::string &filename, const char *gitVersion, T& _class, std::string *failureReason)
 
636
        {
 
637
                *failureReason = "LoadStateWrongVersion";
 
638
 
 
639
                u8 *ptr = nullptr;
 
640
                size_t sz;
 
641
                Error error = LoadFile(filename, gitVersion, ptr, sz, failureReason);
 
642
                if (error == ERROR_NONE) {
 
643
                        error = LoadPtr(ptr, _class);
 
644
                        delete [] ptr;
 
645
                }
 
646
                
 
647
                INFO_LOG(COMMON, "ChunkReader: Done loading %s", filename.c_str());
 
648
                if (error == ERROR_NONE) {
 
649
                        failureReason->clear();
 
650
                }
 
651
                return error;
 
652
        }
 
653
 
 
654
        // Save file template
 
655
        template<class T>
 
656
        static Error Save(const std::string &filename, const std::string &title, const char *gitVersion, T& _class)
 
657
        {
 
658
                // Get data
 
659
                size_t const sz = MeasurePtr(_class);
 
660
                u8 *buffer = new u8[sz];
 
661
                Error error = SavePtr(buffer, _class);
 
662
 
 
663
                // SaveFile takes ownership of buffer
 
664
                if (error == ERROR_NONE)
 
665
                        error = SaveFile(filename, title, gitVersion, buffer, sz);
 
666
                return error;
 
667
        }
 
668
        
 
669
        template <class T>
 
670
        static Error Verify(T& _class)
 
671
        {
 
672
                u8 *ptr = 0;
 
673
 
 
674
                // Step 1: Measure the space required.
 
675
                PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
 
676
                _class.DoState(p);
 
677
                size_t const sz = (size_t)ptr;
 
678
                std::vector<u8> buffer(sz);
 
679
 
 
680
                // Step 2: Dump the state.
 
681
                ptr = &buffer[0];
 
682
                p.SetMode(PointerWrap::MODE_WRITE);
 
683
                _class.DoState(p);
 
684
 
 
685
                // Step 3: Verify the state.
 
686
                ptr = &buffer[0];
 
687
                p.SetMode(PointerWrap::MODE_VERIFY);
 
688
                _class.DoState(p);
 
689
 
 
690
                return ERROR_NONE;
 
691
        }
 
692
 
 
693
        static Error GetFileTitle(const std::string &filename, std::string *title);
 
694
 
 
695
private:
 
696
        struct SChunkHeader
 
697
        {
 
698
                int Revision;
 
699
                int Compress;
 
700
                u32 ExpectedSize;
 
701
                u32 UncompressedSize;
 
702
                char GitVersion[32];
 
703
        };
 
704
 
 
705
        enum {
 
706
                REVISION_MIN = 4,
 
707
                REVISION_TITLE = 5,
 
708
                REVISION_CURRENT = REVISION_TITLE,
 
709
        };
 
710
 
 
711
        static Error LoadFile(const std::string &filename, const char *gitVersion, u8 *&buffer, size_t &sz, std::string *failureReason);
 
712
        static Error SaveFile(const std::string &filename, const std::string &title, const char *gitVersion, u8 *buffer, size_t sz);
 
713
        static Error LoadFileHeader(File::IOFile &pFile, SChunkHeader &header, std::string *title);
 
714
};