Subversion Repositories spk

Rev

Rev 317 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 cycrow 1
// File.cpp: implementation of the C_File class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
 
5
#include "File.h"
6
 
7
#include <time.h>
8
#include <sys/types.h>
9
#include <sys/stat.h>
10
 
11
#ifndef _WIN32
12
#include <unistd.h>
13
#endif
14
 
15
#include <iostream>
16
#include <fstream>
17
 
18
#include "spk.h"
19
 
6 cycrow 20
#include "BaseFile.h"
1 cycrow 21
#include "CatFile.h"
22
#include "DirIO.h"
23
 
24
#include "secure.h"
25
 
26
// LZMA compression
27
#include "lzma/Lzma86Enc.h"
28
#include "lzma/Lzma86Dec.h"
29
 
115 cycrow 30
// X2BOD
283 cycrow 31
#ifdef _XBODLIBRARY__
32
#include "../Windows/libx2bc.h"
33
#else
115 cycrow 34
#include "x2bc/x2bc_common/settings.h"
35
#include "x2bc/x2bc_common/bob_dom.h"
36
#include "x2bc/x2bc_common/bod_parser.h"
37
#include "x2bc/x2bc_common/realfile_stream.h"
283 cycrow 38
#endif
115 cycrow 39
 
1 cycrow 40
//////////////////////////////////////////////////////////////////////
127 cycrow 41
// STATIC FUNCTIONS
42
//////////////////////////////////////////////////////////////////////
43
 
197 cycrow 44
Utils::WString C_File::GetDirectory(FileType eType, const Utils::WString &filename, CBaseFile *file)
127 cycrow 45
{
46
	switch (eType)
47
	{
48
	case FILETYPE_SCRIPT:
277 cycrow 49
		return L"scripts";
127 cycrow 50
	case FILETYPE_TEXT:
277 cycrow 51
		return L"t";
127 cycrow 52
	case FILETYPE_README:
53
	{
54
		if (file)
197 cycrow 55
			return Utils::WString(L"PluginManager/Readme/") + file->getNameValidFile();
56
		return L"PluginManager/Readme";
127 cycrow 57
	}
58
	case FILETYPE_MAP:
277 cycrow 59
		return L"maps";
127 cycrow 60
	case FILETYPE_MOD:
277 cycrow 61
		return L"mods";
127 cycrow 62
	case FILETYPE_UNINSTALL:
197 cycrow 63
		return L"PluginManager/Uninstall";
127 cycrow 64
	case FILETYPE_SOUND:
196 cycrow 65
		if (!filename.empty() && !CFileIO(filename).isFileExtension(L"wav"))
277 cycrow 66
			return L"soundtrack";
197 cycrow 67
		return L"s";
127 cycrow 68
	case FILETYPE_SOUNDTRACK:
277 cycrow 69
		return L"soundtrack";
127 cycrow 70
	case FILETYPE_EXTRA:
197 cycrow 71
		return L"PluginManager/Extras";
127 cycrow 72
	case FILETYPE_SCREEN:
197 cycrow 73
		return L"loadscr";
127 cycrow 74
	case FILETYPE_ADVERT:
197 cycrow 75
		return L"PluginManager/Graphics";
127 cycrow 76
	case FILETYPE_MISSION:
277 cycrow 77
		return L"director";
127 cycrow 78
	}
197 cycrow 79
	return Utils::WString::Null();
127 cycrow 80
}
81
 
82
bool C_File::DoesTypeHaveExtraDir(int i)
83
{
84
	switch (i)
85
	{
86
	case FILETYPE_EXTRA:
87
	case FILETYPE_SHIPSCENE:
88
	case FILETYPE_COCKPITSCENE:
89
	case FILETYPE_SHIPMODEL:
90
	case FILETYPE_SHIPOTHER:
91
		return true;
92
	}
93
	return false;
94
}
95
 
96
//////////////////////////////////////////////////////////////////////
1 cycrow 97
// Construction/Destruction
98
//////////////////////////////////////////////////////////////////////
99
 
100
void CProgressInfoDone::DoingFile ( C_File *file )
101
{
102
	m_iDone = 0;
103
 
104
	if ( !m_bDontDoMax )
105
	{
106
		if ( file->GetData() && file->GetDataSize() )
107
			m_lMaxSize = file->GetDataSize();
108
		else
109
			m_lMaxSize = file->GetSize();
110
	}
111
 
112
	m_pOnFile = file;
113
}
114
 
115
void CProgressInfoDone::DoingPackage ( SMultiSpkFile *file )
116
{
117
	m_iDone = 0;
118
 
119
	if ( !m_bDontDoMax )
120
		m_lMaxSize = file->lSize;
121
 
122
	m_pOnPackage = file;
123
}
124
 
125
int C_File::m_iTempNum = 0;
126
 
127
C_File::C_File()
128
{
129
	m_bDontDeleteData = false;
130
	m_bUsedMalloc = false;
131
	m_sData = NULL;
132
	Reset();
133
}
134
 
197 cycrow 135
C_File::C_File(const Utils::WString &filename)
1 cycrow 136
{
137
	m_bDontDeleteData = false;
138
	m_bUsedMalloc = false;
139
	m_sData = NULL;
140
	Reset ();
130 cycrow 141
	setFilename(filename);
1 cycrow 142
}
143
 
144
C_File::~C_File()
145
{
146
	DeleteData ();
160 cycrow 147
	if (!_sTmpFile.empty())
197 cycrow 148
		CFileIO::Remove(_sTmpFile);
1 cycrow 149
}
150
 
151
 
178 cycrow 152
long C_File::uncompressedDataSize() const
153
{
154
	if (m_lUncomprDataSize)
155
		return m_lUncomprDataSize;
156
	if (m_lSize)
157
		return m_lSize;
158
	return m_lDataSize;
159
}
160
 
1 cycrow 161
/*
178 cycrow 162
	Func:	getDirectory()
1 cycrow 163
	Return: Directory String
164
	Desc:	Returns the directory the file goes into, based on m_sDir and Filetype
165
*/
197 cycrow 166
Utils::WString C_File::getDirectory(CBaseFile *file) const
121 cycrow 167
{
168
	if (IsFakePatch())
197 cycrow 169
		return L"";
121 cycrow 170
 
197 cycrow 171
	Utils::WString sDir = _sDir;
121 cycrow 172
 
197 cycrow 173
	if ((m_iFileType == FILETYPE_MOD) && (sDir == L"Patch"))
174
		return L"PluginManager/Patch";
121 cycrow 175
 
197 cycrow 176
	if ((!sDir.empty()) && (m_iFileType != FILETYPE_README) && sDir != L".")
121 cycrow 177
	{
197 cycrow 178
		Utils::WString dir = sDir.findReplace(L"\\", L"/");
121 cycrow 179
		if (file)
180
		{
197 cycrow 181
			dir = dir.findReplace(L"$scriptname", file->getNameValidFile());
182
			dir = dir.findReplace(L"$scriptauthor", file->author());
121 cycrow 183
		}
184
		return dir;
185
	}
186
 
130 cycrow 187
	return C_File::GetDirectory(m_iFileType, _sName, file);
121 cycrow 188
}
189
 
197 cycrow 190
Utils::WString C_File::getNameDirectory(CBaseFile *file) const
128 cycrow 191
{
197 cycrow 192
	Utils::WString dir = getDirectory(file);
128 cycrow 193
	if (!dir.empty())
197 cycrow 194
		dir += L"/";
195
	return (dir + _sName).findReplace(L"\\", L"/").findReplace(L"//", L"/");
128 cycrow 196
}
197
 
1 cycrow 198
/*
199
	Func:	Reset()
200
	Desc:	Resets the file data, clears all data inside
201
			Clears the Data stream
202
*/
203
void C_File::Reset ()
204
{
205
	m_iLastError = SPKERR_NONE;
206
	m_bLoaded = false;
127 cycrow 207
	m_iFileType = FILETYPE_UNKNOWN;
1 cycrow 208
	m_lSize = 0;
209
	m_iVersion = 0;
210
	m_bSigned = false;
160 cycrow 211
	_iUsed = 0;
1 cycrow 212
	m_tTime = 0;
213
	m_lDataSize = m_lUncomprDataSize = 0;
214
	DeleteData ();
215
	m_iDataCompression = 0;
216
	m_bSkip = false;
217
	m_bShared = false;
218
	m_bCompressedToFile = false;
219
	m_bDisabled = false;
220
	m_bUpdatedSignature = false;
221
	m_iPos = -1;
127 cycrow 222
	_iGame = 0;
1 cycrow 223
}
224
 
225
bool C_File::UpdateSigned()
226
{
227
	switch ( m_iFileType )
228
	{
229
		// text files, readmes, screenshots can be always considered to be signed
230
		case FILETYPE_TEXT:
231
		case FILETYPE_README:
232
		case FILETYPE_SCREEN:
233
		case FILETYPE_ADVERT:
234
		case FILETYPE_SOUND:
235
		case FILETYPE_BACKUP:
236
			m_bSigned = true;
237
			break;
238
 
239
		// mods, maps are always not signed
240
		case FILETYPE_MOD:
241
		case FILETYPE_MAP:
242
		case FILETYPE_SHIPOTHER:
243
		case FILETYPE_SHIPMODEL:
244
		case FILETYPE_SHIPSCENE:
245
		case FILETYPE_COCKPITSCENE:
246
			m_bSigned = false;
247
			break;
248
 
249
		// extra files are a special case
250
		case FILETYPE_EXTRA:
197 cycrow 251
			if ( this->dir().left(6).Compare(L"extras") )
1 cycrow 252
				m_bSigned = true;
253
			else
254
				m_bSigned = false;
255
			break;
256
 
257
		// script files need to check
258
		case FILETYPE_SCRIPT:
259
		case FILETYPE_UNINSTALL:
260
			m_bSigned = this->ReadSignedFile();
261
			break;
262
 
263
		// mission files
264
		case FILETYPE_MISSION:
265
			m_bSigned = false;
266
			break;
267
	}
268
 
269
	return m_bSigned;
270
}
271
 
272
/*
273
	Func:	DeleteData()
274
	Desc:	Clears the data stream, uses free() if created by malloc, otherwise use delete.
275
*/
276
void C_File::DeleteData ()
277
{
278
	if ( m_sData )
279
	{
280
		if ( m_bUsedMalloc )
281
			free ( m_sData );
282
		else
283
			delete [] m_sData;
284
		m_bDontDeleteData = false;
285
		m_sData = NULL;
286
		m_bLoaded = false;
287
		m_lDataSize = 0;
288
	}
289
	m_bUsedMalloc = false;
290
	m_iDataCompression = SPKCOMPRESS_NONE;
291
}
292
 
