Skip to content

Latest commit

 

History

History
166 lines (130 loc) · 5.09 KB

physfs_archiver_vdf.c

File metadata and controls

166 lines (130 loc) · 5.09 KB
 
Jun 20, 2017
Jun 20, 2017
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* VDF support routines for PhysicsFS.
*
* This driver handles Gothic I/II VDF archives.
* This format (but not this driver) was designed by Piranha Bytes for
* use wih the ZenGin engine.
*
* This file was written by Francesco Bertolaccini, based on the UNPK archiver
* by Ryan C. Gordon and the works of degenerated1123 and Nico Bendlin.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
#if PHYSFS_SUPPORTS_VDF
Jul 22, 2017
Jul 22, 2017
17
#include <time.h>
Jun 20, 2017
Jun 20, 2017
18
Jul 22, 2017
Jul 22, 2017
19
20
21
#define VDF_COMMENT_LENGTH 256
#define VDF_SIGNATURE_LENGTH 16
#define VDF_ENTRY_NAME_LENGTH 64
Jun 20, 2017
Jun 20, 2017
22
Jul 12, 2017
Jul 12, 2017
23
24
static const char* VDF_SIGNATURE_G1 = "PSVDSC_V2.00\r\n\r\n";
static const char* VDF_SIGNATURE_G2 = "PSVDSC_V2.00\n\r\n\r";
Jun 20, 2017
Jun 20, 2017
25
26
Jul 22, 2017
Jul 22, 2017
27
static inline int readui32(PHYSFS_Io *io, PHYSFS_uint32 *val)
Jun 20, 2017
Jun 20, 2017
28
{
Jul 22, 2017
Jul 22, 2017
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
PHYSFS_uint32 v;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &v, sizeof (v)), 0);
*val = PHYSFS_swapULE32(v);
return 1;
} /* readui32 */
static PHYSFS_sint64 vdfDosTimeToEpoch(const PHYSFS_uint32 dostime)
{
/* VDF stores timestamps as 32bit DOS dates: the seconds are counted in
2-seconds intervals and the years are counted since 1 Jan. 1980 */
struct tm t;
memset(&t, '\0', sizeof (t));
t.tm_year = ((int) ((dostime >> 25) & 0x7F)) + 80; /* 1980 to 1900 */
t.tm_mon = ((int) ((dostime >> 21) & 0xF)) - 1; /* 1-12 to 0-11 */
t.tm_mday = (int) ((dostime >> 16) & 0x1F);
t.tm_hour = (int) ((dostime >> 11) & 0x1F);
t.tm_min = (int) ((dostime >> 5) & 0x3F);
t.tm_sec = ((int) ((dostime >> 0) & 0x1F)) * 2; /* 2 seconds to 1. */
return (PHYSFS_sint64) mktime(&t);
Jun 20, 2017
Jun 20, 2017
49
50
51
} /* vdfDosTimeToEpoch */
Jul 22, 2017
Jul 22, 2017
52
static int vdfLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count,
Jul 22, 2017
Jul 22, 2017
53
const PHYSFS_sint64 ts, void *arc)
Jun 20, 2017
Jun 20, 2017
54
{
Jul 22, 2017
Jul 22, 2017
55
PHYSFS_uint32 i;
Jun 20, 2017
Jun 20, 2017
56
Jul 22, 2017
Jul 22, 2017
57
for (i = 0; i < count; i++)
Jun 20, 2017
Jun 20, 2017
58
{
Jul 22, 2017
Jul 22, 2017
59
60
61
62
63
64
65
66
67
68
69
70
71
72
char name[VDF_ENTRY_NAME_LENGTH + 1];
int namei;
PHYSFS_uint32 jump, size, type, attr;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, name, sizeof (name) - 1), 0);
BAIL_IF_ERRPASS(!readui32(io, &jump), 0);
BAIL_IF_ERRPASS(!readui32(io, &size), 0);
BAIL_IF_ERRPASS(!readui32(io, &type), 0);
BAIL_IF_ERRPASS(!readui32(io, &attr), 0);
/* Trim whitespace off the end of the filename */
name[VDF_ENTRY_NAME_LENGTH] = '\0'; /* always null-terminated. */
for (namei = VDF_ENTRY_NAME_LENGTH - 1; namei >= 0; namei--)
{
Aug 14, 2017
Aug 14, 2017
73
74
75
76
77
78
/* We assume the filenames are low-ASCII; consider the archive
corrupt if we see something above 127, since we don't know the
encoding. (We can change this later if we find out these exist
and are intended to be, say, latin-1 or UTF-8 encoding). */
BAIL_IF(((PHYSFS_uint8) name[namei]) > 127, PHYSFS_ERR_CORRUPT, 0);
Jul 22, 2017
Jul 22, 2017
79
80
81
82
83
if (name[namei] == ' ')
name[namei] = '\0';
else
break;
} /* for */
Jun 20, 2017
Jun 20, 2017
84
Jul 22, 2017
Jul 22, 2017
85
BAIL_IF(!name[0], PHYSFS_ERR_CORRUPT, 0);
Jun 20, 2017
Jun 20, 2017
86
Jul 22, 2017
Jul 22, 2017
87
BAIL_IF_ERRPASS(!UNPK_addEntry(arc, name, 0, ts, ts, jump, size), 0);
Jun 20, 2017
Jun 20, 2017
88
89
} /* for */
Jul 22, 2017
Jul 22, 2017
90
91
return 1;
} /* vdfLoadEntries */
Jun 20, 2017
Jun 20, 2017
92
93
Aug 14, 2017
Aug 14, 2017
94
95
static void *VDF_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
Jun 20, 2017
Jun 20, 2017
96
{
Jul 22, 2017
Jul 22, 2017
97
98
99
100
PHYSFS_uint8 ignore[16];
PHYSFS_uint8 sig[VDF_SIGNATURE_LENGTH];
PHYSFS_uint32 count, timestamp, version, dataSize, rootCatOffset;
void *unpkarc;
Jun 20, 2017
Jun 20, 2017
101
Jul 22, 2017
Jul 22, 2017
102
103
assert(io != NULL); /* shouldn't ever happen. */
Jul 6, 2017
Jul 6, 2017
104
BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
Jul 3, 2017
Jul 3, 2017
105
Jul 22, 2017
Jul 22, 2017
106
107
108
109
/* skip the 256-byte comment field. */
BAIL_IF_ERRPASS(!io->seek(io, VDF_COMMENT_LENGTH), NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, sig, sizeof (sig)), NULL);
Aug 14, 2017
Aug 14, 2017
110
111
112
113
114
115
116
117
118
if ((memcmp(sig, VDF_SIGNATURE_G1, VDF_SIGNATURE_LENGTH) != 0) &&
(memcmp(sig, VDF_SIGNATURE_G2, VDF_SIGNATURE_LENGTH) != 0))
{
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
} /* if */
*claimed = 1;
Jul 22, 2017
Jul 22, 2017
119
120
121
122
123
124
BAIL_IF_ERRPASS(!readui32(io, &count), NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, ignore, 4), NULL); /* numFiles */
BAIL_IF_ERRPASS(!readui32(io, &timestamp), NULL);
BAIL_IF_ERRPASS(!readui32(io, &dataSize), NULL); /* dataSize */
BAIL_IF_ERRPASS(!readui32(io, &rootCatOffset), NULL); /* rootCatOff */
BAIL_IF_ERRPASS(!readui32(io, &version), NULL);
Jul 3, 2017
Jul 3, 2017
125
Jul 22, 2017
Jul 22, 2017
126
BAIL_IF(version != 0x50, PHYSFS_ERR_UNSUPPORTED, NULL);
Jun 20, 2017
Jun 20, 2017
127
Jul 22, 2017
Jul 22, 2017
128
BAIL_IF_ERRPASS(!io->seek(io, rootCatOffset), NULL);
Jun 20, 2017
Jun 20, 2017
129
Jul 22, 2017
Jul 22, 2017
130
131
unpkarc = UNPK_openArchive(io);
BAIL_IF_ERRPASS(!unpkarc, NULL);
Jun 20, 2017
Jun 20, 2017
132
Jul 22, 2017
Jul 22, 2017
133
if (!vdfLoadEntries(io, count, vdfDosTimeToEpoch(timestamp), unpkarc))
Jun 20, 2017
Jun 20, 2017
134
{
Jul 22, 2017
Jul 22, 2017
135
136
UNPK_abandonArchive(unpkarc);
return NULL;
Jun 20, 2017
Jun 20, 2017
137
138
} /* if */
Jul 22, 2017
Jul 22, 2017
139
140
return unpkarc;
} /* VDF_openArchive */
Jun 20, 2017
Jun 20, 2017
141
142
143
144
145
146
147
148
149
150
151
152
153
const PHYSFS_Archiver __PHYSFS_Archiver_VDF =
{
CURRENT_PHYSFS_ARCHIVER_API_VERSION,
{
"VDF",
"Gothic I/II engine format",
"Francesco Bertolaccini <bertolaccinifrancesco@gmail.com>",
"https://github.com/frabert",
0, /* supportsSymlinks */
},
VDF_openArchive,
Aug 12, 2017
Aug 12, 2017
154
UNPK_enumerate,
Jul 22, 2017
Jul 22, 2017
155
UNPK_openRead,
Jun 20, 2017
Jun 20, 2017
156
157
158
159
UNPK_openWrite,
UNPK_openAppend,
UNPK_remove,
UNPK_mkdir,
Jul 22, 2017
Jul 22, 2017
160
161
UNPK_stat,
UNPK_closeArchive
Jun 20, 2017
Jun 20, 2017
162
163
164
165
};
#endif /* defined PHYSFS_SUPPORTS_VDF */
Jul 22, 2017
Jul 22, 2017
166
/* end of physfs_archiver_vdf.c ... */