Subversion Repositories spk

Rev

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