197 cycrow 293
int C_File::textFileID(const Utils::WString &sFilename) const
1 cycrow 294
{
295
	if ( m_iFileType != FILETYPE_TEXT )
296
		return -1;
297
 
197 cycrow 298
	Utils::WString filename = sFilename;
178 cycrow 299
 
300
	if ( filename.empty() )
130 cycrow 301
		filename = _sName;
1 cycrow 302
 
197 cycrow 303
	Utils::WString textid;
304
	if ( filename.contains(L"-L") || filename.contains(L"-l") )
305
		textid = filename.token(L"-", 1);
1 cycrow 306
	else
257 cycrow 307
		textid = filename.tokens(L".", 1, -2).right(4);
1 cycrow 308
 
178 cycrow 309
	if (textid.isNumber()) return textid.toInt();
43 cycrow 310
	return -1;
1 cycrow 311
}
130 cycrow 312
bool C_File::isAutoTextFile ()
1 cycrow 313
{
178 cycrow 314
	int textid = textFileID();
1 cycrow 315
	if ( textid == -1 ) return false;
316
 
156 cycrow 317
	if ( textid == 4 )
1 cycrow 318
		return true;
319
 
320
	// check for original name
127 cycrow 321
	if ( !_sOriginalName.empty() )
1 cycrow 322
	{
178 cycrow 323
		textid = textFileID(_sOriginalName);
1 cycrow 324
		if ( textid >= 0 && textid <= 3 )
325
			return true;
326
	}
327
 
328
	return false;
329
}
330
 
126 cycrow 331
bool C_File::isFileInAddon() const
332
{
333
	switch (m_iFileType)
334
	{
335
		case FILETYPE_SHIPMODEL:
336
		case FILETYPE_SHIPOTHER:
337
		case FILETYPE_SHIPSCENE:
338
		case FILETYPE_COCKPITSCENE:
339
		case FILETYPE_SOUND:
340
			return false;
341
	}
342
 
343
	return true;
344
}
345
 
121 cycrow 346
bool C_File::IsFakePatch() const
1 cycrow 347
{
121 cycrow 348
	if (m_iFileType != FILETYPE_MOD)
1 cycrow 349
		return false;
350
 
197 cycrow 351
	Utils::WString name = _sName;
121 cycrow 352
 
197 cycrow 353
	if (name.token(L".", 1).toLong())
1 cycrow 354
		return true;
355
 
197 cycrow 356
	if (name.left(10) == L"FakePatch_")
1 cycrow 357
		return true;
358
 
359
	return false;
360
}
361
 
362
/*
363
########################################################################################################################
364
####################################             File Pointer Functions             ####################################
365
########################################################################################################################
366
*/
367
 
368
/*
369
	Func:	SetFilename
370
	Accept:	filename - String for the filename of disk
371
	Desc:	Sets the file pointer
372
			Reads the file size and last modifed time to store in the class
373
			Splits up the filename and dir path
374
*/
178 cycrow 375
 
197 cycrow 376
void C_File::setFilename(const Utils::WString &filename)
129 cycrow 377
{
197 cycrow 378
	Utils::WString file = filename.findReplace ( L"\\", L"/" ).findReplace ( L"//", L"/" );
1 cycrow 379
 
197 cycrow 380
	_sFullDir = file.tokens(L"/", 1, -2);
381
	_sName = file.token(L"/", -1);
382
	if ( _sFullDir.right(2) == L"/." )
129 cycrow 383
		_sFullDir = _sFullDir.left(-2);
1 cycrow 384
 
385
	ReadFileSize ();
386
 
387
	ReadLastModified ();
388
}
389
 
390
 
391
/*
392
	Func:	ReadFromFile
393
	Return:	Boolean - Returns true if read was successfull
394
	Desc:	Reads data from file pointer into data stream
395
			As its read from a file, there will be no compression, so its set to None
396
*/
397
bool C_File::ReadFromFile ()
398
{
129 cycrow 399
	return this->readFromFile(filePointer());
1 cycrow 400
}
401
 
197 cycrow 402
bool C_File::readFromFile(const Utils::WString filename)
129 cycrow 403
{
52 cycrow 404
	CFileIO File(filename);
405
	if ( !File.startRead() ) {
1 cycrow 406
		m_iLastError = SPKERR_FILEOPEN;
407
		return false;
408
	}
409
 
410
	m_iDataCompression = SPKCOMPRESS_NONE;
411
	m_lDataSize = m_lUncomprDataSize = m_lSize;
412
 
413
	DeleteData ();
414
 
52 cycrow 415
	m_sData = File.readAll((size_t *)&m_lSize);
416
	if ( !m_sData ) { 
417
		m_iLastError = SPKERR_MALLOC; 
1 cycrow 418
		m_lDataSize = 0;
52 cycrow 419
		return false; 
1 cycrow 420
	}
421
 
52 cycrow 422
	m_lDataSize = m_lSize;
423
	m_tTime = File.modifiedTime();
424
 
1 cycrow 425
	m_iLastError = SPKERR_NONE;
426
 
427
	m_bLoaded = true;
428
 
52 cycrow 429
	File.close();
1 cycrow 430
	return true;
431
}
432
 
433
/*
434
	Func:	ReadFromData
435
	Accept:	data - The data stream to read
436
			size - The length of the data stream
437
	Return: Boolean - Return true if successfull
438
	Desc:	Copys data to the data stream in the file
439
			Used when data is already loaded into memory
440
*/
441
bool C_File::ReadFromData ( char *data, long size )
442
{
443
	DeleteData ();
444
 
445
	m_lDataSize = size ;
446
	m_sData = new unsigned char[m_lDataSize];
447
 
448
	memcpy ( m_sData, data, size );
449
 
450
	return true;
451
}
452
 
453
 
58 cycrow 454
bool C_File::readFromFile(CFileIO &File)
52 cycrow 455
{
58 cycrow 456
	return readFromFile(File, File.fileSize(), false);
52 cycrow 457
}
58 cycrow 458
 
459
bool C_File::readFromFile(CFileIO &File, int iSize, bool bDoSize)
51 cycrow 460
{
58 cycrow 461
	if ( !File.isOpened() ) File.startRead();
462
	if ( !File.isOpened() ) return false;
463
 
61 cycrow 464
	m_lDataSize = iSize;
51 cycrow 465
	try {
466
		m_sData = new unsigned char[m_lDataSize];
467
	}
468
	catch(std::exception &e) {
227 cycrow 469
		CLog::logf(CLog::Log_IO, 2, L"C_File::readFromFile() unable to malloc, %d (%hs)", m_lDataSize, e.what());
51 cycrow 470
		return false;
471
	}
472
 
58 cycrow 473
	if ( bDoSize ) File.readSize();
51 cycrow 474
 
475
	try { 
58 cycrow 476
		File.read(m_sData, m_lDataSize); 
51 cycrow 477
	}
478
	catch(std::exception &e) {
227 cycrow 479
		CLog::logf(CLog::Log_IO, 2, L"C_File::readFromFile() unable to read from file, %d (%hs)", m_lDataSize, e.what());
51 cycrow 480
		DeleteData ();
481
		m_lDataSize = 0;
482
		return false;
483
	}
484
	return true;
485
}
486
 
43 cycrow 487
void C_File::copyData(const unsigned char *data, size_t size)
488
{
489
	m_lDataSize = (long)size;
490
	delete m_sData;
491
	m_sData = new unsigned char[size];
492
	memcpy(m_sData, data, size);
493
}
1 cycrow 494
 
43 cycrow 495
 
178 cycrow 496
/*
497
	Func:	filePointer
498
	Desc:	Returns the file pointer name
499
			Joins dir and name together
500
			Works for relative paths as well
501
*/
197 cycrow 502
Utils::WString C_File::filePointer() const
88 cycrow 503
{
197 cycrow 504
	Utils::WString fullfile = _sFullDir;
88 cycrow 505
	if ( !fullfile.empty() )
197 cycrow 506
		fullfile += L"/";
88 cycrow 507
 
130 cycrow 508
	if ( !_sName.empty() )
509
		fullfile += _sName;
88 cycrow 510
 
511
	return fullfile;
512
}
127 cycrow 513
 
514
bool C_File::isExternalFile() const
515
{
516
	if (!m_sData && !m_lDataSize)
517
	{
197 cycrow 518
		Utils::WString file = this->filePointer();
127 cycrow 519
		if (!file.empty() && CFileIO::Exists(file))
520
			return true;
521
	}
522
	return false;
523
}
524
 
1 cycrow 525
 
526
 
160 cycrow 527
void C_File::updateSignature()
1 cycrow 528
{
197 cycrow 529
	_sSignature = L"";
1 cycrow 530
 
531
	bool deleteData = false;
532
	if ( !m_sData )
533
	{
534
		if ( !ReadFromFile() )
535
			return;
536
		deleteData = true;
537
	}
538
 
539
	if ( CheckPCK() )
540
		UnPCKFile();
541
 
542
	m_bUpdatedSignature = true;
543
 
544
	if ( !m_sData )
545
		return;
546
 
547
	size_t fPos = m_lDataSize;
548
	if ( fPos > 700 )
549
		fPos = 700;
550
	unsigned char *data = m_sData + (m_lDataSize - fPos);
551
	data[fPos - 1] = '\0';
197 cycrow 552
	Utils::WString sData ((char *)data);
553
	int pos = sData.findPos(L"</codearray>", 0);
1 cycrow 554
	if ( pos != -1 )
555
	{
160 cycrow 556
		sData = sData.right(sData.length() - pos);
197 cycrow 557
		pos = sData.findPos(L"<signature>", 0);
558
		int endpos = sData.findPos(L"</signature>", 0);
1 cycrow 559
		if ( pos != -1 && endpos != -1 )
560
		{
160 cycrow 561
			_sSignature = sData.mid(pos + 12, endpos - (pos + 12) + 1);
562
			_sSignature = _sSignature.remove('\n').remove('\r');
1 cycrow 563
		}
564
	}
565
 
566
	if ( deleteData )
567
		DeleteData();
568
}
569
 
570
 
