Subversion Repositories spk

Rev

Rev 121 | Rev 126 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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