Subversion Repositories spk

Rev

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