Subversion Repositories spk

Rev

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

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