cpp -> c
[rofl0r-agsutils.git] / Clib32.c
blobd28c0e36f435db0b95140df9f6fc4f44665dde30
1 /* CLIB32 - DJGPP implemention of the CLIB reader.
2 (c) 1998-99 Chris Jones
4 22/12/02 - Shawn's Linux changes approved and integrated - CJ
6 v1.2 (Apr'01) added support for new multi-file CLIB version 10 files
7 v1.1 (Jul'99) added support for appended-to-exe data files
9 This is UNPUBLISHED PROPRIETARY SOURCE CODE;
10 the contents of this file may not be disclosed to third parties,
11 copied or duplicated in any form, in whole or in part, without
12 prior express permission from Chris Jones.
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stddef.h>
19 #include "ByteArray.h"
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <stdint.h>
25 #include <stddef.h>
27 #define CLIB_IS_INSTALLED
28 char clib32copyright[] = "CLIB32 v1.21 (c) 1995,1996,1998,2001,2007 Chris Jones";
29 char lib_file_name[255] = " ";
30 char base_path[255] = ".";
31 char original_base_filename[255];
32 char clbuff[20];
33 const int RAND_SEED_SALT = 9338638; // must update editor agsnative.cpp if this changes
34 #define MAX_FILES 10000
35 #define MAXMULTIFILES 25
37 static off_t filelength(int fd) {
38 struct stat st;
39 fstat(fd, &st);
40 return st.st_size;
43 struct MultiFileLib {
44 char data_filenames[MAXMULTIFILES][20];
45 size_t num_data_files;
46 char filenames[MAX_FILES][25];
47 unsigned offset[MAX_FILES];
48 unsigned length[MAX_FILES];
49 char file_datafile[MAX_FILES]; // number of datafile
50 size_t num_files;
53 struct MultiFileLibNew {
54 char data_filenames[MAXMULTIFILES][50];
55 size_t num_data_files;
56 char filenames[MAX_FILES][100];
57 unsigned offset[MAX_FILES];
58 unsigned length[MAX_FILES];
59 char file_datafile[MAX_FILES]; // number of datafile
60 size_t num_files;
63 MultiFileLibNew mflib;
64 NATIVESTATIC char *clibendfilesig = "CLIB\x1\x2\x3\x4SIGE";
65 NATIVESTATIC char *clibpasswencstring = "My\x1\xde\x4Jibzle";
66 NATIVESTATIC int _last_rand;
68 void init_pseudo_rand_gen(int seed) {
69 _last_rand = seed;
72 int get_pseudo_rand() {
73 return( ((_last_rand = _last_rand * 214013L
74 + 2531011L) >> 16) & 0x7fff );
77 void clib_decrypt_text(char *toenc) {
78 int adx = 0;
80 while (1) {
81 toenc[0] -= clibpasswencstring[adx];
82 if (toenc[0] == 0)
83 break;
85 adx++;
86 toenc++;
88 if (adx > 10)
89 adx = 0;
93 void fgetnulltermstring(char *sss, ByteArray *ddd, int bufsize) {
94 int b = -1;
95 off_t l = ByteArray_get_length(ddd);
96 do {
97 if (b < bufsize - 1) b++;
98 if(ByteArray_get_position(ddd) >= l)
99 return;
100 sss[b] = ByteArray_readByte(ddd);
101 } while (sss[b] != 0);
104 long last_opened_size;
106 int fread_data_enc_byte(struct ByteArray *ba) {
107 return ByteArray_readUnsignedByte(ba) - get_pseudo_rand();
110 uint32_t fread_data_enc_int(struct ByteArray *ba) {
111 union {
112 uint32_t i;
113 unsigned char c[4];
114 } res;
115 res.i = ByteArray_readUnsignedInt(ba);
116 size_t i = 0;
117 for(; i < 4; i++)
118 res.c[i] -= get_pseudo_rand();
119 return res.i;
122 void fread_data_intarray_enc(struct ByteArray *ba, unsigned* dest, size_t count) {
123 size_t i = 0;
124 for(; i < count; i++)
125 dest[i] = fread_data_enc_int(ba);
128 void fread_data_intarray(struct ByteArray *ba, unsigned* dest, size_t count) {
129 size_t i = 0;
130 for(; i < count; i++)
131 dest[i] = ByteArray_readInt(ba);
134 void fread_data_enc(void *data, size_t dataSize, size_t dataCount, struct ByteArray *ooo) {
135 ByteArray_readMultiByte(ooo, (char*)data, dataSize * dataCount);
136 unsigned char *dataChar = (unsigned char*)data;
137 for (int i = 0; i < dataSize * dataCount; i++)
138 dataChar[i] -= get_pseudo_rand();
141 void fgetstring_enc(char *sss, struct ByteArray *ooo, int maxLength) {
142 int i = 0;
143 while ((i == 0) || (sss[i - 1] != 0)) {
144 sss[i] = ByteArray_readByte(ooo) - get_pseudo_rand();
145 if (i < maxLength - 1) i++;
149 int getw_enc(struct ByteArray *ooo) {
150 return fread_data_enc_int(ooo);
153 int read_new_new_enc_format_clib(MultiFileLibNew * mfl, struct ByteArray * wout, int libver) {
154 size_t aa;
155 int randSeed = ByteArray_readInt(wout);
156 init_pseudo_rand_gen(randSeed + RAND_SEED_SALT);
157 mfl->num_data_files = getw_enc(wout);
158 for (aa = 0; aa < mfl->num_data_files; aa++)
159 fgetstring_enc(mfl->data_filenames[aa], wout, 50);
160 mfl->num_files = getw_enc(wout);
162 if (mfl->num_files > MAX_FILES)
163 return -1;
165 for (aa = 0; aa < mfl->num_files; aa++)
166 fgetstring_enc(mfl->filenames[aa], wout, 100);
168 fread_data_intarray_enc(wout, mfl->offset, mfl->num_files);
169 fread_data_intarray_enc(wout, mfl->length, mfl->num_files);
170 for(aa = 0; aa < mfl->num_files; aa++)
171 mfl->file_datafile[aa] = fread_data_enc_byte(wout);
172 return 0;
175 int read_new_new_format_clib(MultiFileLibNew * mfl, struct ByteArray * wout, int libver) {
176 int aa;
177 mfl->num_data_files = ByteArray_readInt(wout);
178 for (aa = 0; aa < mfl->num_data_files; aa++)
179 fgetnulltermstring(mfl->data_filenames[aa], wout, 50);
180 mfl->num_files = ByteArray_readInt(wout);
182 if (mfl->num_files > MAX_FILES) return -1;
184 for (aa = 0; aa < mfl->num_files; aa++) {
185 short nameLength = ByteArray_readShort(wout);
186 nameLength /= 5;
187 ByteArray_readMultiByte(wout, mfl->filenames[aa], nameLength);
188 clib_decrypt_text(mfl->filenames[aa]);
190 fread_data_intarray(wout, mfl->offset, mfl->num_files);
191 fread_data_intarray(wout, mfl->length, mfl->num_files);
192 ByteArray_readMultiByte(wout, mfl->file_datafile, mfl->num_files);
193 return 0;
196 int read_new_format_clib(MultiFileLib * mfl, struct ByteArray * wout, int libver) {
197 mfl->num_data_files = ByteArray_readInt(wout);
198 ByteArray_readMultiByte(wout, (char*) mfl->data_filenames, 20U * mfl->num_data_files);
199 mfl->num_files = ByteArray_readInt(wout);
201 if (mfl->num_files > MAX_FILES) return -1;
203 ByteArray_readMultiByte(wout, (char*) mfl->filenames, 25U * mfl->num_files);
205 fread_data_intarray(wout, mfl->offset, mfl->num_files);
206 fread_data_intarray(wout, mfl->length, mfl->num_files);
207 ByteArray_readMultiByte(wout, mfl->file_datafile, mfl->num_files);
209 if (libver >= 11) {
210 size_t aa;
211 for (aa = 0; aa < mfl->num_files; aa++)
212 clib_decrypt_text(mfl->filenames[aa]);
214 return 0;
217 int csetlib(char *namm, char *passw) {
218 original_base_filename[0] = 0;
220 if (namm == NULL) {
221 lib_file_name[0] = ' ';
222 lib_file_name[1] = 0;
223 return 0;
225 strcpy(base_path, ".");
227 int passwmodifier = 0, aa;
228 size_t cc, l;
230 struct ByteArray ba_b, *ba = &ba_b; // allocate on stack so we dont have to deal with mem leaks.
231 ByteArray_ctor(ba);
232 if(!ByteArray_open_file(ba, namm)) return -1;
233 ByteArray_set_endian(ba, BAE_LITTLE); // all ints etc are saved in little endian.
234 off_t ba_len = ByteArray_get_length(ba);
235 ByteArray_readMultiByte(ba, clbuff, 5);
237 uint32_t absoffs = 0; /* we read 4 bytes- so our datatype
238 must be 4 bytes as well, since we use a pointer to it */
240 if (strncmp(clbuff, "CLIB", 4) != 0) {
241 ByteArray_set_position(ba, ba_len - 12);
242 ByteArray_readMultiByte(ba, clbuff, 12);
244 if (strncmp(clbuff, clibendfilesig, 12) != 0)
245 return -2;
246 // it's an appended-to-end-of-exe thing
247 ByteArray_set_position(ba, ba_len - 16);
248 absoffs = ByteArray_readUnsignedInt(ba);
249 ByteArray_set_position(ba, absoffs + 5);
252 int lib_version = ByteArray_readUnsignedByte(ba);
253 if ((lib_version != 6) && (lib_version != 10) &&
254 (lib_version != 11) && (lib_version != 15) &&
255 (lib_version != 20) && (lib_version != 21))
256 return -3; // unsupported version
258 char *nammwas = namm;
259 // remove slashes so that the lib name fits in the buffer
260 while (namm[0] == '\\' || namm[0] == '/') namm++;
262 if (namm != nammwas) {
263 // store complete path
264 snprintf(base_path, sizeof(base_path), "%s", nammwas);
265 base_path[namm - nammwas] = 0;
266 l = strlen(base_path);
267 if ((base_path[l - 1] == '\\') || (base_path[l - 1] == '/'))
268 base_path[l - 1] = 0;
271 if (lib_version >= 10) {
272 if (ByteArray_readUnsignedByte(ba) != 0)
273 return -4; // not first datafile in chain
275 if (lib_version >= 21) {
276 if (read_new_new_enc_format_clib(&mflib, ba, lib_version))
277 return -5;
279 else if (lib_version == 20) {
280 if (read_new_new_format_clib(&mflib, ba, lib_version))
281 return -5;
282 } else {
283 // PSP: Allocate struct on the heap to avoid overflowing the stack.
284 MultiFileLib* mflibOld = (MultiFileLib*)malloc(sizeof(MultiFileLib));
286 if (read_new_format_clib(mflibOld, ba, lib_version))
287 return -5;
288 // convert to newer format
289 mflib.num_files = mflibOld->num_files;
290 mflib.num_data_files = mflibOld->num_data_files;
291 memcpy(mflib.offset, mflibOld->offset, sizeof(int) * mflib.num_files);
292 memcpy(mflib.length, mflibOld->length, sizeof(int) * mflib.num_files);
293 memcpy(mflib.file_datafile, mflibOld->file_datafile, sizeof(char) * mflib.num_files);
294 for (aa = 0; aa < mflib.num_data_files; aa++)
295 strcpy(mflib.data_filenames[aa], mflibOld->data_filenames[aa]);
296 for (aa = 0; aa < mflib.num_files; aa++)
297 strcpy(mflib.filenames[aa], mflibOld->filenames[aa]);
299 free(mflibOld);
302 ByteArray_close_file(ba);
303 strcpy(lib_file_name, namm);
305 // make a backup of the original file name
306 strcpy(original_base_filename, mflib.data_filenames[0]);
307 strlwr(original_base_filename);
309 strcpy(mflib.data_filenames[0], namm);
310 for (aa = 0; aa < mflib.num_files; aa++) {
311 // correct offsetes for EXE file
312 if (mflib.file_datafile[aa] == 0)
313 mflib.offset[aa] += absoffs;
315 return 0;
318 passwmodifier = ByteArray_readUnsignedByte(ba);
319 ByteArray_readUnsignedByte(ba); // unused byte
320 mflib.num_data_files = 1;
321 strcpy(mflib.data_filenames[0], namm);
323 short tempshort = ByteArray_readShort(ba);
324 mflib.num_files = tempshort;
326 if (mflib.num_files > MAX_FILES) return -4;
328 ByteArray_readMultiByte(ba, clbuff, 13); // skip password dooberry
329 for (aa = 0; aa < mflib.num_files; aa++) {
330 ByteArray_readMultiByte(ba, mflib.filenames[aa], 13);
331 l = strlen(mflib.filenames[aa]);
332 for (cc = 0; cc < l; cc++)
333 mflib.filenames[aa][cc] -= passwmodifier;
335 for(cc = 0; cc < mflib.num_files; cc++)
336 mflib.length[cc] = ByteArray_readUnsignedInt(ba);
338 ByteArray_set_position_rel(ba, 2 * mflib.num_files); // skip flags & ratio
340 mflib.offset[0] = ByteArray_get_position(ba);
341 strcpy(lib_file_name, namm);
342 ByteArray_close_file(ba);
344 for (aa = 1; aa < mflib.num_files; aa++) {
345 mflib.offset[aa] = mflib.offset[aa - 1] + mflib.length[aa - 1];
346 mflib.file_datafile[aa] = 0;
348 mflib.file_datafile[0] = 0;
349 return 0;
352 int clibGetNumFiles() {
353 if (lib_file_name[0] == ' ') return 0;
354 return mflib.num_files;
357 const char *clibGetFileName(int index) {
358 if (lib_file_name[0] == ' ') return 0;
360 if ((index < 0) || (index >= mflib.num_files)) return 0;
362 return mflib.filenames[index];
365 int clibfindindex(char *fill) {
366 if (lib_file_name[0] == ' ') return -1;
368 size_t bb;
369 for (bb = 0; bb < mflib.num_files; bb++) {
370 if (stricmp(mflib.filenames[bb], fill) == 0)
371 return bb;
373 return -1;
376 int clibfilesize(char *fill) {
377 int idxx = clibfindindex(fill);
378 if (idxx >= 0) return mflib.length[idxx];
379 return -1;
382 int cliboffset(char *fill) {
383 int idxx = clibfindindex(fill);
384 if (idxx >= 0)
385 return mflib.offset[idxx];
386 return -1;
389 const char *clibgetoriginalfilename() {
390 return original_base_filename;
393 char actfilename[250];
394 char *clibgetdatafile(char *fill) {
395 int idxx = clibfindindex(fill);
396 if (idxx >= 0) {
397 #if defined(LINUX_VERSION) || defined(MAC_VERSION)
398 sprintf(actfilename, "%s/%s", base_path, mflib.data_filenames[mflib.file_datafile[idxx]]);
399 #else
400 sprintf(actfilename, "%s\\%s", base_path, mflib.data_filenames[mflib.file_datafile[idxx]]);
401 #endif
402 return actfilename;
404 return 0;
407 FILE *tfil;
408 FILE *clibopenfile(char *filly, char *readmode) {
409 int bb;
410 for (bb = 0; bb < mflib.num_files; bb++) {
411 if (stricmp(mflib.filenames[bb], filly) == 0) {
412 char actfilename[250];
413 #if defined(ANDROID_VERSION)
414 sprintf(actfilename, "%s/%s", base_path, mflib.data_filenames[mflib.file_datafile[bb]]);
415 #else
416 sprintf(actfilename, "%s\\%s", base_path, mflib.data_filenames[mflib.file_datafile[bb]]);
417 #endif
418 tfil = ci_fopen(actfilename, readmode);
419 if (tfil == NULL)
420 return NULL;
421 fseek(tfil, mflib.offset[bb], SEEK_SET);
422 return tfil;
425 return ci_fopen(filly, readmode);
428 #define PR_DATAFIRST 1
429 #define PR_FILEFIRST 2
430 int cfopenpriority = PR_DATAFIRST;
432 FILE *clibfopen(char *filnamm, char *fmt) {
433 last_opened_size = -1;
434 if (cfopenpriority == PR_FILEFIRST) {
435 // check for file, otherwise use datafile
436 if (fmt[0] != 'r') {
437 tfil = ci_fopen(filnamm, fmt);
438 } else {
439 tfil = ci_fopen(filnamm, fmt);
441 if ((tfil == NULL) && (lib_file_name[0] != ' ')) {
442 tfil = clibopenfile(filnamm, fmt);
443 last_opened_size = clibfilesize(filnamm);
447 } else {
448 // check datafile first, then scan directory
449 if ((cliboffset(filnamm) < 1) | (fmt[0] != 'r'))
450 tfil = ci_fopen(filnamm, fmt);
451 else {
452 tfil = clibopenfile(filnamm, fmt);
453 last_opened_size = clibfilesize(filnamm);
458 if ((last_opened_size < 0) && (tfil != NULL))
459 last_opened_size = filelength(fileno(tfil));
461 return tfil;