Subversion Repositories spk

Rev

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