Subversion Repositories spk

Rev

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