571
/*
572
	Func:	ReadFileSize()
573
	Return:	Returns the file size read
574
	Desc:	Opens the file and seeks to the end
575
*/
576
long C_File::ReadFileSize ()
577
{
129 cycrow 578
	CFileIO File(filePointer());
52 cycrow 579
	if ( File.exists() ) m_lSize = File.fileSize();
1 cycrow 580
 
581
	m_lUncomprDataSize = m_lSize;
582
 
583
	return m_lSize;
584
}
585
 
586
/*
587
	Func:	ReadLastModifed()
588
	Desc:	Reads the last modified time of the file and returns
589
			Uses seperate rountines for Windows and Linux
590
*/
591
time_t C_File::ReadLastModified ()
592
{
197 cycrow 593
	Utils::WString file = filePointer();
129 cycrow 594
	if ( file.empty() )
1 cycrow 595
		return m_tTime;
596
 
597
	#ifndef _WIN32
598
	struct stat attrib;			// create a file attribute structure
599
    stat ( file.c_str(), &attrib);
600
	m_tTime = attrib.st_mtime;
601
	#else
602
	#endif
603
 
604
	return m_tTime;
605
}
606
 
607
bool C_File::CheckValidFilePointer ()
608
{
129 cycrow 609
	return CFileIO::Exists(filePointer());
1 cycrow 610
}
611
 
612
bool C_File::ReadSignedFile()
613
{
614
	if ( (m_iFileType != FILETYPE_SCRIPT) && (m_iFileType != FILETYPE_UNINSTALL) )
615
		return false;
616
 
617
	// check file pointer
197 cycrow 618
	Utils::WString file = filePointer();
196 cycrow 619
	Utils::WString ext = CFileIO(file).extension();
620
	if ( !ext.Compare(L"xml") && !ext.Compare(L"pck") )
1 cycrow 621
		return false;
622
 
623
	if ( m_iDataCompression != SPKCOMPRESS_NONE )
624
		return m_bSigned;
625
 
626
	// check file extenstion
196 cycrow 627
	if ( (ext.Compare(L"pck")) || (CheckPCK()) )
1 cycrow 628
	{
629
		size_t size = 0;
630
		unsigned char *data = UnPCKFile ( &size );
53 cycrow 631
		if ( (data) && (size) ) {
632
			bool ret = ::ReadSignedFromData ( data, (long)size );
633
			//delete data;
634
			return ret;
635
		}
1 cycrow 636
	}
637
	else if ( (m_sData) && (m_iDataCompression == SPKCOMPRESS_NONE) )
638
		return ::ReadSignedFromData ( m_sData, m_lDataSize );
639
	else
640
	{
53 cycrow 641
		unsigned char pData[5001];
1 cycrow 642
 
53 cycrow 643
		CFileIO File(file);
644
		int iAmount = (File.fileSize() > 5000) ? 5000 : File.fileSize();
645
		if ( File.startRead() ) {
646
			File.seekStart(File.fileSize() - iAmount);
647
			if ( File.read(pData, iAmount, true) ) {
648
				return ::ReadSignedFromData(pData, iAmount);
1 cycrow 649
			}
650
		}
651
	}
652
 
653
	return false;
654
}
655
 
656
int C_File::ReadScriptVersion ()
657
{
54 cycrow 658
	if ( (m_iFileType != FILETYPE_SCRIPT) && (m_iFileType != FILETYPE_UNINSTALL) ) return 0;
1 cycrow 659
 
54 cycrow 660
	if ( (m_sData) && (m_iDataCompression == SPKCOMPRESS_NONE) )
1 cycrow 661
		m_iVersion = ::ReadScriptVersionFromData ( m_sData, m_lDataSize );
54 cycrow 662
	else {
129 cycrow 663
		CFileIO File(filePointer());
54 cycrow 664
		if ( File.startRead() ) {
665
			int iRead = (File.fileSize() > 5000) ? 5000 : File.fileSize();
666
			unsigned char *data = File.read(iRead);
667
			if ( data ) {
668
				m_iVersion = ::ReadScriptVersionFromData(data, iRead);
669
				delete []data;
1 cycrow 670
			}
671
		}
672
	}
673
 
674
	return m_iVersion;
675
}
676
 
677
bool C_File::MatchFile ( C_File *file )
678
{
679
	if ( file->GetFileType() != m_iFileType )
680
		return false;
681
 
131 cycrow 682
	if ( file->dir() != _sDir )
1 cycrow 683
		return false;
684
 
130 cycrow 685
	if ( file->name() != _sName )
125 cycrow 686
	{
687
		// check if the base name matches, but only for certain file extensions
688
		if (file->shouldCheckBaseName())
689
		{
196 cycrow 690
			Utils::WString baseName = CFileIO(file->name()).dir() + L"/" + CFileIO(file->name()).baseName();
691
			Utils::WString compareBaseName = CFileIO(_sName).dir() + L"/" + CFileIO(_sName).baseName();
125 cycrow 692
			if (baseName.Compare(compareBaseName))
693
				return true;
694
		}
695
		return false;
116 cycrow 696
	}
1 cycrow 697
 
698
	return true;
699
}
700
 
701
/*
702
########################################################################################################################
703
####################################              Compression Functions             ####################################
704
########################################################################################################################
705
*/
706
 
707
bool C_File::CompressFile ( CProgressInfo *progress )
708
{
197 cycrow 709
	Utils::WString file = this->filePointer();
710
	if ( !CFileIO(file).exists() )
1 cycrow 711
	{
213 cycrow 712
		if ( !this->writeToFile(L"tempuncompr.dat", m_sData, m_lDataSize) )
1 cycrow 713
			return false;
213 cycrow 714
		file = L"tempuncompr.dat";
1 cycrow 715
	}
716
 
717
	bool ret = false;
718
 
211 cycrow 719
#pragma warning(disable:4244)
285 cycrow 720
	FILE *fIn = fopen(file.toFileUTF8().c_str(), "rb");
211 cycrow 721
#pragma warning(default:4244)
1 cycrow 722
	if ( fIn )
723
	{
724
		FILE *fOut = fopen("tempcompr.dat", "wb");
725
		if ( fOut )
726
		{
727
			int err;
728
			if ( progress )
729
				err = zlib_def(fIn, fOut, progress->GetDonePointer());
730
			else
731
				err = zlib_def(fIn, fOut, 0);
732
 
733
			fclose(fOut);
734
			if ( err == Z_OK )
735
			{
736
				DeleteData ();
737
 
197 cycrow 738
				CFileIO File(L"tempcompr.dat");
54 cycrow 739
				File.setAutoDelete(true);
740
				if ( File.startRead() ) {
741
					m_sData = File.readAll((size_t *)&m_lDataSize);
742
					if ( !m_sData ) {
743
						m_iLastError = SPKERR_FILEREAD;
744
						m_lDataSize = 0;
1 cycrow 745
					}
54 cycrow 746
					else {
747
						m_iLastError = SPKERR_NONE;
748
						m_iDataCompression = SPKCOMPRESS_ZLIB;
749
						ret = true;
750
					}
1 cycrow 751
				}
54 cycrow 752
				File.close();
1 cycrow 753
			}
754
		}
755
		fclose(fIn);
756
	}
757
 
197 cycrow 758
	CFileIO::Remove(L"tempuncompr.dat");
1 cycrow 759
 
760
	return ret;
761
}
762
 
763
bool C_File::ChangeCompression ( int compressionType, CProgressInfo *progress )
764
{
765
	// no data to try to compress
766
	if ( (!m_sData) || (!m_lDataSize) )
767
		return false;
768
 
769
	// laready compressed to correct type
770
	if ( compressionType == m_iDataCompression )
771
		return true;
772
 
773
	// otherwise, lets recompress the file
774
	// first we uncompress the data
775
	if ( !this->UncompressData(progress) )
776
		return false;
777
 
778
	// next we compress to new type
779
	if ( !this->CompressData(compressionType, progress) )
780
		return false;
781
	return true;
782
}
783
 
308 cycrow 784
unsigned char* C_File::CompressToData(int compressionType, size_t* outSize, CProgressInfo* progress, int level)
1 cycrow 785
{
308 cycrow 786
	if (outSize) *outSize = 0;
787
	size_t initialLen = m_lDataSize;
788
	if (initialLen < 100) initialLen = 200;
789
	else if (initialLen < 1000) initialLen *= 2;
790
	initialLen += 1000;
1 cycrow 791
 
308 cycrow 792
	switch (compressionType)
1 cycrow 793
	{
308 cycrow 794
	case SPKCOMPRESS_ZLIB:
795
	{
796
		unsigned long comprLen = static_cast<unsigned long>(initialLen);
797
		unsigned char* compr = (unsigned char*)calloc(comprLen, 1);
798
		if (!compr) return NULL;
799
 
800
		int err = Z_NOTENOUGH_BUF;
801
		while (err == Z_NOTENOUGH_BUF)
802
		{
803
			err = compress2(compr, &comprLen, (const unsigned char*)m_sData, m_lDataSize,
804
				(progress) ? progress->GetDonePointer() : 0, level);
805
			if (err == Z_NOTENOUGH_BUF)
1 cycrow 806
			{
308 cycrow 807
				unsigned long newLen = comprLen + (CHUNK * 2);
808
				unsigned char* newCompr = (unsigned char*)realloc(compr, newLen);
809
				if (!newCompr) { free(compr); return NULL; }
810
				compr = newCompr;
811
				comprLen = newLen;
812
			}
813
		}
1 cycrow 814
 
308 cycrow 815
		if (err == Z_OK && comprLen > 0)
816
		{
817
			unsigned char* retData = new (std::nothrow) unsigned char[comprLen];
818
			if (!retData) { free(compr); return NULL; }
819
			memcpy(retData, compr, comprLen);
820
			free(compr);
821
			if (outSize) *outSize = static_cast<size_t>(comprLen);
822
			return retData;
823
		}
1 cycrow 824
 
308 cycrow 825
		free(compr);
826
		return NULL;
827
	}
828
	break;
1 cycrow 829
 
308 cycrow 830
	case SPKCOMPRESS_LZMA:
831
	{
832
		size_t comprLen = initialLen;
833
		unsigned char* compr = new (std::nothrow) unsigned char[comprLen];
834
		if (!compr) return NULL;
1 cycrow 835
 
308 cycrow 836
		SRes res = Lzma86_Encode((Byte*)compr, (size_t*)&comprLen, (const Byte*)m_sData, (size_t)m_lDataSize,
837
			level, LZMA_DICT, SZ_FILTER_NO, (progress) ? progress->GetDonePointer() : NULL);
1 cycrow 838
 
308 cycrow 839
		if (res == SZ_OK && comprLen > 0)
840
		{
841
			unsigned char* retData = new (std::nothrow) unsigned char[comprLen];
842
			if (!retData) { delete[] compr; return NULL; }
843
			memcpy(retData, compr, comprLen);
844
			delete[] compr;
845
			if (outSize) *outSize = comprLen;
846
			return retData;
847
		}
848
 
849
		delete[] compr;
850
		return NULL;
1 cycrow 851
	}
308 cycrow 852
	break;
853
	}
1 cycrow 854
 
855
	return NULL;
856
}
857
 
