summaryrefslogtreecommitdiffstats
path: root/src/cppc4group.hpp
blob: 03cb8682707d5e5dbb49457aa2e3fbe635911a7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#pragma once

// this is the main and only include file for cppc4group, the C++-wrapper for cc4group
// because cc4group is already object-oriented, this is just a simple wrapper and almost all methods work exactly the same, just with C++-types
// although, when dealing with raw memory (because cc4group can't know the type of the stored data) also users of this wrapper have to deal with some void*
// because most methods behave exactly the same, please look at cc4group.h for their description (they are named exactly the same with a few exceptions)
// in case their are real differences, they will be noted in this header also
// until now, all except one example only use cc4group's C-API, but as a C++-programmer you should have no problems reading them anyway
// one general difference to the C-API that is not mentioned at the individual methods is that functions actually returning data return an std::optional instead of a bool...
// ...the optional will be populated normally and empty in error cases

#include <memory>
#include <vector>
#include <optional>
#include <cstdio>
#include <functional>

class CppC4Group {
	// all C-related stuff is hidden from this header so it doesn't land in the precious C++-only code this might be used in...
	// ...and pollute the root-namespace with various types that are better contained in this class instead
	struct Private;

	std::unique_ptr<Private> p;

	// this is only needed for internal purposes
	CppC4Group(std::unique_ptr<Private>&& p);

public:
	// this struct is used for the getEntryData-method to return them in a uniform way (instead of using reference- or pointer-arguments)
	struct Data {
		// this will contain the information cc4group.getEntryData stores in its data argument
		const void* data;
		// and the same for size
		size_t size;

		// there should be no reason to construct one of these as API user, but it is needed internally
		Data();
		Data(const void* const data, const size_t size);
	};

	// this struct contains the same things as the CC4Group_EntryInfo struct of the C-version
	// member descriptions also apply equally here
	struct EntryInfo {
		std::string fileName;
		int32_t modified;
		std::string author;
		size_t size;
		size_t totalSize;
		bool executable;
		bool directory;
		bool official;
	};

	// this struct is used in custom tmp memory strategies
	// instead of using additional pointer arguments to return the cleanup stuff everything is returned in a single one of this by the tmp memory strategy function
	struct TmpMemory {
		using TmpMemoryCleanupCallback = std::function<bool(void* memory, void* arg)>;

		// memory needs to hold the readily allocated memory
		// it corresponds to the pointer that needs to be returned by C tmp memory strategies
		void* memory;

		// cleanup is a fancy std::function that will be called when the memory is not needed anymore
		// it receives the memory pointer stored above and the custom argument stored right below as arguments
		TmpMemoryCleanupCallback cleanup;

		// this can be set to arbitrary data needed by the cleanup callback to properly cleanup all used resources
		void* arg;

		// this is just a plain constructor setting each member accordingly
		TmpMemory(void* const memory, const TmpMemoryCleanupCallback& cleanup, void* const arg);
	};

public:
	// the C++ custom tmp memory strategy only receives the needed size as argument and must return an optional containing the information described above (TmpMemory)
	// or an empty optional on failure
	using TmpMemoryCallback = std::optional<TmpMemory>(*)(size_t size);

	// these are equivalent to their C counterparts
	using ReadCallback = bool(*)(const void** const data, size_t* const size, void* const arg);
	using SetupCallback = bool(*)(void* const arg);
	using WriteCallback = bool(*)(const void* const data, size_t const size, void* const arg);

	// these enums are just mapped to their C-counterparts internally
	enum TmpMemoryStrategy {
		Memory,
		File,
		Auto
	};

	enum MemoryManagement {
		Take,
		Copy,
		Reference
	};

	// use this to set one of the predefined strategies
	static void setTmpMemoryStrategy(const TmpMemoryStrategy strategy);

	// and this for your own custom strategy
	static void setTmpMemoryStrategy(const TmpMemoryCallback callback);

public:
	// the constructor will automatically construct an internal CC4Group, so no new-equivalent method is needed
	// may throw std::bad_alloc if the allocation and construction of the internal CC4Group object fails
	CppC4Group();

	// the move constructor is needed to move the returned group out of the optional from openAsChild
	CppC4Group(CppC4Group&& other);

	// the destructor will automatically delete the internal CC4Group, so also no extra method needed
	~CppC4Group();

	void create();
	bool openExisting(const std::string& path);
	bool openFd(const int fd);
	bool openFilePointer(FILE* file);
	bool openMemory(const void* const data, const size_t size, const MemoryManagement management = Reference);
	bool openWithReadCallback(const ReadCallback callback, void* const callbackArg, const MemoryManagement management = Take, SetupCallback initCallback = nullptr, SetupCallback deinitCallback = nullptr);

	// save actually maps to both cc4group.save and cc4group.saveOverwrite, thanks to default arguments (yes, thats the reason why they are separate in the C-API)
	bool save(const std::string& path, const bool overwrite = false);
	bool saveToFd(const int fd);
	bool saveToFilePointer(FILE* file);
	bool saveWithWriteCallback(const WriteCallback callback, void* const arg = nullptr, size_t bufferSize = 0);

	bool extractAll(const std::string& path);
	bool extractSingle(const std::string& entryPath, const std::string& targetPath);

	std::optional<Data> getEntryData(const std::string& path);
	std::string getErrorMessage();
	int32_t getErrorCode();
	std::string getErrorMethod();
	std::string getErrorCauser();

	bool setMaker(const std::string& maker, const std::string& path = "", const bool recursive = false);
	bool setCreation(const int32_t creation, const std::string& path = "", const bool recursive = false);
	bool setOfficial(const bool official, const std::string& path = "", const bool recursive = false);
	bool setExecutable(const bool executable, const std::string& path);

	std::optional<EntryInfo> getEntryInfo(const std::string& path = "");
	std::optional<std::vector<EntryInfo>> getEntryInfos(const std::string& path = "");

	bool deleteEntry(const std::string& path, const bool recursive = false);
	bool renameEntry(const std::string& oldPath, const std::string& newPath);

	bool createDirectory(const std::string& path);

	bool createFile(const std::string& path);

	bool setEntryData(const std::string& path, const void* const data = nullptr, const size_t size = 0, const MemoryManagement management = Copy);

	// to get the child group out of the optional in case of success, construct a new CppC4Group with the move constructor: CppC4Group child{std::move(*optionalChild)};
	std::optional<CppC4Group> openAsChild(const std::string& path);
};