1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef ENGINE_SHARED_DATAFILE_H
4#define ENGINE_SHARED_DATAFILE_H
5
6#include "uuid_manager.h"
7
8#include <base/hash.h>
9#include <base/types.h>
10
11#include <engine/storage.h>
12
13#include <cstdint>
14#include <functional>
15#include <map>
16#include <vector>
17
18enum
19{
20 ITEMTYPE_EX = 0xFFFF,
21};
22
23/**
24 * The data processor function is called after a particular data item is first successfully uncompressed.
25 * The function can validate the data and return `std::make_pair(nullptr, 0)` on error or the original data
26 * on success. The function can also replace the data and return a new data pointer and size. The new data
27 * must be allocated with `malloc`. When returning different data or on errors, the original data must be
28 * freed by the function using `free`.
29 */
30typedef std::function<std::pair<void *, size_t>(void *pData, size_t Size)> FDataProcessor;
31
32// raw datafile access
33class CDataFileReader
34{
35 class CDatafile *m_pDataFile = nullptr;
36
37 int GetExternalItemType(int InternalType, CUuid *pUuid);
38 int GetInternalItemType(int ExternalType);
39
40public:
41 ~CDataFileReader();
42 CDataFileReader &operator=(CDataFileReader &&Other);
43
44 [[nodiscard]] bool Open(const char *pFullName, IStorage *pStorage, const char *pPath, int StorageType);
45 [[nodiscard]] bool Open(IStorage *pStorage, const char *pPath, int StorageType);
46 void Close();
47 bool IsOpen() const;
48 IOHANDLE File() const;
49
50 int GetDataSize(int Index) const;
51 void *GetData(int Index);
52 void *GetDataSwapped(int Index); // makes sure that the data is 32bit LE ints when saved
53 const char *GetDataString(int Index);
54 void AddDataProcessor(int Index, FDataProcessor DataProcessor);
55 void UnloadData(int Index);
56 int NumData() const;
57
58 int GetItemSize(int Index) const;
59 void *GetItem(int Index, int *pType = nullptr, int *pId = nullptr, CUuid *pUuid = nullptr);
60 void GetType(int Type, int *pStart, int *pNum);
61 int FindItemIndex(int Type, int Id);
62 void *FindItem(int Type, int Id);
63 bool OverrideItemData(int Index, const void *pData, size_t Size);
64 int NumItems() const;
65
66 const char *FullName() const;
67 const char *BaseName() const;
68 const char *Path() const;
69 SHA256_DIGEST Sha256() const;
70 unsigned Crc() const;
71 int Size() const;
72};
73
74// write access
75class CDataFileWriter
76{
77public:
78 enum ECompressionLevel
79 {
80 COMPRESSION_DEFAULT,
81 COMPRESSION_BEST,
82 };
83
84private:
85 class CDataInfo
86 {
87 public:
88 void *m_pUncompressedData;
89 int m_UncompressedSize;
90 void *m_pCompressedData;
91 int m_CompressedSize;
92 ECompressionLevel m_CompressionLevel;
93 };
94
95 class CItemInfo
96 {
97 public:
98 int m_Type;
99 int m_Id;
100 int m_Size;
101 int m_Next;
102 int m_Prev;
103 void *m_pData;
104 };
105
106 class CItemTypeInfo
107 {
108 public:
109 int m_Num = 0;
110 int m_First = -1;
111 int m_Last = -1;
112 };
113
114 class CExtendedItemType
115 {
116 public:
117 int m_Type;
118 CUuid m_Uuid;
119 };
120
121 IOHANDLE m_File;
122 std::map<uint16_t, CItemTypeInfo, std::less<>> m_ItemTypes; // item types must be sorted in ascending order
123 std::vector<CItemInfo> m_vItems;
124 std::vector<CDataInfo> m_vDatas;
125 std::vector<CExtendedItemType> m_vExtendedItemTypes;
126
127 int GetTypeFromIndex(int Index) const;
128 int GetExtendedItemTypeIndex(int Type, const CUuid *pUuid);
129
130public:
131 CDataFileWriter();
132 CDataFileWriter(CDataFileWriter &&Other)
133 {
134 m_File = Other.m_File;
135 Other.m_File = nullptr;
136 m_ItemTypes = std::move(Other.m_ItemTypes);
137 m_vItems = std::move(Other.m_vItems);
138 m_vDatas = std::move(Other.m_vDatas);
139 m_vExtendedItemTypes = std::move(Other.m_vExtendedItemTypes);
140 }
141 ~CDataFileWriter();
142
143 [[nodiscard]] bool Open(class IStorage *pStorage, const char *pFilename, int StorageType = IStorage::TYPE_SAVE);
144 int AddItem(int Type, int Id, size_t Size, const void *pData, const CUuid *pUuid = nullptr);
145 int AddData(size_t Size, const void *pData, ECompressionLevel CompressionLevel = COMPRESSION_DEFAULT);
146 int AddDataSwapped(size_t Size, const void *pData);
147 int AddDataString(const char *pStr);
148 void Finish();
149};
150
151#endif
152