Subversion Repositories spk

Rev

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