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.
19 #include "ByteArray.h"
21 #include <sys/types.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];
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
) {
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
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
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
) {
72 int get_pseudo_rand() {
73 return( ((_last_rand
= _last_rand
* 214013L
74 + 2531011L) >> 16) & 0x7fff );
77 void clib_decrypt_text(char *toenc
) {
81 toenc
[0] -= clibpasswencstring
[adx
];
93 void fgetnulltermstring(char *sss
, ByteArray
*ddd
, int bufsize
) {
95 off_t l
= ByteArray_get_length(ddd
);
97 if (b
< bufsize
- 1) b
++;
98 if(ByteArray_get_position(ddd
) >= l
)
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
) {
115 res
.i
= ByteArray_readUnsignedInt(ba
);
118 res
.c
[i
] -= get_pseudo_rand();
122 void fread_data_intarray_enc(struct ByteArray
*ba
, unsigned* dest
, size_t count
) {
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
) {
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
) {
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
) {
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
)
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
);
175 int read_new_new_format_clib(MultiFileLibNew
* mfl
, struct ByteArray
* wout
, int libver
) {
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
);
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
);
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
);
211 for (aa
= 0; aa
< mfl
->num_files
; aa
++)
212 clib_decrypt_text(mfl
->filenames
[aa
]);
217 int csetlib(char *namm
, char *passw
) {
218 original_base_filename
[0] = 0;
221 lib_file_name
[0] = ' ';
222 lib_file_name
[1] = 0;
225 strcpy(base_path
, ".");
227 int passwmodifier
= 0, aa
;
230 struct ByteArray ba_b
, *ba
= &ba_b
; // allocate on stack so we dont have to deal with mem leaks.
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)
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
))
279 else if (lib_version
== 20) {
280 if (read_new_new_format_clib(&mflib
, ba
, lib_version
))
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
))
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
]);
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
;
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;
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;
369 for (bb
= 0; bb
< mflib
.num_files
; bb
++) {
370 if (stricmp(mflib
.filenames
[bb
], fill
) == 0)
376 int clibfilesize(char *fill
) {
377 int idxx
= clibfindindex(fill
);
378 if (idxx
>= 0) return mflib
.length
[idxx
];
382 int cliboffset(char *fill
) {
383 int idxx
= clibfindindex(fill
);
385 return mflib
.offset
[idxx
];
389 const char *clibgetoriginalfilename() {
390 return original_base_filename
;
393 char actfilename
[250];
394 char *clibgetdatafile(char *fill
) {
395 int idxx
= clibfindindex(fill
);
397 #if defined(LINUX_VERSION) || defined(MAC_VERSION)
398 sprintf(actfilename
, "%s/%s", base_path
, mflib
.data_filenames
[mflib
.file_datafile
[idxx
]]);
400 sprintf(actfilename
, "%s\\%s", base_path
, mflib
.data_filenames
[mflib
.file_datafile
[idxx
]]);
408 FILE *clibopenfile(char *filly
, char *readmode
) {
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
]]);
416 sprintf(actfilename
, "%s\\%s", base_path
, mflib
.data_filenames
[mflib
.file_datafile
[bb
]]);
418 tfil
= ci_fopen(actfilename
, readmode
);
421 fseek(tfil
, mflib
.offset
[bb
], SEEK_SET
);
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
437 tfil
= ci_fopen(filnamm
, fmt
);
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
);
448 // check datafile first, then scan directory
449 if ((cliboffset(filnamm
) < 1) | (fmt
[0] != 'r'))
450 tfil
= ci_fopen(filnamm
, fmt
);
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
));