Subversion Repositories spk

Rev

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