858
bool C_File::CompressData ( int compressionType, CProgressInfo *progress, int level )
859
{
860
	// no data to try to compress
861
	if ( (!m_sData) || (!m_lDataSize) )
862
		return false;
863
 
864
	// if comopression is set to noe, dont bother
283 cycrow 865
	if (compressionType == SPKCOMPRESS_NONE)
1 cycrow 866
		return true;
867
 
868
	if ( compressionType == SPKCOMPRESS_7ZIP )
869
		compressionType = SPKCOMPRESS_LZMA;
870
 
871
	// if its zlib, and we are trying to compress pcked files (ie already zlib compression) then switch to lzma instead
197 cycrow 872
	if ( compressionType == SPKCOMPRESS_ZLIB && (this->checkFileExt(L"pck") || this->checkFileExt(L"cat") || this->checkFileExt(L"dat") || this->checkFileExt(L"pbb") || this->checkFileExt(L"pbd")) )
1 cycrow 873
		compressionType = SPKCOMPRESS_LZMA;
874
 
283 cycrow 875
	// dont compress cat/dat files
876
	if (this->checkFileExt(L"cat") || this->checkFileExt(L"dat"))
877
		compressionType = SPKCOMPRESS_NONE;
878
 
1 cycrow 879
	// if its already compressed, no need to compress again
880
	if ( compressionType == m_iDataCompression )
881
		return true;
882
 
883
	// no need to change the compression
884
	if ( m_iDataCompression != SPKCOMPRESS_NONE )
885
		return true;
886
 
887
	m_lUncomprDataSize = m_lDataSize;
888
 
308 cycrow 889
	size_t comprLen = static_cast<size_t>(m_lDataSize);
1 cycrow 890
	if ( comprLen < 100 )
891
		comprLen = 200;
892
	else if ( comprLen < 1000 )
893
		comprLen *= 2;
894
	comprLen += 1000;
895
 
896
	// > 500mb (do file compression
897
	if ( comprLen > 500000000 )
898
		return this->CompressFile(progress);
899
 
900
	// best compression, attempt to compress the file multiple times until we get the best one
901
	if ( compressionType == SPKCOMPRESS_BEST )
902
	{
903
		int compress[] = { SPKCOMPRESS_ZLIB, SPKCOMPRESS_LZMA };
904
		int bestCompress = -1;
308 cycrow 905
		size_t bestSize = 0;
1 cycrow 906
		unsigned char *bestCompr = NULL;
907
		for ( int i = 0; i < 2; i++ )
908
		{
308 cycrow 909
			size_t checkSize = 0;
1 cycrow 910
			unsigned char *compr = this->CompressToData(compress[i], &checkSize, progress, level);
911
			if ( compr )
912
			{
913
				if ( checkSize < bestSize || bestCompress == -1 )
914
				{
915
					if ( bestCompr )
916
						delete bestCompr;
917
					bestCompr = compr;
918
					bestCompress = compress[i];
919
					bestSize = checkSize;
920
				}
921
				// not the best, no need to keep it
922
				else
923
					delete compr;
924
			}
925
		}
926
 
927
		if ( bestCompress != -1 && bestCompr )
928
		{
929
			DeleteData ();
930
			m_sData = bestCompr;
931
			m_bUsedMalloc = false;
932
			m_lDataSize = bestSize;
933
			m_iDataCompression = bestCompress;
934
			return true;
935
		}
936
 
937
		if ( bestCompr )
938
			delete bestCompr;
939
	}
940
 
941
	if ( compressionType == SPKCOMPRESS_ZLIB || compressionType == SPKCOMPRESS_LZMA )
942
	{
943
		unsigned char *compr = this->CompressToData(compressionType, &comprLen, progress, level);
944
		if ( compr )
945
		{
946
			DeleteData ();
947
			m_sData = compr;
948
			m_bUsedMalloc = false;
949
			m_lDataSize = comprLen;
950
			m_iDataCompression = compressionType;
951
		}
952
		// we shall always return true, files can be added in non compressed mode
283 cycrow 953
		//TODO: file compression?
1 cycrow 954
		return true;
955
	}
956
 
957
	return false;
958
}
959
 
960
bool C_File::UncompressData ( CProgressInfo *progress )
961
{
962
	// no data to try to uncompress
45 cycrow 963
	if ( (!m_sData) || (!m_lDataSize) ) {
964
		return (m_lSize) ? false : true;
965
	}
1 cycrow 966
 
967
	if ( m_bCompressedToFile )
968
		return false;
969
 
970
	// if comopression is set to none, dont bother
971
	if ( m_iDataCompression == SPKCOMPRESS_NONE )
972
		return true;
973
 
974
	if ( m_iDataCompression == SPKCOMPRESS_ZLIB )
975
	{
976
		unsigned long uncomprLen = m_lUncomprDataSize;
977
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
978
		int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );
979
		if ( err == Z_OK )
980
		{
981
			DeleteData ();
982
			m_iDataCompression = SPKCOMPRESS_NONE;
983
			m_lDataSize = uncomprLen;
984
			m_sData = uncompr;
985
			return true;
986
		}
987
 
988
		if ( uncompr )
989
			delete [] uncompr;
990
	}
991
	else if ( m_iDataCompression == SPKCOMPRESS_LZMA )
992
	{
993
		size_t uncomprLen = m_lUncomprDataSize;
994
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
995
		SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);
996
		if ( res == SZ_OK )
997
		{
998
			DeleteData ();
999
			m_iDataCompression = SPKCOMPRESS_NONE;
1000
			m_lDataSize = (long)uncomprLen;
1001
			m_sData = new unsigned char[m_lDataSize];
1002
			memcpy(m_sData, uncompr, m_lDataSize);
1003
			delete uncompr;
1004
			return true;
1005
		}
1006
 
1007
		if ( uncompr )
1008
			delete [] uncompr;
1009
	}
1010
	else if ( m_iDataCompression == SPKCOMPRESS_7ZIP )
1011
	{
1012
		long len = m_lUncomprDataSize;
1013
		unsigned char *compr = LZMADecode_C ( (unsigned char *)m_sData, m_lDataSize, (size_t*)&len, NULL );
1014
		if ( compr )
1015
		{
1016
			DeleteData ();
1017
			m_sData = compr;
1018
			m_lDataSize = len;
1019
			m_iDataCompression = SPKCOMPRESS_NONE;
1020
			return true;
1021
		}
1022
	}
1023
 
1024
	return false;
1025
}
1026
 
1027
unsigned char *C_File::UncompressData ( long *size, CProgressInfo *progress )
1028
{
1029
	// no data to try to uncompress
1030
	if ( (!m_sData) || (!m_lDataSize) )
1031
		return NULL;
1032
 
1033
	//if ( m_bCompressedToFile )
1034
	//	return NULL;
1035
 
1036
	// if comopression is set to none, dont bother
1037
	if ( m_iDataCompression == SPKCOMPRESS_NONE )
1038
	{
1039
		*size = m_lDataSize;
143 cycrow 1040
		unsigned char *uncompr = new unsigned char[m_lDataSize];
1041
		memcpy(uncompr, m_sData, m_lDataSize);
1042
		return uncompr;
1 cycrow 1043
	}
1044
 
1045
	if ( m_iDataCompression == SPKCOMPRESS_ZLIB )
1046
	{
1047
		unsigned long uncomprLen = m_lUncomprDataSize;
1048
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1049
		int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );
1050
		if ( err == Z_OK )
1051
		{
1052
			*size = uncomprLen;
1053
			return uncompr;
1054
		}
1055
		if ( uncompr )
1056
			delete [] uncompr;
1057
	}
1058
	if ( m_iDataCompression == SPKCOMPRESS_7ZIP )
1059
	{
1060
		long len = m_lUncomprDataSize;
1061
		unsigned char *compr = LZMADecode_C ( m_sData, m_lDataSize, (size_t *)&len, NULL );
1062
		if ( compr )
1063
		{
1064
			*size = len;
1065
			return compr;
1066
		}
1067
		if ( compr )
1068
			delete [] compr;
1069
	}
1070
	else if ( m_iDataCompression == SPKCOMPRESS_LZMA )
1071
	{
1072
		size_t uncomprLen = m_lUncomprDataSize;
1073
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1074
		SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);
1075
		if ( res == SZ_OK )
1076
		{
1077
			*size = (long)uncomprLen;
1078
			return uncompr;
1079
		}
1080
		if ( uncompr )
1081
			delete [] uncompr;
1082
	}
1083
 
1084
	return NULL;
1085
}
1086
 
197 cycrow 1087
bool C_File::uncompressToFile(const Utils::WString &toFile, CBaseFile *spkfile, bool includedir, CProgressInfo *progress)
1 cycrow 1088
{
1089
#ifdef _INCLUDE7ZIP
1090
	if ( (!m_sData) || (!m_lDataSize) )
1091
		return false;
1092
	// if theres a tmp file, open it and check it still exists
178 cycrow 1093
	if ( !m_sTmpFile.empty() )
1 cycrow 1094
	{
56 cycrow 1095
		if ( CFileIO::Exists(m_sTmpFile) ) return true;
1 cycrow 1096
		m_sTmpFile = "";
1097
	}
1098
 
1099
	// now uncompress to the file
178 cycrow 1100
	Utils::String file = toFile;
1101
	if (file.empty())
1 cycrow 1102
	{
1103
		m_iTempNum++;
178 cycrow 1104
		file = "uncompr" + (long)m_iTempNum + ".tmp";
1 cycrow 1105
	}
1106
	else
178 cycrow 1107
		file = _getFullFileToDir(file, includedir, spkfile);
1 cycrow 1108
 
56 cycrow 1109
	CFileIO File("compr.tmp");
1110
	if ( !File.startWrite() ) return false;
1111
	if ( !File.write(m_sData, m_lDataSize) ) return false;
1112
	File.close();
1113
	if ( LZMADecodeFile ( "compr.tmp", file.c_str(), (CProgressInfo7Zip *)progress ) )
1 cycrow 1114
	{
56 cycrow 1115
		ret = true;
178 cycrow 1116
		if ( toFile.empty() )
56 cycrow 1117
			m_sTmpFile = file;
1 cycrow 1118
	}
1119
 
56 cycrow 1120
	CFileIO::Remove("compr.tmp");
1 cycrow 1121
 
1122
	return ret;
1123
#else
1124
	return false;
1125
#endif
1126
}
1127
 
