Subversion Repositories spk

Rev

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

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