Subversion Repositories spk

Rev

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