1128
 
129 cycrow 1129
bool C_File::writeFilePointer(unsigned char *cData, long len)
1 cycrow 1130
{
129 cycrow 1131
	return writeToFile(filePointer(), cData, len);
1 cycrow 1132
}
197 cycrow 1133
bool C_File::writeToFile(const Utils::WString &filename, unsigned char *cData, long len)
1 cycrow 1134
{
1135
	unsigned char *data = cData;
54 cycrow 1136
	if ( (!len) || (!data) ) {
1 cycrow 1137
		len = m_lDataSize;
1138
		data = m_sData;
1139
	}
1140
 
45 cycrow 1141
	if ( (!len) || (!data) ) {
1142
		if ( m_lSize ) return false;
1143
	}
1 cycrow 1144
 
54 cycrow 1145
	bool ret = false;
1146
 
1 cycrow 1147
	// check for cat file
197 cycrow 1148
	if ( filename.contains(L"::")) {
1149
		Utils::WString catfile = filename.token(L"::", 1);
1150
		Utils::WString file = filename.token(L"::", 2);
1 cycrow 1151
 
1152
		CCatFile newcat;
201 cycrow 1153
		return newcat.addData(catfile, data, len, file, true, true);
1 cycrow 1154
	}
54 cycrow 1155
	else {
197 cycrow 1156
		Utils::WString filen = filename.findReplace(L"/", L"\\");
1157
		filen = filen.findReplace(L"\\\\", L"\\");
1 cycrow 1158
 
45 cycrow 1159
		if ( len && data ) {
54 cycrow 1160
			CFileIO File(filen);
1161
			if ( File.startWrite() ) ret = File.write(data, len);
45 cycrow 1162
		}
1 cycrow 1163
	}
1164
 
54 cycrow 1165
	return ret;
1 cycrow 1166
}
1167
 
197 cycrow 1168
bool C_File::writeToDir(const Utils::WString &dir, CBaseFile *spkfile, bool includedir, const Utils::WString &appendDir, unsigned char *data, long len)
1 cycrow 1169
{
197 cycrow 1170
	Utils::WString fullfile = _getFullFileToDir(dir, includedir, spkfile);
1 cycrow 1171
 
129 cycrow 1172
	if (!appendDir.empty())
1 cycrow 1173
	{
129 cycrow 1174
		if (!fullfile.empty())
197 cycrow 1175
			fullfile += L"/";
1 cycrow 1176
		fullfile += appendDir;
1177
	}
1178
 
197 cycrow 1179
	Utils::WString fulldir = fullfile.tokens(L"/", 1, -2);
129 cycrow 1180
	if (!fulldir.empty())
1 cycrow 1181
	{
160 cycrow 1182
		if (!CDirIO(fulldir).create())
1 cycrow 1183
			return false;
1184
	}
1185
 
129 cycrow 1186
	return writeToFile(fullfile, data, len);
1 cycrow 1187
}
1188
 
197 cycrow 1189
Utils::WString C_File::dataSizeString() const
1 cycrow 1190
{
134 cycrow 1191
	return SPK::GetSizeString(m_lDataSize);
1 cycrow 1192
}
197 cycrow 1193
Utils::WString C_File::uncompressedSizeString() const
1 cycrow 1194
{
178 cycrow 1195
	return SPK::GetSizeString(uncompressedDataSize());
1 cycrow 1196
}
1197
 
197 cycrow 1198
Utils::WString C_File::creationTimeString() const
1 cycrow 1199
{
1200
	if ( !m_tTime )
201 cycrow 1201
		return Utils::WString::Null();
1 cycrow 1202
 
1203
	struct tm   *currDate;
1204
	char    dateString[100];
1205
 
1206
	time_t n = m_tTime;
1207
 
1208
	currDate = localtime(&n);
1209
 
1210
	strftime(dateString, sizeof dateString, "(%d/%m/%Y) %H:%M", currDate);
1211
 
197 cycrow 1212
	return Utils::WString(dateString);
1 cycrow 1213
}
1214
 
1215
bool C_File::CompareNew ( C_File *file )
1216
{
1217
	if ( !m_iVersion )
1218
		ReadScriptVersion ();
1219
 
1220
	// if version, check if its later version
1221
	if ( (m_iVersion) && (file->GetVersion()) )
1222
	{
1223
		if ( m_iVersion > file->GetVersion() )
1224
			return false;
1225
	}
1226
 
1227
	// now check for last modified time
1228
	if ( (m_tTime) && (file->GetLastModified()) )
1229
	{
1230
		if ( m_tTime > file->GetLastModified() )
1231
			return false;
1232
	}
1233
 
1234
	// assume same or newer
1235
	return true;
1236
}
1237
 
197 cycrow 1238
Utils::WString GetFileTypeString(int type)
1 cycrow 1239
{
1240
	switch ( type )
1241
	{
1242
		case FILETYPE_SCRIPT:
197 cycrow 1243
			return L"Script";
1 cycrow 1244
		case FILETYPE_TEXT:
197 cycrow 1245
			return L"Text";
1 cycrow 1246
		case FILETYPE_README:
197 cycrow 1247
			return L"Readme";
1 cycrow 1248
		case FILETYPE_MAP:
197 cycrow 1249
			return L"Map";
1 cycrow 1250
		case FILETYPE_MOD:
197 cycrow 1251
			return L"Mod";
1 cycrow 1252
		case FILETYPE_UNINSTALL:
197 cycrow 1253
			return L"Uninstall";
1 cycrow 1254
		case FILETYPE_SOUND:
197 cycrow 1255
			return L"Sound";
1 cycrow 1256
		case FILETYPE_EXTRA:
197 cycrow 1257
			return L"Extra";
1 cycrow 1258
		case FILETYPE_SCREEN:
197 cycrow 1259
			return L"Screen";
1 cycrow 1260
		case FILETYPE_ADVERT:
197 cycrow 1261
			return L"Advert";
1 cycrow 1262
		case FILETYPE_MISSION:
197 cycrow 1263
			return L"Mission";
1 cycrow 1264
		case FILETYPE_BACKUP:
197 cycrow 1265
			return L"Backup";
1 cycrow 1266
		case FILETYPE_SHIPOTHER:
197 cycrow 1267
			return L"ShipOther";
1 cycrow 1268
		case FILETYPE_SHIPMODEL:
197 cycrow 1269
			return L"ShipModel";
1 cycrow 1270
		case FILETYPE_SHIPSCENE:
197 cycrow 1271
			return L"ShipScene";
1 cycrow 1272
		case FILETYPE_COCKPITSCENE:
197 cycrow 1273
			return L"CockpitScene";
1 cycrow 1274
	}
1275
 
197 cycrow 1276
	return Utils::WString::Null();
1 cycrow 1277
}
1278
 
197 cycrow 1279
FileType GetFileTypeFromString(const Utils::WString &type)
1 cycrow 1280
{
197 cycrow 1281
	Utils::WString ltype = type.lower();
1282
	if ( ltype == L"script" || ltype == L"scriptpck")
1 cycrow 1283
		return FILETYPE_SCRIPT;
197 cycrow 1284
	else if ( ltype == L"text" )
1 cycrow 1285
		return FILETYPE_TEXT;
197 cycrow 1286
	else if ( ltype == L"readme" )
1 cycrow 1287
		return FILETYPE_README;
197 cycrow 1288
	else if ( ltype == L"map" )
1 cycrow 1289
		return FILETYPE_MAP;
197 cycrow 1290
	else if ( ltype == L"mod" )
1 cycrow 1291
		return FILETYPE_MOD;
197 cycrow 1292
	else if ( ltype == L"uninstall" )
1 cycrow 1293
		return FILETYPE_UNINSTALL;
197 cycrow 1294
	else if ( ltype == L"sound" )
1 cycrow 1295
		return FILETYPE_SOUND;
197 cycrow 1296
	else if ( ltype == L"extra" )
1 cycrow 1297
		return FILETYPE_EXTRA;
197 cycrow 1298
	else if ( ltype == L"screen" )
1 cycrow 1299
		return FILETYPE_SCREEN;
197 cycrow 1300
	else if ( ltype == L"advert" )
1 cycrow 1301
		return FILETYPE_ADVERT;
197 cycrow 1302
	else if ( ltype == L"mission" )
1 cycrow 1303
		return FILETYPE_MISSION;
197 cycrow 1304
	else if ( ltype == L"backup" )
1 cycrow 1305
		return FILETYPE_BACKUP;
197 cycrow 1306
	else if ( ltype == L"shipother" )
1 cycrow 1307
		return FILETYPE_SHIPOTHER;
197 cycrow 1308
	else if ( ltype == L"shipmodel" )
1 cycrow 1309
		return FILETYPE_SHIPMODEL;
197 cycrow 1310
	else if ( ltype == L"shipscene" )
1 cycrow 1311
		return FILETYPE_SHIPSCENE;
197 cycrow 1312
	else if ( ltype == L"cockpitscene" )
1 cycrow 1313
		return FILETYPE_COCKPITSCENE;
1314
 
127 cycrow 1315
	return FILETYPE_UNKNOWN;
1 cycrow 1316
}
1317
 
1318
 
