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
156
157
|
#pragma once
#ifdef __cplusplus
extern "C" {
#define this this_
#define new new_
#define delete delete_
#endif
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
typedef struct {
const char* fileName;
int32_t modified;
const char* author;
size_t size;
size_t totalSize;
bool executable;
bool directory;
bool official;
} CC4Group_EntryInfo;
typedef struct CC4Group_t CC4Group;
typedef void(*CC4Group_CleanupFunc)(void* data);
typedef struct {
CC4Group_CleanupFunc func;
void* data;
} CC4Group_CleanupJob;
typedef void* (*CC4Group_TmpMemoryStrategy)(CC4Group* const this, const size_t size, CC4Group_CleanupJob* cleanupJob);
// the callback has to store a pointer to the newly read data in data, as well as the amount of read data in size
// the callback must return true if the end of data is reached or any read error happens and false otherwise
// the pointer passed in will be handled as specified with the corresponding MemoryManagement
typedef bool (*CC4Group_ReadCallback)(const void** const data, size_t* const size, void* const arg);
// can be used as initialization before and deinitialization after all necessary calls to a read callback are made; for instance for buffer allocation and deletion
// the callback should return true on success and false on failure
typedef bool (*CC4Group_ReadSetupCallback)(void* const arg);
typedef struct {
struct {
int Take; // cc4group will free the data when its not needed anymore; e.g. in the destructor or when setting the file's data again
int Copy; // cc4group will copy the data to use it; the original data is untouched and needs to be freed by the caller whenever desired
int Reference; // cc4group will use the data as is (i.e. store the pointer and use it); the caller must guarantee it's validity throughout the groups lifetime (or until the file's data is set to a new pointer) and needs to take care of freeing it afterwards
} const MemoryManagement;
struct {
CC4Group_TmpMemoryStrategy Memory;
CC4Group_TmpMemoryStrategy File;
CC4Group_TmpMemoryStrategy Auto;
} const TmpMemoryStrategies;
void (*setTmpMemoryStrategy)(const CC4Group_TmpMemoryStrategy strategy);
// allocates and initializes a new group object, like the operator new
// NULL may be returned if the memory allocation (malloc) fails; in this case errno contains additional error information
CC4Group* (*new)(void);
// destructs the group object and frees all memory used by group, like the operator delete
void (*delete)(CC4Group* const this);
// after creating a group with new, exactly one of create, openExisting, openMemory, openFd, openFilePointer or openWithReadCallback must be called before any other action on the group object may be executed (except delete)
// initializes the group to be a fresh, empty group
bool (*create)(CC4Group* const this);
// opens a group on the filesystem; path may point to a directory inside a group; path "-" can be used to read the group from stdin
bool (*openExisting)(CC4Group* const this, const char* const path);
// opens a group that is stored entirely in memory
// see the description of MemoryManagement to know if and when data has to be freed by the caller
// if the lazy mode is not used, the data can be freed immediately after this function returns
bool (*openMemory)(CC4Group* const this, const void* const groupData, size_t const size, int const memoryManagement);
// opens a group through a file descriptor
// the file descriptor must have been opened with read access; also be aware that the file must be opened with binary mode on windows
bool (*openFd)(CC4Group* const this, int fd);
// opens a group through a FILE*
// the file must have been opened with read access; also be aware that the file must be opened with binary mode on windows
bool (*openFilePointer)(CC4Group* const this, FILE* fd);
// opens a group and calls the callback to get the group data; initCallback is called before readCallback is called and deinitCallback is called after all read operations are done; initCallback and deinitCallback may be NULL if they should not be used
bool (*openWithReadCallback)(CC4Group* const this, CC4Group_ReadCallback const readCallback, void* const callbackArg, int const memoryManagement, CC4Group_ReadSetupCallback const initCallback, CC4Group_ReadSetupCallback const deinitCallback);
// saves the current in-memory state of the group as a compressed c4group to disk
// fails if the given path already exists
bool (*save)(CC4Group* const this, const char* const path);
// same as save, except that an already existing group will be overwritten
// be careful, any existing file will be overwritten in-place. if any error occurs after opening the target file (e.g. out of memory, a program or system crash), the previous contents will be lost
bool (*saveOverwrite)(CC4Group* const this, const char* const path);
// extraction to disk
bool (*extractAll)(CC4Group* const this, const char* const targetPath);
bool (*extractSingle)(CC4Group* const this, const char* const entryPath, const char* const targetPath);
bool (*getEntryInfo)(CC4Group* const this, const char* const path, CC4Group_EntryInfo* const info);
bool (*getEntryInfos)(CC4Group* const this, const char* const path, CC4Group_EntryInfo** const infos, size_t* const size);
// the group owns the data pointed to. the pointer is valid until the group destructor is called
bool (*getEntryData)(CC4Group* const this, const char* const entryPath, const void** const data, size_t* const size);
// see the description of MemoryManagement to know if and when data has to be freed by the caller
bool (*setEntryData)(CC4Group* const this, const char* const entryPath, const void* const data, size_t const size, int const memoryManagementMode);
// group metadata handling
bool (*setMaker)(CC4Group* const this, const char* const maker, const char* const path, bool const recursive);
bool (*setCreation)(CC4Group* const this, int32_t const creation, const char* const path, bool const recursive);
bool (*setOfficial)(CC4Group* const this, bool const official, const char* const path, bool const recursive);
bool (*setExecutable)(CC4Group* const this, bool const executable, const char* const path);
// modifying the group
bool (*createDirectory)(CC4Group* const this, const char* const path);
bool (*createFile)(CC4Group* const this, const char* const path);
bool (*renameEntry)(CC4Group* const this, const char* const oldPath, const char* const newPath);
bool (*deleteEntry)(CC4Group* const this, const char* const path, bool const recursive);
// error information
// all error information is only meaningfully defined after any error ocurred (indicated by any method returning false) and always describes the last error that ocurred
// returns a human readable error message, including the "error causer", an interpretation of the error code, the internal method in which the error occured ("error method") and possibly also the error code
// the returned error message pointer is valid until the next call to getErrorMessage is issued or the group is destructed
// this method may return NULL if memory allocation for the formatted message fails; so NULL should be considered as out of memory
const char* (*getErrorMessage)(CC4Group* const this);
// returns the error code of the last error; interpretation of this code depends on the internally used function that caused the error
int32_t (*getErrorCode)(const CC4Group* const this);
// returns the internal method name in which the error ocurred
const char* (*getErrorMethod)(const CC4Group* const this);
// returns human readable information during which operation the error occured
const char* (*getErrorCauser)(const CC4Group* const this);
} const CC4Group_API;
#ifndef CC4GROUP_DYNAMIC_LOAD
extern CC4Group_API cc4group;
#endif
#ifdef __cplusplus
}
#undef this
#undef new
#undef delete
#endif
|