Subversion Repositories spk

Rev

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