200 cycrow 1319
Utils::WString FormatErrorString(int error, const Utils::WString &rest)
1 cycrow 1320
{
200 cycrow 1321
	std::vector<Utils::WString> args;
1 cycrow 1322
 
200 cycrow 1323
	if (!rest.empty())
1324
		rest.tokenise(L"~", args);
1 cycrow 1325
 
200 cycrow 1326
	Utils::WString errorStr;
1 cycrow 1327
	switch ( error )
1328
	{
1329
		case SPKINSTALL_CREATEDIRECTORY:
200 cycrow 1330
			errorStr = L"Creating Directory: %1";
1 cycrow 1331
			break;
1332
		case SPKINSTALL_CREATEDIRECTORY_FAIL:
200 cycrow 1333
			errorStr = L"Unable to Creating Directory: %1";
1 cycrow 1334
			break;
1335
		case SPKINSTALL_WRITEFILE:
200 cycrow 1336
			errorStr = L"Writing File: %1";
1 cycrow 1337
			break;
1338
		case SPKINSTALL_WRITEFILE_FAIL:
200 cycrow 1339
			errorStr = L"Unable to Write File: %1";
1 cycrow 1340
			break;
1341
		case SPKINSTALL_DELETEFILE:
200 cycrow 1342
			errorStr = L"Deleting File: %1";
1 cycrow 1343
			break;
1344
		case SPKINSTALL_DELETEFILE_FAIL:
200 cycrow 1345
			errorStr = L"Unable to delete File: %1";
1 cycrow 1346
			break;
1347
		case SPKINSTALL_REMOVEDIR:
200 cycrow 1348
			errorStr = L"Removing Directory: %1";
1 cycrow 1349
			break;
1350
		case SPKINSTALL_SKIPFILE:
200 cycrow 1351
			errorStr = L"Skipping File (older): %1";
1 cycrow 1352
			break;
1353
		case SPKINSTALL_ENABLEFILE:
200 cycrow 1354
			errorStr = L"Enabled File: %1";
1 cycrow 1355
			break;
1356
		case SPKINSTALL_DISABLEFILE:
200 cycrow 1357
			errorStr = L"Disabled File: %1";
1 cycrow 1358
			break;
1359
		case SPKINSTALL_ENABLEFILE_FAIL:
200 cycrow 1360
			errorStr = L"Failed to enable File: %1";
1 cycrow 1361
			break;
1362
		case SPKINSTALL_DISABLEFILE_FAIL:
200 cycrow 1363
			errorStr = L"Failed to disable File: %1";
1 cycrow 1364
			break;
1365
		case SPKINSTALL_UNINSTALL_MOVE:
200 cycrow 1366
			errorStr = L"Moving uninstall file: %1";
1 cycrow 1367
			break;
1368
		case SPKINSTALL_UNINSTALL_MOVE_FAIL:
200 cycrow 1369
			errorStr = L"Unable to Move uninstall file: %1";
1 cycrow 1370
			break;
1371
		case SPKINSTALL_UNINSTALL_COPY:
200 cycrow 1372
			errorStr = L"Coping uninstall file: %1";
1 cycrow 1373
			break;
1374
		case SPKINSTALL_UNINSTALL_COPY_FAIL:
200 cycrow 1375
			errorStr = L"Unable to Copy uninstall file: %1";
1 cycrow 1376
			break;
1377
		case SPKINSTALL_UNINSTALL_REMOVE:
200 cycrow 1378
			errorStr = L"Removing Uninstall file: %1";
1 cycrow 1379
			break;
1380
		case SPKINSTALL_UNINSTALL_REMOVE_FAIL:
200 cycrow 1381
			errorStr = L"Unable to remove Uninstall file: %1";
1 cycrow 1382
			break;
1383
		case SPKINSTALL_SHARED:
200 cycrow 1384
			errorStr = L"Removing Unused Shared file: %1";
1 cycrow 1385
			break;
1386
		case SPKINSTALL_SHARED_FAIL:
200 cycrow 1387
			errorStr = L"Unable to remove Unused Shared file: %1";
1 cycrow 1388
			break;
1389
		case SPKINSTALL_ORIGINAL_BACKUP:
200 cycrow 1390
			errorStr = L"Backing up original file: %1";
1 cycrow 1391
			break;
1392
		case SPKINSTALL_ORIGINAL_BACKUP_FAIL:
200 cycrow 1393
			errorStr = L"Unable to back up original file: %1";
1 cycrow 1394
			break;
1395
		case SPKINSTALL_ORIGINAL_RESTORE:
200 cycrow 1396
			errorStr = L"Restoring original file: %1";
1 cycrow 1397
			break;
1398
		case SPKINSTALL_ORIGINAL_RESTORE_FAIL:
200 cycrow 1399
			errorStr = L"Unable to restore original file: %1";
1 cycrow 1400
			break;
1401
		case SPKINSTALL_FAKEPATCH:
200 cycrow 1402
			errorStr = L"Shifted fake patch: %1 to %2";
1 cycrow 1403
			break;
1404
		case SPKINSTALL_FAKEPATCH_FAIL:
200 cycrow 1405
			errorStr = L"Unable to shift fake patch: %1 to %2";
1 cycrow 1406
			break;
1407
		case SPKINSTALL_AUTOTEXT:
200 cycrow 1408
			errorStr = L"Shifted text file: %1 to %2";
1 cycrow 1409
			break;
1410
		case SPKINSTALL_AUTOTEXT_FAIL:
200 cycrow 1411
			errorStr = L"Unable to shift text file: %1 to %2";
1 cycrow 1412
			break;
1413
		case SPKINSTALL_MISSINGFILE:
200 cycrow 1414
			errorStr = L"File is missing: %1";
1 cycrow 1415
			break;
1416
		case SPKINSTALL_ORPHANED:
200 cycrow 1417
			errorStr = L"Orphaned File removed: %1";
1 cycrow 1418
			break;
1419
		case SPKINSTALL_ORPHANED_FAIL:
200 cycrow 1420
			errorStr = L"Unable to remove Orphaned File: %1";
1 cycrow 1421
			break;
1422
	}
1423
 
200 cycrow 1424
	Utils::WString ret = errorStr.args(args);
1 cycrow 1425
	return ret;
1426
}
1427
 
1428
 
1429
bool C_File::CheckPCK ()
1430
{
1431
	if ( (m_sData) && (m_lDataSize) && (m_iDataCompression == SPKCOMPRESS_NONE) )
1432
		return IsDataPCK ( m_sData, m_lDataSize );
1433
 
197 cycrow 1434
	Utils::WString filename = filePointer();
54 cycrow 1435
	if ( !filename.empty() ) {
1436
		CFileIO File(filename);
1437
		if ( File.startRead() ) {
1438
			unsigned char data[4];
1439
			if ( File.read(data, 3) ) return IsDataPCK ( data, 3 );
1 cycrow 1440
		}
1441
	}
1442
 
197 cycrow 1443
	if (checkFileExt(L"pck") || checkFileExt(L"pbb") || checkFileExt(L"pbd")) return true;
1 cycrow 1444
	return false;
1445
}
1446
 
1447
bool C_File::PCKFile()
1448
{
1449
	if ( !m_lDataSize || !m_sData )
1450
	{
1451
		if ( !this->ReadFromFile() )
1452
			return false;
1453
	}
1454
 
1455
	if ( m_lDataSize && m_sData )
1456
	{
1457
		if ( !this->UncompressData() )
1458
			return false;
1459
 
1460
		size_t size;
40 cycrow 1461
		unsigned char *data = PCKData(m_sData, m_lDataSize, &size, false);
1 cycrow 1462
		if ( data && size )
1463
		{
40 cycrow 1464
			m_lUncomprDataSize = m_lDataSize;
1 cycrow 1465
			this->DeleteData();
1466
			m_bUsedMalloc = false;
1467
			m_lDataSize = (long)size;
1468
			m_sData = new unsigned char[size];
1469
			memcpy(m_sData, data, size);
1470
			delete [] data;
1471
		}
1472
 
1473
		return true;
1474
	}
1475
 
1476
	return false;
1477
}
1478
 
1479
unsigned char *C_File::UnPCKFile ( size_t *len )
1480
{
1481
	unsigned char *data = NULL;
1482
	size_t datasize = 0;
1483
 
1484
	if ( CheckValidFilePointer() )
1485
	{
129 cycrow 1486
		CFileIO File(filePointer());
54 cycrow 1487
		if ( File.startRead() ) data = File.readAll(&datasize);
1 cycrow 1488
	}
1489
 
1490
	if ( !data )
1491
	{
1492
		if ( !m_lDataSize )
1493
		{
1494
			if ( !this->ReadFromFile() )
1495
				return NULL;
1496
		}
1497
		datasize = m_lDataSize;
1498
		data = new unsigned char[datasize];
1499
		memcpy ( data, m_sData, datasize );
1500
	}
1501
 
1502
	if ( data )
1503
	{
1504
		unsigned char *newdata = UnPCKData ( data, datasize, len, CheckPCK() );
308 cycrow 1505
		delete[] data;
1 cycrow 1506
		return newdata;
1507
	}
1508
 
1509
	return NULL;
1510
}
1511
 
1512
bool C_File::UnPCKFile()
1513
{
1514
	if ( !m_lDataSize || !m_sData )
1515
	{
1516
		if ( !this->ReadFromFile() )
1517
			return false;
1518
	}
1519
	if ( m_lDataSize && m_sData )
1520
	{
1521
		if ( !this->UncompressData() )
1522
			return false;
1523
 
1524
		size_t size;
1525
		unsigned char *data = UnPCKData(m_sData, m_lDataSize, &size, CheckPCK());
1526
		if ( data && size )
1527
		{
1528
			this->DeleteData();
1529
			m_lUncomprDataSize = m_lDataSize;
1530
			m_bUsedMalloc = false;
1531
			m_sData = new unsigned char[size];
1532
			memcpy(m_sData, data, size);
1533
			m_lDataSize = (long)size;
1534
			delete []data;
58 cycrow 1535
			return true;
1 cycrow 1536
		}
1537
	}
1538
 
1539
	return false;
1540
}
1541
 
213 cycrow 1542
unsigned char *UnPCKFile (const Utils::WString &file, size_t *len, bool nocrypt )
1 cycrow 1543
{
54 cycrow 1544
	CFileIO File(file);
1545
	if ( !File.startRead() ) return NULL;
1 cycrow 1546
 
54 cycrow 1547
	size_t size;
1548
	unsigned char *data = File.readAll(&size);
1 cycrow 1549
 
54 cycrow 1550
	if ( data ) {
1 cycrow 1551
		unsigned char *unData = UnPCKData ( data, size, len, nocrypt );
1552
		delete data;
1553
		return unData;
1554
	}
1555
 
1556
	return NULL;
1557
}
1558
 
