Subversion Repositories spk

Rev

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

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