Subversion Repositories spk

Rev

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