1559
unsigned char *UnPCKData ( unsigned char *data, size_t datasize, size_t *len ) { return UnPCKData(data, datasize, len, IsDataPCK(data, datasize)); }
308 cycrow 1560
unsigned char* UnPCKData(unsigned char* data, size_t datasize, size_t* len, bool nocrypt)
1 cycrow 1561
{
308 cycrow 1562
	if (!data || datasize < 8) { // Minimum size for header + length
1563
		if (len) *len = 0;
1564
		return nullptr;
1565
	}
1566
 
96 cycrow 1567
	bool isPCK = IsDataPCK(data, datasize);
308 cycrow 1568
	unsigned char* newData = data;
1569
	unsigned char* tempData = nullptr;
96 cycrow 1570
 
308 cycrow 1571
	if (nocrypt) {
1572
		tempData = new (std::nothrow) unsigned char[datasize];
1573
		if (!tempData) { if (len) *len = 0; return nullptr; }
1574
		memcpy(tempData, data, datasize);
1575
		unsigned char magic = tempData[0] ^ 0xC8;
1576
		for (size_t i = 1; i < datasize; i++)
1577
			tempData[i] ^= magic;
1578
		newData = tempData + 1;
1579
		datasize -= 1;
1580
	}
96 cycrow 1581
 
308 cycrow 1582
	if (datasize < 4) { // Not enough data for length
1583
		if (tempData) delete[] tempData;
1584
		if (len) *len = 0;
1585
		return nullptr;
1586
	}
1 cycrow 1587
 
308 cycrow 1588
	// Read uncompressed length safely
1589
	size_t lenPos = datasize - 4;
1590
	unsigned long uncomprLen = 0;
1591
	memcpy(&uncomprLen, newData + lenPos, 4);
1592
	if (uncomprLen > datasize * 100 || uncomprLen == 0) {
1593
		if (tempData) delete[] tempData;
1594
		if (len) *len = 0;
1595
		return nullptr;
1 cycrow 1596
	}
1597
 
308 cycrow 1598
	unsigned char* uncompr = new (std::nothrow) unsigned char[uncomprLen + 1];
1599
	if (!uncompr) {
1600
		if (tempData) delete[] tempData;
1601
		if (len) *len = 0;
1602
		return nullptr;
1 cycrow 1603
	}
308 cycrow 1604
	memset(uncompr, 0, uncomprLen + 1);
1605
 
1606
	// Parse header
1607
	size_t bufOffset = PCKHEADERSIZE;
1608
	if (datasize < bufOffset + 8) { // Not enough data for header and footer
1609
		if (tempData) delete[] tempData;
1610
		delete[] uncompr;
1611
		if (len) *len = 0;
1612
		return nullptr;
96 cycrow 1613
	}
308 cycrow 1614
	unsigned char flag = newData[3];
1615
	unsigned char* buf = newData + bufOffset;
1 cycrow 1616
 
308 cycrow 1617
	if (flag & GZ_FLAG_EXTRA) {
1618
		if (datasize < bufOffset + 2) { if (tempData) delete[] tempData; delete[] uncompr; if (len) *len = 0; return nullptr; }
1 cycrow 1619
		size_t xlen = *((short int*)(buf));
308 cycrow 1620
		buf += 2;
1 cycrow 1621
		buf += xlen;
1622
	}
308 cycrow 1623
	if (flag & GZ_FLAG_FILENAME) {
1624
		char* origname = (char*)(buf);
1625
		buf += strlen(origname) + 1;
1 cycrow 1626
	}
308 cycrow 1627
	if (flag & GZ_FLAG_COMMENT) {
1628
		char* comment = (char*)(buf);
1 cycrow 1629
		buf += strlen(comment) + 1;
1630
	}
308 cycrow 1631
	if (flag & GZ_FLAG_HCRC) {
1 cycrow 1632
		buf += 2;
308 cycrow 1633
	}
1 cycrow 1634
 
308 cycrow 1635
	long bufSize = (long)(datasize - (buf - newData) - 8);
1636
	if (bufSize <= 0) {
1637
		if (tempData) delete[] tempData;
1638
		delete[] uncompr;
1639
		if (len) *len = 0;
1640
		return nullptr;
1 cycrow 1641
	}
1642
 
308 cycrow 1643
	int err = uncompress2(uncompr, &uncomprLen, buf, bufSize);
1644
	if (err != Z_OK) {
1645
		if (tempData) delete[] tempData;
1646
		delete[] uncompr;
1647
		if (len) *len = 0;
1648
		return nullptr;
1649
	}
1650
 
1651
	if (len) *len = uncomprLen;
41 cycrow 1652
	uncompr[uncomprLen] = '\0';
317 cycrow 1653
	if (tempData) delete[]tempData;
1 cycrow 1654
	return uncompr;
1655
}
1656
 
1657
bool IsDataPCK ( const unsigned char *data, size_t size )
1658
{
1659
	if ( size >=3 )
1660
	{
1661
		unsigned char magic=data[0] ^ 0xC8;
1662
		return ((data[1] ^ magic)==0x1F && (data[2] ^ magic)==0x8B);
1663
	}
1664
	else
1665
		return false;
1666
 
1667
}
1668
 
1669
bool ReadSignedFromData ( unsigned char *data, long size )
1670
{
53 cycrow 1671
	bool ret = false;
1672
 
1673
	if ( IsDataPCK ( data, size ) ) {
1 cycrow 1674
		size_t unpckSize = 0;
1675
		unsigned char *unpckData = UnPCKData ( data, size, &unpckSize, false );
53 cycrow 1676
		if ( (unpckData) && (unpckSize) ) {
1677
			ret = ReadSignedFromData ( unpckData, (long)unpckSize );
1678
			delete unpckData;
1679
		}
1680
		return ret;
1 cycrow 1681
	}
1682
 
53 cycrow 1683
	char tag[10000];
1684
 
1 cycrow 1685
	// work backwards
1686
	int pos = size - 1;
43 cycrow 1687
	int max = size - 5000;
1688
	if ( max < 0 ) max = 0;
1 cycrow 1689
	// find the first tage
53 cycrow 1690
	while ( pos > max ) {
1691
		while ( data[pos] != '>' && pos > max ) pos--;
1692
		if ( data[pos] != '>' ) break;
1 cycrow 1693
 
53 cycrow 1694
		// now find the front
1695
		int pos2 = pos - 1;
1696
		while ( data[pos2] != '<' && pos2 > max ) pos2--;
1697
		if ( data[pos2] != '<' ) break;
1 cycrow 1698
 
53 cycrow 1699
		memcpy(tag, data + pos2, pos - pos2);
1700
		tag[pos - pos2] = '\0';
1 cycrow 1701
 
201 cycrow 1702
		Utils::WString sTag(tag);
1703
		if ( sTag.Compare(L"</signature") || sTag.Compare(L"<signature") ) return true;
1704
		if ( sTag.Compare(L"</codearray") || sTag.Compare(L"<codearray") ) return false;
53 cycrow 1705
		pos = pos2 - 1;
1 cycrow 1706
	}
1707
 
1708
	return false;
1709
}
1710
 
1711
int ReadScriptVersionFromData ( unsigned char *data, long size )
1712
{
54 cycrow 1713
	int iVersion = 0;
1714
 
1 cycrow 1715
	if ( IsDataPCK ( data, size ) )
1716
	{
1717
		size_t unpckSize = 0;
1718
		unsigned char *unpckData = UnPCKData ( data, size, &unpckSize );
54 cycrow 1719
		if ( (unpckData) && (unpckSize) ) {
1720
			iVersion = ReadScriptVersionFromData ( unpckData, (long)unpckSize );
1721
			delete unpckData;
1722
		}
1723
		return iVersion;
1 cycrow 1724
	}
1725
 
54 cycrow 1726
	// only check the beginning of the file
1727
	int iMax = (size > 5000) ? 5000 : size;
1728
 
1 cycrow 1729
	int pos = 0;
1730
	bool found = false;
1731
	// skip past initial space
54 cycrow 1732
	char tag[21];
1733
	while ( pos < iMax )
1 cycrow 1734
	{
54 cycrow 1735
		// skip past whitespace
1736
		while ( (pos < iMax) && (data[pos] == ' ') ) ++pos;
1737
		// find the first '<'
1738
		while ( (pos < iMax) && (data[pos] != '<') ) ++pos;
1739
		if ( data[pos] != '<' ) break; //not found
1 cycrow 1740
 
54 cycrow 1741
		// find end tag '>'
1742
		int iStartPos = pos;
1743
		while ( (pos < iMax) && (data[pos] != '>') ) ++pos;
1744
		if ( data[pos] != '>' ) break; //not found
1745
		if ( (pos - iStartPos) > 20 ) continue;
1 cycrow 1746
 
54 cycrow 1747
		// check if the tag is what we're looking for
1748
		memcpy(tag, data + iStartPos, pos - iStartPos);
1749
		tag[pos - iStartPos] = '\0';
201 cycrow 1750
		Utils::WString sTag(tag);
1751
		if ( !sTag.Compare(L"<version") ) continue;
54 cycrow 1752
 
1753
		//extract the tag data
1754
		iStartPos = pos + 1;
1755
		while ( (pos < iMax) && (data[pos] != '<') ) ++pos;
1756
		if ( (pos - iStartPos) > 20 ) continue;
1757
		memcpy(tag, data + iStartPos, pos - iStartPos);
1758
		tag[pos - iStartPos] = '\0';
1759
		return atoi(tag);
1 cycrow 1760
	}
1761
 
1762
	return iVersion;
1763
}
1764
 
197 cycrow 1765
Utils::WString C_File::baseName() const
1 cycrow 1766
{
1767
	// remove any directory
197 cycrow 1768
	Utils::WString file = _sName.token(L"/", -1);
1 cycrow 1769
 
1770
	// remove file extension
197 cycrow 1771
	return file.remToken(L".", -1);
1 cycrow 1772
}
1773
 
