Subversion Repositories spk

Rev

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

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