~jelmer/smpq/vcs-field-uses-insecure-uri

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/*
    common.h - StormLib MPQ archiving utility
    Copyright (C) 2010 - 2016  Pali Rohár <pali.rohar@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <time.h>

#if defined(_MSC_VER)
#define inline __inline
#elif defined(__STRICT_ANSI__)
#define inline __inline__
#endif

/*********
 * Flags *
 *********/

#define CREATE			1 << 0
#define LIST			1 << 0

/* Options - program */
#define QUIET			1 << 1
#define OVERWRITE		1 << 2
#define VERBOSE			1 << 3

/* Options - archive types */
#define MPQ_VERSION		1 << 4
#define MPQ_VERSION_1		1 << 5
#define MPQ_VERSION_2		1 << 6
#define MPQ_VERSION_3		1 << 7
#define MPQ_VERSION_4		1 << 8
#define MPQ_PATCHED		1 << 9
#define MPQ_PARTIAL		1 << 10
#define MPQ_ENCRYPTED		1 << 11
#define MPQ_NOT_ENCRYPTED	1 << 12

/* Options - archive open/create */
#define NO_SYSTEM_LF		1 << 14
#define NO_LISTFILE		1 << 15
#define LISTFILE		1 << 16
#define NO_ATTRIBUTES		1 << 17
#define SECTOR_CRC		1 << 18
#define MAX_FILE_COUNT		1 << 19

/* Options - file */
#define LOCALE			1 << 20
#define ENCRYPT			1 << 21
#define FIX_KEY			1 << 22
#define DELETE_MARKER		1 << 23
#define SINGLE_UNIT		1 << 24
#define COMPRESSION		1 << 25

/* Options - with arguments */
#define MPQ_VERSION_ARG		1
#define LISTFILE_ARG		2
#define MAX_FILE_COUNT_ARG	3
#define LOCALE_ARG		4
#define COMPRESSION_ARG		5

/*************
 * Variables *
 *************/

/* Application name */
extern const char * app;

/***********************************************
 * Functions for manipulating with MPQ archive *
 ***********************************************/

/**
 * Create new archive and/or append file(s) to archive
 *
 * Internaly this function calls SFileCreateArchive or SFileOpenArchive for getting access to archive.
 * For each file check if it has correct name and calls SFileCreateFile. Next it uses SFileWriteFile for writing file data to archive.
 */
int smpq_append(const char * archive, const char * const files[], unsigned int flags, unsigned int locale, unsigned int maxFileCount, const char * compression);

/**
 * Extract or print list files from archive
 *
 * Internaly this function open archive throw SFileOpenArchive and append all patched archives to memmory by calling SFileOpenPatchArchive
 * For each file mask it calls SFileFindFirstFile. Is return first (and then continue searching) valid file with mask and then it try
 * extract using functions SFileOpenFileEx and SFileReadFile. MPQ archives does not have stored real filenames (only hashes) so original
 * file names must be stored in other list text file (MPQ archives does not support directory structures, so for this is used standard
 * windows separator = char backslash '\'). So SFileFindFirstFile only tries check if file witch given name from list is correct
 * for stored hashes. When we use more patched archives it is normal that file with same name is in more patched archives (so search
 * function return one file name more times). To prevent extracting one file more times, smpq remember extracted files. For this is used
 * dictionary struct trie, which spend linear time (of path) for remeber file and linear time too for check if file is in this structre
 * (if file was extracted). When is needed to extract file with long path and subdirs does not exist, smpq will use function mkpath,
 * which recursive create needed directories (find separator '/').
 */
int smpq_extract(const char * archive, const char * const files[], unsigned int flags, const char * listfile, unsigned int locale, const char * const parchives[]);

/**
 * Show info about archive
 *
 * Internaly this function only calls StormLib GetInfo function.
 */
int smpq_info(const char * archive, unsigned int flags);

/**
 * Remove file(s) from archive
 *
 * Internaly this function only calls for each specified file SFileRemoveFile if exist.
 */
int smpq_remove(const char * archive, const char * const files[], unsigned int flags, const char * listfile, unsigned int locale);

/**
 * Rename file in archive
 *
 * Internaly this function only calls for each specified file SFileRenameFile if exist.
 */
int smpq_rename(const char * archive, const char * oldName, const char * newName, unsigned int flags, const char * listfile, unsigned int locale);

/**
 * Load system listfiles for archive to memory
 *
 * Internaly this function looks for all *.txt files in system StormLib directory and tries load all text list files to memory
 * by calling SFileAddListFile. On Windows is this directory same with directory where are smpq executable.
 */
void smpq_systemlistfiles(void * SArchive, const char * archive, unsigned int flags);

/************************
 * Functions for output *
 ************************/

/* Print formatted error message */
void printError(const char * archive, const char * file, const char * message, int errnum);

/* Print verbose message */
void printVerbose(const char * archive, const char * message, const char * file);

/* Print normal message */
void printMessage(const char * message, ...);

/*************************************
 * Functions for FILETIME conversion *
 *************************************/

/**
 * MPQ archives stores modification time of files in FILETIME format.
 * These function convert FILETIME to/from Unix timestamp which is default format
 */

#define OFFSET 116444736000000000ULL /* Number of 100 ns units between 01/01/1601 and 01/01/1970 */
#define NSEC 10000000ULL /* Convert 100 ns to sec */

#define TYPE_SIGNED(TYPE) ( (TYPE) 0 > (TYPE) -1 )
#define TYPE_SHIFT(TYPE) ( sizeof(TYPE) * 8 - TYPE_SIGNED(TYPE) - 1 )
#define TYPE_MAX(TYPE) ( (TYPE)( ~( 1LL << TYPE_SHIFT(TYPE) ) << 1 ) + 1 )

/* Convert time_t to FILETIME */
static inline void toFileTime(unsigned long long int * to, time_t from) {

	if ( from == 0 )
		*to = 0;
	else
		*to = from * NSEC + OFFSET;

}

/* Convert FILETIME to time_t */
static inline int fromFileTime(time_t * to, unsigned long long int from) {

	if ( from < OFFSET )
		return 0;

	if ( ( from - OFFSET ) / NSEC > TYPE_MAX(time_t) )
		return 1;

	*to = ( from - OFFSET ) / NSEC;

	return 1;

}

#undef TYPE_SIGNED
#undef TYPE_LEN
#undef TYPE_MAX

#undef OFFSET
#undef NSEC

/**********************************************
 * Functions for path conversation in archive *
 **********************************************/

/**
 * MPQ archives does not support directory structures. Instead it store full path to file in file name
 * As default MPQ archives are designed for Windows, so dir separator is backslash character.
 * These functions convert Windows file path to/from Unix
 */

/* Replace all chars '/' in path to '\\' */
static inline void toArchivePath(char * to, const char * from) {

	int i = -1;

	while ( from[++i] ) {

		if ( from[i] == '/' )
			to[i] = '\\';
		else
			to[i] = from[i];

	}

	to[i] = 0;

}

/* Replace all chars '\\' in path to '/' on other OS than Windows */
static inline void fromArchivePath(char * to, const char * from) {

#if defined(WIN32) || defined(_MSC_VER)

	strcpy(to, from);

#else

	int i = -1;

	while ( from[++i] ) {

		if ( from[i] == '\\' )
			to[i] = '/';
		else
			to[i] = from[i];

	}

	to[i] = 0;

#endif

}