1774
void C_File::CopyData(C_File *oldFile, bool includeData)
1775
{
178 cycrow 1776
	setFilename(oldFile->fullFilename());
131 cycrow 1777
	_sDir = oldFile->dir();
1 cycrow 1778
	m_tTime = oldFile->GetCreationTime();
1779
	m_bShared = oldFile->IsShared();
1780
	m_bSigned = oldFile->IsSigned();
127 cycrow 1781
	m_iFileType = oldFile->fileType();
1 cycrow 1782
	m_lSize = oldFile->GetSize();
1783
	if ( includeData )
1784
	{
1785
		m_lDataSize = oldFile->GetDataSize();
1786
		if ( m_sData )
1787
			this->DeleteData();
1788
		m_sData = NULL;
1789
		if ( oldFile->GetData() && m_lDataSize )
1790
		{
1791
			m_sData = new unsigned char[m_lDataSize];
1792
			m_bUsedMalloc = false;
1793
			memcpy((char *)m_sData, (char *)oldFile->GetData(), m_lDataSize);
1794
		}
178 cycrow 1795
		m_lUncomprDataSize = oldFile->uncompressedDataSize();
1 cycrow 1796
	}
1797
	m_iDataCompression = oldFile->GetCompressionType();
1798
}
1799
 
1800
float GetLibraryVersion() { return (float)LIBRARYVERSION; }
1801
float GetFileFormatVersion() { return (float)FILEVERSION; }
1802
 
197 cycrow 1803
Utils::WString C_File::fileExt() const 
130 cycrow 1804
{ 
197 cycrow 1805
	return _sName.token(L".", -1); 
130 cycrow 1806
}
1807
 
197 cycrow 1808
bool C_File::checkFileExt(const Utils::WString& ext) 
178 cycrow 1809
{
1810
	if (fileExt().Compare(ext)) return true; return false;
1811
}
1812
 
197 cycrow 1813
const Utils::WString &C_File::changeFileExt(const Utils::WString &ext)
130 cycrow 1814
{
197 cycrow 1815
	_sName = CFileIO(_sName).changeFileExtension(ext);
130 cycrow 1816
	return _sName;
1817
}
1818
 
1 cycrow 1819
bool C_File::CheckPackedExtension()
1820
{
197 cycrow 1821
	Utils::WString ext = this->fileExt();
1822
	if ( ext == L"pck" )
1 cycrow 1823
		return true;
197 cycrow 1824
	else if ( ext == L"pbb" )
1 cycrow 1825
		return true;
197 cycrow 1826
	else if ( ext == L"pbd" )
1 cycrow 1827
		return true;
1828
 
1829
	return false;
1830
}
1831
 
125 cycrow 1832
bool C_File::shouldCheckBaseName() const
1833
{
196 cycrow 1834
	Utils::WString ext = CFileIO(_sName).extension();
1835
	if (ext == L"xml" || ext == L"txt" || ext == L"pck")
125 cycrow 1836
		return true;
196 cycrow 1837
	if (ext == L"bod" || ext == L"bob" || ext == L"pbb" || ext == L"pbd")
125 cycrow 1838
		return true;
1839
	return false;
1840
}
1841
 
127 cycrow 1842
unsigned int C_File::game() const 
1843
{ 
1844
	return _iGame; 
1845
}
125 cycrow 1846
 
129 cycrow 1847
bool C_File::isForGame(int game) const
1848
{
1849
	if (game > 0)
1850
	{
1851
		if (!_iGame || _iGame == GAME_ALLNEW)
1852
			return true;
1853
		return (_iGame & 1 << game) != 0;
1854
	}
1855
 
1856
	return true;
1857
}
1858
 
1859
int C_File::getForSingleGame() const
1860
{
1861
	int checkGame = _iGame & ~GAME_ALLNEW;
1862
	for (int i = 0; i < 31; ++i)
1863
	{
1864
		if (checkGame == (1 << i))
1865
			return i;
1866
	}
1867
 
1868
	return 0;
1869
}
1870
 
127 cycrow 1871
void C_File::setGame(unsigned int i) 
1872
{ 
1873
	if (i == 0 || i == 1 << 31)
1874
		_iGame = 0;
1875
	else
1876
		_iGame = i; 
1877
}
1878
 
1879
 
323 cycrow 1880
unsigned char* C_File::BobDecompile(size_t* size)
115 cycrow 1881
{
1882
	(*size) = 0;
1883
 
197 cycrow 1884
	Utils::WString fromFile = this->filePointer();
283 cycrow 1885
	if (!CFileIO::Exists(fromFile))
1886
	{
1887
		if (this->writeToFile(CPackages::tempDirectory() + L"bob.tmp"))
1888
			fromFile = CPackages::tempDirectory() + L"bob.tmp";
1889
	}
1890
 
1891
	fromFile = fromFile.findReplace(L"/", L"\\");
1892
	Utils::WString toFile = CPackages::tempDirectory() + L"bod.tmp";
1893
	toFile = toFile.findReplace(L"/", L"\\");
1894
 
1895
	if (CFileIO::Exists(fromFile))
1896
	{
1897
#ifdef _XBODLIBRARY__
1898
		if (X2BC_BOB2BOD(fromFile.toString().c_str(), toFile.toString().c_str())) {
1899
			CFileIO F(toFile);
1900
			if (F.exists() && F.startRead()) {
1901
				unsigned char* data = F.readAll(size);
1902
				F.close();
1903
				F.remove();
1904
 
1905
				return data;
1906
			}
1907
		}
1908
#else
1909
		// Use x2bc library to convert the file
1910
		Settings settings;
1911
		bob_dom_document doc(&settings);
1912
 
1913
		ibinaryrealfile is;
1914
		otextrealfile os;
1915
 
1916
		is.open(fromFile.toString().c_str(), filestream::rdonly);
1917
		os.open(toFile.toString().c_str(), filestream::create);
1918
 
1919
		if (!is.fail() && !os.fail())
1920
		{
1921
			if (doc.convert(is, os))
1922
			{
1923
				CFileIO F(toFile);
1924
				if (F.exists() && F.startRead())
1925
				{
1926
					unsigned char* data = F.readAll(size);
1927
					F.close();
1928
					F.remove();
1929
 
1930
					return data;
1931
				}
1932
			}
1933
		}
1934
#endif
1935
	}
1936
 
1937
	if (CFileIO::Exists(CPackages::tempDirectory() + L"bob.tmp"))
1938
		CFileIO::Remove(CPackages::tempDirectory() + L"bob.tmp");
1939
 
1940
	return NULL;
323 cycrow 1941
}
1942
 
1943
unsigned char* C_File::BobCompile(size_t* size, bool isCut)
1944
{
283 cycrow 1945
	(*size) = 0;
1946
 
323 cycrow 1947
	if (!m_sData || !m_lDataSize)
1948
	{
1949
		if (!this->ReadFromFile())
1950
			return NULL;
115 cycrow 1951
	}
1952
 
323 cycrow 1953
	Utils::WString toFile = CPackages::tempDirectory() + L"bob.tmp";
213 cycrow 1954
	toFile = toFile.findReplace(L"/", L"\\");
323 cycrow 1955
	CFileIO ToFile(toFile);
115 cycrow 1956
 
323 cycrow 1957
	Settings settings;
1958
	bod_parser p(&settings);
1959
	bool bRes;
1960
	bod_parser::fileType type = isCut ? bod_parser::cutFile : bod_parser::bobFile;
115 cycrow 1961
 
323 cycrow 1962
	obinaryrealfile os;
1963
	os.open(ToFile.fullFilename().toFileUTF8().c_str(), filestream::create);
1964
	if (!os.bad())
1965
	{
1966
		bRes = p.compile((char *)m_sData, (size_t)m_lDataSize, type, os);
1967
		for (bod_parser::iterator& it = p.errors.begin(); it != p.errors.end(); ++it) {
1968
			;  // check errors?
115 cycrow 1969
		}
1970
	}
323 cycrow 1971
	os.close();
115 cycrow 1972
 
323 cycrow 1973
	CFileIO tmpFile(CPackages::tempDirectory() + L"bob.tmp");
1974
	if (tmpFile.exists() && tmpFile.startRead())
1975
	{
1976
		unsigned char* data = tmpFile.readAll(size);
1977
		tmpFile.close();
1978
		tmpFile.remove();
1979
		if (data)
1980
			return data;
115 cycrow 1981
	}
1982
 
1983
	return NULL;
1984
}
1985
 
1 cycrow 1986
 
197 cycrow 1987
bool C_File::renameScript(const Utils::WString &baseName)
1 cycrow 1988
{
1989
	if ( !m_sData || !m_lDataSize )
1990
	{
1991
		if ( !this->ReadFromFile() )
1992
			return false;
1993
	}
1994
 
1995
	// uncompress the file
1996
	if ( !this->UncompressData() )
1997
		return false;
1998
 
1999
	// un pck the file
197 cycrow 2000
	if (this->checkFileExt(L"pck"))
1 cycrow 2001
	{
2002
		if ( !this->UnPCKFile() )
2003
			return false;
2004
	}
2005
 
2006
	// now we should have the raw data
197 cycrow 2007
	Utils::WString data((const char *)m_sData);
178 cycrow 2008
	data.truncate(m_lDataSize);
2009
	data = data.findReplace(this->baseName(), baseName);
1 cycrow 2010
 
2011
	this->DeleteData();
178 cycrow 2012
	m_sData = new unsigned char[data.length()];
2013
	memcpy(m_sData, data.c_str(), data.length());
2014
	m_lDataSize = (long)data.length();
1 cycrow 2015
 
2016
	// repck the file
197 cycrow 2017
	if (this->checkFileExt(L"pck"))
1 cycrow 2018
	{
2019
		if ( !this->PCKFile() )
2020
			return false;
2021
	}
2022
 
2023
 
2024
	return true;
129 cycrow 2025
}
2026
 
197 cycrow 2027
Utils::WString C_File::_getFullFileToDir(const Utils::WString &dir, bool includedir, CBaseFile *file) const
129 cycrow 2028
{
197 cycrow 2029
	Utils::WString fullfile = dir;
129 cycrow 2030
	if (includedir)
2031
	{
197 cycrow 2032
		Utils::WString d = getDirectory(file);
129 cycrow 2033
		if (!d.empty())
2034
		{
2035
			if (!fullfile.empty())
197 cycrow 2036
				fullfile += L"/";
129 cycrow 2037
			fullfile += d;
2038
		}
2039
	}
130 cycrow 2040
	if (!_sName.empty())
129 cycrow 2041
	{
2042
		if (!fullfile.empty())
197 cycrow 2043
			fullfile += L"/";
130 cycrow 2044
		fullfile += _sName;
129 cycrow 2045
	}
2046
 
197 cycrow 2047
	fullfile = fullfile.findReplace(L"\\", L"/");
129 cycrow 2048
	return fullfile;
2049
}