Subversion Repositories spk

Rev

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

Rev Author Line No. Line
6 cycrow 1
// SpkFile.cpp: implementation of the CSpkFile class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
 
5
#include "BaseFile.h"
6
 
7
//////////////////////////////////////////////////////////////////////
8
// Construction/Destruction
9
//////////////////////////////////////////////////////////////////////
10
 
11
#include "spk.h"
12
 
13
#include "DirIO.h"
14
#include "File_IO.h"
15
#include "CatFile.h"
16
#include "Packages.h"
88 cycrow 17
#include "TextDB.h"
6 cycrow 18
 
46 cycrow 19
#include <Package/InstallText.h>
6 cycrow 20
 
46 cycrow 21
// remove these eventually
22
using namespace SPK;
23
using namespace Package;
6 cycrow 24
 
25
CArchiveFile::~CArchiveFile()
26
{
27
	Delete ();
28
}
29
 
30
CArchiveFile::CArchiveFile() : CBaseFile ()
31
{
32
	SetDefaults ();
33
}
34
 
35
void CBaseFile::SetDefaults ()
36
{
46 cycrow 37
	_setDefaults();
38
 
6 cycrow 39
	m_pIconFile = NULL;
40
 
41
	m_bAutoGenerateUpdateFile = false;
42
	m_SHeader.iValueCompression = SPKCOMPRESS_ZLIB;
43
	m_SHeader2.iFileCompression = SPKCOMPRESS_ZLIB;
44
	m_SHeader2.iDataCompression = SPKCOMPRESS_LZMA;
45
	m_pParent = NULL;
50 cycrow 46
	_changed();
6 cycrow 47
	m_bUpdate = false;
130 cycrow 48
	_bCombineFiles = false;
6 cycrow 49
 
50
	ClearError();
51
 
52
	m_iLoadError = 0;
53
 
54
	m_bFullyLoaded = false;
55
	m_bSigned = false;
56
	m_bEnable = m_bGlobal = m_bProfile = m_bModifiedEnabled = true;
57
	m_bOverrideFiles = false;
58
}
59
 
88 cycrow 60
CBaseFile::CBaseFile() : _pTextDB(NULL)
6 cycrow 61
{
62
	SetDefaults ();
63
}
64
CBaseFile::~CBaseFile()
65
{
66
	Delete();
67
}
68
 
170 cycrow 69
 
70
Utils::String CBaseFile::getFullPackageName(int language, const Utils::String &byString) const
71
{ 
72
	return getFullPackageName(language, true, byString); 
73
}
74
Utils::String CBaseFile::getFullPackageName(int language, bool includeVersion, const Utils::String &byString) const
75
{
171 cycrow 76
	Utils::String p = this->name(language);
170 cycrow 77
	if (includeVersion)
78
	{
79
		p += " V";
80
		p += this->version();
81
	}
82
	p += " ";
83
	p += byString + " " + this->author();
84
	return p;
85
}
86
 
87
Utils::String CBaseFile::getFullPackageName(const Utils::String &format, int lang) const
88
{
89
	if (format.empty())
90
		return getFullPackageName(lang);
91
 
171 cycrow 92
	Utils::String args[3] = { this->name(lang), this->version(), this->author()};
170 cycrow 93
	return format.args(args, 3);
94
}
95
 
6 cycrow 96
void CBaseFile::Delete ()
97
{
170 cycrow 98
	m_lTempFiles.clear();
6 cycrow 99
	m_lFiles.clear(true);
100
 
101
	if ( m_pIconFile )
102
	{
103
		delete m_pIconFile;
104
		m_pIconFile = NULL;
105
	}
106
 
88 cycrow 107
	if ( _pTextDB ) {
108
		delete _pTextDB;
109
		_pTextDB = NULL;
110
	}
6 cycrow 111
}
112
 
113
 
114
/*
115
##########################################################################################
116
##################                Base Class Functions                  ##################
117
##########################################################################################
118
*/
119
 
170 cycrow 120
const CLinkList<C_File> &CBaseFile::fileList() const
131 cycrow 121
{
170 cycrow 122
	return m_lFiles;
131 cycrow 123
}
170 cycrow 124
CLinkList<C_File> &CBaseFile::fileList(FileType type, CLinkList<C_File>& list) const
125
{ 
126
	for (CListNode<C_File>* node = m_lFiles.Front(); node; node = node->next())
6 cycrow 127
	{
170 cycrow 128
		C_File* f = node->Data();
129
		if (f->GetFileType() == type)
130
			list.push_back(f);
6 cycrow 131
	}
132
 
133
	return list;
134
}
170 cycrow 135
CLinkList<C_File> &CBaseFile::fileList(FileType type)
136
{
137
	m_lTempFiles.clear();
138
	return fileList(type, m_lTempFiles);
139
}
6 cycrow 140
 
13 cycrow 141
C_File *CBaseFile::GetNextFile(C_File *prev) const
6 cycrow 142
{
143
	int type = -1;
144
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
145
	{
146
		C_File *f = node->Data();
147
		if ( type == -1 )
148
		{
149
			if ( f == prev )
150
				type = f->GetFileType();
151
		}
152
		else
153
		{
154
			if ( f->GetFileType() == type )
155
				return f;
156
		}
157
	}
158
 
159
	return NULL;
160
}
161
 
13 cycrow 162
C_File *CBaseFile::GetPrevFile(C_File *next) const
6 cycrow 163
{
164
	if ( !next )
165
		return NULL;
166
 
167
	int type = -1;
168
	for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() )
169
	{
170
		C_File *f = node->Data();
171
		if ( type == -1 )
172
		{
173
			if ( f == next )
174
				type = f->GetFileType();
175
		}
176
		else
177
		{
178
			if ( f->GetFileType() == type )
179
				return f;
180
		}
181
	}
182
 
183
	return NULL;
184
}
185
 
13 cycrow 186
C_File *CBaseFile::GetFirstFile(int type) const
6 cycrow 187
{
188
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
189
	{
190
		C_File *f = node->Data();
191
		if ( f->GetFileType() == type )
192
			return f;
193
	}
194
 
195
	return NULL;
196
}
197
 
175 cycrow 198
int CBaseFile::CheckFile(const Utils::String &filename, float *version )
6 cycrow 199
{
91 cycrow 200
	CFileIO File(filename);
201
	if ( !File.startRead() ) return 0;
202
	Utils::String line = File.readEndOfLine();
51 cycrow 203
	Utils::String type = line.token(";", 1);
204
	File.close();
6 cycrow 205
 
206
	// check for old version
51 cycrow 207
	if ( line.left(3) == "HiP" ) return SPKFILE_OLD;
6 cycrow 208
 
209
	// check for format
51 cycrow 210
	if ( version ) *version = line.token(";", 2);
6 cycrow 211
 
51 cycrow 212
	if ( type == "BaseCycrow" )	return SPKFILE_BASE;
213
	if ( type == "SPKCycrow" )	return SPKFILE_SINGLE;
214
	if ( type == "XSPCycrow" )	return SPKFILE_SINGLESHIP;
215
	if ( type == "MSPKCycrow" )	return SPKFILE_MULTI;
6 cycrow 216
	return SPKFILE_INVALID;
217
}
218
 
219
void CBaseFile::ClearFileData()
220
{
88 cycrow 221
	for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
6 cycrow 222
	{
88 cycrow 223
		f->Data()->DeleteData();
6 cycrow 224
	}
225
}
226
 
130 cycrow 227
Utils::String CBaseFile::getNameValidFile() const
6 cycrow 228
{
130 cycrow 229
	Utils::String name = this->name();
230
	name.removeChar(':');
231
	name.removeChar('/');
232
	name.removeChar('\\');
233
	name.removeChar('*');
234
	name.removeChar('?');
235
	name.removeChar('"');
236
	name.removeChar('<');
237
	name.removeChar('>');
238
	name.removeChar('|');
239
	return name;
240
}
6 cycrow 241
 
242
void CBaseFile::SwitchFilePointer(C_File *oldFile, C_File *newFile)
243
{
244
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
245
	{
246
		C_File *f = node->Data();
247
		if ( f == oldFile )
248
		{
249
			node->ChangeData(newFile);
250
			break;
251
		}
252
	}
253
}
254
 
255
bool CBaseFile::AnyFileType ( int type )
256
{
257
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
258
	{
259
		C_File *f = node->Data();
260
		if ( f->GetFileType() == type )
261
			return true;
262
	}
263
 
264
	return false;
265
}
266
 
267
void CBaseFile::AddFile ( C_File *file )
268
{
269
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
270
	{
271
		C_File *f = node->Data();
130 cycrow 272
		if ( f->fileType() != file->fileType() )
6 cycrow 273
			continue;
130 cycrow 274
		if ( f->name() != file->name () )
6 cycrow 275
			continue;
170 cycrow 276
		if ( f->dir() != file->dir() )
6 cycrow 277
			continue;
127 cycrow 278
		if ( f->game() != file->game() )
6 cycrow 279
			continue;
280
 
281
		m_lFiles.remove(node, true);
282
		break;
283
	}
284
 
88 cycrow 285
	_addFile(file);
6 cycrow 286
}
287
 
155 cycrow 288
C_File *CBaseFile::addFile(const Utils::String &file, const Utils::String &dir, FileType type, int game, bool packed)
127 cycrow 289
{
290
	C_File *newfile = new C_File(file);
178 cycrow 291
	newfile->setDir(dir);
130 cycrow 292
	newfile->setFileType(type);
127 cycrow 293
	newfile->setGame(game);
6 cycrow 294
 
155 cycrow 295
	if (packed)
296
	{
297
		if (newfile->PCKFile())
298
		{
299
			newfile->setFilename(CFileIO(newfile->filePointer()).changeFileExtension("pck"));
300
		}
301
	}
302
 
6 cycrow 303
	// first check if the file already exists
304
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
305
	{
306
		C_File *f = node->Data();
130 cycrow 307
		if ( f->fileType() != newfile->fileType() )
6 cycrow 308
			continue;
130 cycrow 309
		if ( f->name() != newfile->name () )
6 cycrow 310
			continue;
134 cycrow 311
		if ( f->dir() != newfile->dir() )
6 cycrow 312
			continue;
130 cycrow 313
		if (f->game() != newfile->game())
314
		{
315
			//same file, for different game, check if they are the same and combine them
316
			if (_bCombineFiles)
317
			{
318
				char *data = NULL;
319
				char *newData = NULL;
320
				size_t size = 0;
321
				size_t newSize = 0;
322
 
323
				if (f->GetData() && f->GetDataSize())
143 cycrow 324
					data = (char *)f->UncompressData((long *)&size, NULL);
130 cycrow 325
				else if(f->isExternalFile())
326
					data = CFileIO(f->filePointer()).ReadToData(&size);
327
				if (newfile->GetData() && newfile->GetDataSize())
143 cycrow 328
					newData = (char *)f->UncompressData((long *)&newSize, NULL);
130 cycrow 329
				else
330
					newData = CFileIO(newfile->filePointer()).ReadToData(&newSize);
331
 
332
				// compare bytes
333
				bool matched = false;
334
				if (size == newSize)
335
				{
336
					matched = true;
337
					for (unsigned long i = 0; i < size; ++i)
338
					{
339
						if (data[i] != newData[i])
340
						{
341
							matched = false;
342
							break;
343
						}
344
					}
345
				}
346
 
143 cycrow 347
				if (data)
130 cycrow 348
					delete data;
143 cycrow 349
				if (newData)
130 cycrow 350
					delete newData;
351
 
352
				if (matched)
353
				{
354
					if(!f->game() || f->game() == GAME_ALLNEW)
355
						newfile->setGame(0);
356
					else
357
						newfile->setGame(newfile->game() | f->game());
358
					m_lFiles.remove(node, true);
359
					break;
360
				}
361
			}
6 cycrow 362
			continue;
130 cycrow 363
		}
6 cycrow 364
 
365
		// must already exist, delete this one
366
		m_lFiles.remove(node, true);
367
		break;
368
	}
369
 
88 cycrow 370
	_addFile(newfile);
6 cycrow 371
 
372
	return newfile;
373
}
374
 
170 cycrow 375
bool CBaseFile::addFileNow(const Utils::String &file, const Utils::String &dir, FileType type, CProgressInfo* progress)
6 cycrow 376
{
170 cycrow 377
	C_File* f = addFile(file, dir, type);
378
	if (!f->ReadFromFile())
6 cycrow 379
		return false;
380
 
381
	// compress the file
170 cycrow 382
	return f->CompressData(m_SHeader2.iDataCompression, progress);
6 cycrow 383
}
384
 
155 cycrow 385
C_File *CBaseFile::appendFile(const Utils::String &file, int type, int game, bool packed, const Utils::String &dir, CProgressInfo *progress )
6 cycrow 386
{
155 cycrow 387
	C_File *newfile = addFile(file, dir, static_cast<FileType>(type), game, packed);
6 cycrow 388
	if ( !newfile )
389
		return NULL;
390
 
391
	// read the file into memory
155 cycrow 392
	if (newfile->GetData() && newfile->GetDataSize())
393
	{
394
		// now compress the file
395
		if (newfile->CompressData(m_SHeader2.iDataCompression, progress))
396
			return newfile;
397
	}
6 cycrow 398
	if ( newfile->ReadFromFile () )
399
	{
400
		// now compress the file
401
		if ( newfile->CompressData ( m_SHeader2.iDataCompression, progress ) )
402
			return newfile;
403
	}
404
	else if ( newfile->GetLastError() == SPKERR_MALLOC )
405
	{
406
		if ( newfile->CompressFile ( progress ) )
407
			return newfile;
408
	}
409
 
410
	m_lFiles.pop_back ();
411
	delete newfile;
412
 
413
	return NULL;
414
}
415
 
170 cycrow 416
C_File *CBaseFile::findFileAt(FileType filetype, size_t pos) const
6 cycrow 417
{
170 cycrow 418
	size_t count = 0;
6 cycrow 419
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
420
	{
421
		C_File *file = node->Data();
422
		if ( file->GetFileType() != filetype )
423
			continue;
424
 
425
		if ( count == pos )
426
			return file;
427
 
428
		++count;
429
	}
430
 
431
	return NULL;
432
}
433
 
170 cycrow 434
C_File* CBaseFile::findFile(const Utils::String &filename, FileType type, const Utils::String &dir, int game) const
435
{	
436
	Utils::String lfile = CFileIO(filename.lower()).filename();
6 cycrow 437
 
170 cycrow 438
	CListNode<C_File>* node = m_lFiles.Front();
439
	while (node)
6 cycrow 440
	{
170 cycrow 441
		C_File* f = node->Data();
6 cycrow 442
		node = node->next();
443
 
170 cycrow 444
		if (type != f->GetFileType())
6 cycrow 445
			continue;
170 cycrow 446
		if (dir != f->dir())
6 cycrow 447
			continue;
170 cycrow 448
		if (game != f->game())
6 cycrow 449
			continue;
170 cycrow 450
		if (f->name().lower() == lfile)
6 cycrow 451
			return f;
452
	}
453
	return NULL;
454
}
455
 
170 cycrow 456
bool CBaseFile::removeFile(const Utils::String& file, FileType type, const Utils::String& dir, int game)
6 cycrow 457
{
170 cycrow 458
	C_File* f = findFile(file, type, dir, game);
459
	if (!f)
6 cycrow 460
		return false;
172 cycrow 461
	return removeFile(f);
6 cycrow 462
}
463
 
172 cycrow 464
bool CBaseFile::removeFile(C_File *file)
6 cycrow 465
{
172 cycrow 466
	size_t count = 0;
6 cycrow 467
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
468
	{
469
		C_File *f = node->Data();
470
		if ( f == file )
172 cycrow 471
			return removeFile(count);
6 cycrow 472
		++count;
473
	}
474
	return false;
475
}
476
 
172 cycrow 477
bool CBaseFile::removeFile(size_t pos)
6 cycrow 478
{
172 cycrow 479
	if (pos >= static_cast<size_t>(m_lFiles.size()))
6 cycrow 480
		return false;
481
 
482
	C_File *file = m_lFiles.Get ( pos );
483
	m_lFiles.erase ( pos + 1 );
484
 
485
	if ( file )
486
		delete file;
487
 
50 cycrow 488
	_changed();
6 cycrow 489
 
490
	return true;
491
}
492
 
493
 
129 cycrow 494
void CBaseFile::removeAllFiles(FileType type, int game)
6 cycrow 495
{
496
	if ( m_lFiles.empty() )
497
		return;
498
 
499
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
500
	{
129 cycrow 501
		if (game == 0 && node->Data()->game() && node->Data()->game() != GAME_ALLNEW)
502
			continue;
503
		if ( game > -1 )
504
		{
505
			unsigned int fileGame = node->Data()->game() & ~GAME_ALLNEW;
506
			if (fileGame != (1 << game))
507
			{
508
				// just remove the game from file
509
				if (fileGame & (1 << game))
510
					node->Data()->setGame(node->Data()->game() & ~(1 << game));
6 cycrow 511
				continue;
129 cycrow 512
			}
6 cycrow 513
		}
129 cycrow 514
		if ( type == FILETYPE_UNKNOWN || node->Data()->GetFileType() == type )
6 cycrow 515
			node->DeleteData();
516
	}
517
 
518
	m_lFiles.RemoveEmpty();
519
 
50 cycrow 520
	_changed();
6 cycrow 521
}
522
 
523
void CBaseFile::RecompressAllFiles ( int type, CProgressInfo *progress )
524
{
525
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
526
	{
527
		C_File *file = node->Data();
528
		if ( progress )
529
			progress->UpdateFile(file);
530
 
531
		if ( file->GetCompressionType() == type )
532
			continue;
533
 
534
		if ( !file->GetData() )
535
			file->ReadFromFile();
536
 
537
		file->ChangeCompression ( type, progress );
538
	}
539
}
540
 
47 cycrow 541
void CBaseFile::CompressAllFiles ( int type, CProgressInfo *progress, CProgressInfo *overallProgress, int level )
6 cycrow 542
{
47 cycrow 543
	if ( overallProgress ) overallProgress->SetMax(m_lFiles.size());
544
 
545
	int iCount = 0;
6 cycrow 546
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
547
	{
548
		C_File *file = node->Data();
549
		if ( progress )
550
			progress->UpdateFile(file);
551
 
552
		if ( !file->GetData() )
553
			file->ReadFromFile();
554
 
555
		file->CompressData ( type, progress, level );
47 cycrow 556
 
557
		if ( overallProgress ) overallProgress->SetDone(++iCount);
6 cycrow 558
	}
559
}
560
 
561
bool CBaseFile::UncompressAllFiles ( CProgressInfo *progress )
562
{
563
	int countFile = 0;
564
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
565
	{
566
		C_File *fit = node->Data();
567
		if ( progress )
568
		{
569
			progress->UpdateFile ( fit );
570
			progress->UpdateProgress(countFile++, m_lFiles.size());
571
		}
572
 
573
		bool uncomprToFile = false;
574
 
575
		if ( progress )
576
			progress->SwitchSecond();
577
 
127 cycrow 578
		if(!fit->isExternalFile())
6 cycrow 579
		{
127 cycrow 580
			if (!fit->UncompressData(progress))
6 cycrow 581
			{
127 cycrow 582
				if (fit->GetCompressionType() == SPKCOMPRESS_7ZIP)
6 cycrow 583
				{
178 cycrow 584
					if (!fit->uncompressToFile("temp", this, false, progress))
127 cycrow 585
						return false;
586
					else
587
					{
588
						uncomprToFile = true;
178 cycrow 589
						fit->setFullDir("temp");
127 cycrow 590
					}
6 cycrow 591
				}
127 cycrow 592
 
593
				if (!uncomprToFile)
594
					return false;
6 cycrow 595
			}
596
		}
597
 
598
		if ( progress )
599
			progress->SwitchSecond();
600
	}
601
	return true;
602
}
603
 
170 cycrow 604
size_t CBaseFile::fileSize() const
6 cycrow 605
{
170 cycrow 606
	size_t fullsize = 1000;
6 cycrow 607
 
170 cycrow 608
	for (CListNode<C_File>* node = m_lFiles.Front(); node; node = node->next())
178 cycrow 609
		fullsize += node->Data()->uncompressedDataSize();
6 cycrow 610
 
170 cycrow 611
	if (m_pIconFile)
178 cycrow 612
		fullsize += m_pIconFile->uncompressedDataSize();
6 cycrow 613
 
614
	return fullsize;
615
}
616
 
617
/*
618
	Func:   GetEndOfLine
619
	Input:  id - The file id for the current file to read from
620
	        line - Pointed to hold the line number thats read
621
			upper - true if it converts to uppercase
622
	Return: String - the string it has read
623
	Desc:   Reads a string from a file, simlar to readLine() classes, reads to the end of the line in a file
624
*/
175 cycrow 625
Utils::String CBaseFile::GetEndOfLine ( FILE *id, int *line, bool upper )
6 cycrow 626
{
175 cycrow 627
	Utils::String word;
6 cycrow 628
 
629
	char c = fgetc ( id );
630
	if ( c == -1 )
631
		return "";
632
 
633
	while ( (c != 13) && (!feof(id)) && (c != '\n') )
634
	{
635
		word += c;
636
		c = fgetc ( id );
637
	}
638
 
639
	if ( line )
640
		++(*line);
641
 
642
	if ( upper )
175 cycrow 643
		return word.upper();
6 cycrow 644
 
645
	return word;
646
}
647
 
170 cycrow 648
size_t CBaseFile::countFiles(FileType filetype) const
6 cycrow 649
{
170 cycrow 650
	size_t i = 0;
6 cycrow 651
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
652
	{
653
		C_File *file = node->Data();
654
		if ( file->GetFileType() != filetype )
655
			continue;
656
		++i;
657
	}
658
 
659
	return i;
660
}
661
 
662
/*
663
	Func:   CreateFilesLine
664
	Return: String - returns the full string for files list
665
	Desc:   Creates a signle line list of all the files
666
*/
175 cycrow 667
Utils::String CBaseFile::createFilesLine(SSPKHeader2 *header, CProgressInfo* progress) const
6 cycrow 668
{
170 cycrow 669
	Utils::String line;
6 cycrow 670
 
170 cycrow 671
	if (progress)
6 cycrow 672
	{
673
		progress->SetDone(0);
674
		progress->UpdateStatus(STATUS_COMPRESS);
675
	}
676
 
175 cycrow 677
	if (header)
6 cycrow 678
	{
175 cycrow 679
		header->iDataCompression = m_SHeader2.iDataCompression;
680
		header->iFileCompression = m_SHeader2.iFileCompression;
681
		header->lSize = m_SHeader2.lSize;
682
		header->iNumFiles = 0;
683
		header->lFullSize = 0;
6 cycrow 684
	}
685
 
170 cycrow 686
	if (m_pIconFile)
6 cycrow 687
	{
688
		// no data, read it from file
170 cycrow 689
		if (!m_pIconFile->GetData())
690
			m_pIconFile->ReadFromFile();
6 cycrow 691
 
692
		// compress the file
170 cycrow 693
		if (!m_pIconFile->CompressData(m_SHeader2.iDataCompression, progress))
6 cycrow 694
			m_pIconFile->SetDataCompression(SPKCOMPRESS_NONE);
695
 
178 cycrow 696
		line += "Icon:" + Utils::String::Number(m_pIconFile->GetDataSize() + (long)4) + ":" + m_pIconFile->uncompressedDataSize() + ":" + (long)m_pIconFile->GetCompressionType() + ":" + _sIconExt + "\n";
175 cycrow 697
		if (header)
6 cycrow 698
		{
175 cycrow 699
			++header->iNumFiles;
700
			header->lFullSize += (m_pIconFile->GetDataSize() + 4);
6 cycrow 701
		}
702
	}
703
 
170 cycrow 704
	for (CListNode<C_File>* node = m_lFiles.Front(); node; node = node->next())
6 cycrow 705
	{
170 cycrow 706
		C_File* file = node->Data();
707
		if (progress)
708
			progress->UpdateFile(file);
6 cycrow 709
 
710
		// no data, read it from file
170 cycrow 711
		if (!file->GetData())
6 cycrow 712
		{
170 cycrow 713
			if (!file->ReadFromFile())
6 cycrow 714
			{
170 cycrow 715
				if (file->GetLastError() == SPKERR_MALLOC)
6 cycrow 716
				{
170 cycrow 717
					if (!file->CompressFile(progress))
6 cycrow 718
						continue;
719
				}
720
			}
721
		}
722
 
170 cycrow 723
		if (!file->GetData())
6 cycrow 724
			continue;
725
 
726
		// compress the file
170 cycrow 727
		if (!file->CompressData(m_SHeader2.iDataCompression, progress))
6 cycrow 728
		{
729
			file->SetDataCompression(SPKCOMPRESS_NONE);
730
			file->SetUncompressedDataSize(file->GetDataSize());
731
		}
732
 
170 cycrow 733
		Utils::String command = GetFileTypeString(file->GetFileType());
734
		if (command.empty())
6 cycrow 735
			continue;
736
 
170 cycrow 737
		if (file->IsShared())
738
			command = "$" + command;
6 cycrow 739
 
170 cycrow 740
		if (file->dir().empty())
178 cycrow 741
			line += command + ":" + (file->GetDataSize() + (long)4) + ":" + file->uncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->filename() + ":NULL:" + (long)file->game() + "\n";
6 cycrow 742
		else
178 cycrow 743
			line += command + ":" + (file->GetDataSize() + (long)4) + ":" + file->uncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->filename() + ":" + file->dir() + ":" + (long)file->game() + "\n";
6 cycrow 744
 
175 cycrow 745
		if (header)
6 cycrow 746
		{
175 cycrow 747
			++header->iNumFiles;
748
			header->lFullSize += (file->GetDataSize() + 4);
6 cycrow 749
		}
750
	}
751
 
752
	return line;
753
}
754
 
755
/*
756
######################################################################################
757
##########							Reading Functions			    		##########
758
######################################################################################
759
*/
760
 
761
void CBaseFile::ReadAllFilesToMemory ()
762
{
763
	// no file to read from
50 cycrow 764
	if ( this->filename().empty() ) return;
6 cycrow 765
 
766
	// now open the file
58 cycrow 767
	CFileIO File(this->filename());
768
	if ( !File.startRead() ) return;
6 cycrow 769
 
770
	// read the header
58 cycrow 771
	File.readEndOfLine();
6 cycrow 772
	// skip past values
58 cycrow 773
	File.seek(4 + m_SHeader.lValueCompressSize);
6 cycrow 774
 
775
	// read the next header
58 cycrow 776
	File.readEndOfLine();
6 cycrow 777
	// skip past files
58 cycrow 778
	File.seek(4 + m_SHeader2.lSize);
6 cycrow 779
 
780
	if ( m_pIconFile )
781
	{
782
		if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
51 cycrow 783
			m_pIconFile->readFromFile(File, m_pIconFile->GetDataSize());
6 cycrow 784
		else
58 cycrow 785
			File.seek(4 + m_pIconFile->GetDataSize());
6 cycrow 786
	}
787
 
788
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
789
	{
790
		C_File *fit = node->Data();
791
		if ( (!fit->GetData()) && (!fit->Skip()) )
51 cycrow 792
			fit->readFromFile(File, fit->GetDataSize());
6 cycrow 793
		else
58 cycrow 794
			File.seek(4 + fit->GetDataSize());
6 cycrow 795
	}
796
 
51 cycrow 797
	File.close();
6 cycrow 798
}
799
 
800
bool CBaseFile::ReadFileToMemory(C_File *f)
801
{
62 cycrow 802
	if ( this->filename().empty() || !f ) return false;		// no filename to load from
51 cycrow 803
	if ( f->GetData() && f->GetDataSize() ) return true;	// already loaded the data
804
	if ( !m_lFiles.FindData(f) ) return false;				// unable to find file entry
6 cycrow 805
 
806
	// now open the file
58 cycrow 807
	CFileIO *File = _startRead();
808
	if ( !File ) return false;
6 cycrow 809
 
58 cycrow 810
	if ( m_pIconFile ) File->seek(4 + m_pIconFile->GetDataSize());
51 cycrow 811
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
6 cycrow 812
		C_File *fit = node->Data();
51 cycrow 813
		if (fit == f ) {
58 cycrow 814
			fit->readFromFile(*File, fit->GetDataSize());
6 cycrow 815
			break;
816
		}
58 cycrow 817
		else File->seek(4 + fit->GetDataSize());
6 cycrow 818
	}
819
 
58 cycrow 820
	delete File;
6 cycrow 821
	return true;
822
}
823
 
58 cycrow 824
CFileIO *CBaseFile::_startRead()
6 cycrow 825
{
826
	// no file to read from
58 cycrow 827
	if ( this->filename().empty() ) return NULL;
6 cycrow 828
 
829
	// now open the file
58 cycrow 830
	CFileIO *File = new CFileIO(this->filename());
831
	if ( !File->startRead() ) return NULL;
6 cycrow 832
 
833
	// read the header
58 cycrow 834
	File->readEndOfLine();
6 cycrow 835
	// skip past values
58 cycrow 836
	File->seek(4 + m_SHeader.lValueCompressSize);
6 cycrow 837
 
838
	// read the next header
58 cycrow 839
	File->readEndOfLine();
6 cycrow 840
	// skip past files
58 cycrow 841
	File->seek(4 + m_SHeader2.lSize);
6 cycrow 842
 
58 cycrow 843
	return File;
844
}
6 cycrow 845
 
88 cycrow 846
void CBaseFile::_addFile(C_File *file, bool dontChange)
847
{
848
	if ( !dontChange ) {
849
		file->UpdateSigned();
850
		_changed();
851
	}
852
	m_lFiles.push_back(file);
853
 
854
	_updateTextDB(file);
855
}
856
 
857
void CBaseFile::_updateTextDB(C_File *file)
858
{
859
	if ( !_pTextDB ) _pTextDB = new CTextDB();
860
 
861
	if ( file->GetFileType() == FILETYPE_TEXT ) {
862
		Utils::String baseFile = CFileIO(file->filePointer()).baseName();
863
		int lang = (baseFile.isin("-L")) ? baseFile.right(3) : baseFile.truncate(-4);
864
 
865
		// read in the text file to the database
866
		_pTextDB->parseTextFile(0, 0, file->filePointer(), lang);
867
	}
868
}
869
 
870
void CBaseFile::_resetTextDB()
871
{
872
	if ( _pTextDB ) delete _pTextDB;
873
	_pTextDB = new CTextDB();
874
 
875
	for(CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next()) {
876
		_updateTextDB(node->Data());
877
	}
878
}
879
 
58 cycrow 880
void CBaseFile::ReadIconFileToMemory ()
881
{
882
	if ( !m_pIconFile )	return;
883
	CFileIO *File = _startRead();
884
	if ( !File ) return;
885
 
886
	if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
887
		m_pIconFile->readFromFile(*File, m_pIconFile->GetDataSize());
888
	else
889
		File->seek(4 + m_pIconFile->GetDataSize());
890
 
891
	delete File;
6 cycrow 892
}
893
 
14 cycrow 894
void CBaseFile::_install_adjustFakePatches(CPackages *pPackages)
6 cycrow 895
{
175 cycrow 896
	Utils::CStringList lPatches;
182 cycrow 897
	int startfake = pPackages->findNextFakePatch();
6 cycrow 898
 
14 cycrow 899
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
900
	{
901
		C_File *fit = node->Data();
902
		// only do fake patchs
903
		if ( !fit->IsFakePatch() )
904
			continue;
905
 
906
		// we should only have cat and dat files, but lets check just incase they have been added incorrectly
178 cycrow 907
		if ( !fit->checkFileExt ("cat") && !fit->checkFileExt("dat") )
14 cycrow 908
			continue;
909
 
910
		// search for the name on the list
175 cycrow 911
		Utils::String newname;
912
		bool isOpposite = false;
913
		if (lPatches.contains(fit->baseName()))
914
		{
915
			newname = lPatches.findString(fit->baseName());
916
			isOpposite = true;
917
		}
14 cycrow 918
		else
919
		{
175 cycrow 920
			newname = Utils::String::PadNumber((long)startfake, 2);
921
			lPatches.pushBack(fit->baseName(), newname);
14 cycrow 922
		}
923
 
924
		// rename the file
925
		fit->FixOriginalName();
175 cycrow 926
		CLog::logf(CLog::Log_Install, 2, "Adjusting fake patch number, %s => %s", fit->getNameDirectory(this).c_str(), (newname + "." + fit->fileExt()).c_str());
927
		fit->setName(newname + "." + fit->fileExt());
14 cycrow 928
 
929
		// find the next gap
175 cycrow 930
		if ( !isOpposite ) {
182 cycrow 931
			startfake = pPackages->findNextFakePatch(startfake + 1);
14 cycrow 932
		}
933
	}
934
}
935
 
43 cycrow 936
void CBaseFile::_install_renameText(CPackages *pPackages)
14 cycrow 937
{
130 cycrow 938
	int starttext = pPackages->findNextTextFile();
43 cycrow 939
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
940
		C_File *fit = node->Data();
130 cycrow 941
		if ( !fit->isAutoTextFile() )
43 cycrow 942
			continue;
6 cycrow 943
 
130 cycrow 944
		Utils::String newname = SPK::FormatTextName(starttext, pPackages->GetLanguage(), (pPackages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));
43 cycrow 945
		fit->FixOriginalName();
130 cycrow 946
		CLog::logf(CLog::Log_Install, 2, "Adjusting text file, %s => %s", fit->getNameDirectory(this).c_str(), (newname + "." + fit->fileExt()).c_str());
947
		fit->setName(newname + "." + fit->fileExt());
6 cycrow 948
 
43 cycrow 949
		++starttext;
950
	}
951
}
6 cycrow 952
 
50 cycrow 953
bool CBaseFile::_install_setEnabled(bool bEnable, C_File *fit)
954
{
955
	if ( !bEnable )
956
	{
957
		if ( (fit->GetFileType() == FILETYPE_UNINSTALL) || (fit->GetFileType() == FILETYPE_README) || (fit->GetFileType() == FILETYPE_ADVERT) )
958
			bEnable = true;
178 cycrow 959
		else if ( (fit->GetFileType() == FILETYPE_EXTRA) && (fit->dir().left(7).lower() == "Extras/") )
50 cycrow 960
			bEnable = true;
961
		else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )
962
			bEnable = true;
963
 
964
		if ( bEnable ) CLog::logf(CLog::Log_Install, 3, "Filetype(%d) is always enabled, setting enabled flag", fit->GetFileType());
965
	}
966
 
967
	return bEnable;
968
}
969
 
175 cycrow 970
bool CBaseFile::_install_uncompress(C_File *fit, CProgressInfo *progress, Utils::CStringList *errorStr, bool *uncomprToFile)
50 cycrow 971
{
972
	*uncomprToFile = false;
134 cycrow 973
	_sLastError = fit->getNameDirectory(this);
974
	_iLastError = SPKERR_UNCOMPRESS;
96 cycrow 975
 
50 cycrow 976
	if ( !fit->UncompressData ( progress ) )
977
	{
978
		CLog::log(CLog::Log_Install, 2, "Failed to uncompress data, attempting file decompression");
979
		if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP )
980
		{
178 cycrow 981
			if ( fit->uncompressToFile(Utils::String::Null(), this, false, progress ) )
50 cycrow 982
				*uncomprToFile = true;
983
		}
984
 
985
		if ( !uncomprToFile )
986
		{
987
			if ( errorStr )
175 cycrow 988
				errorStr->pushBack(_sLastError, ERRORLOG(SPKINSTALL_UNCOMPRESS_FAIL));
50 cycrow 989
			CLog::log(CLog::Log_Install, 1, "Unable to decompress file, skipping");
990
			return false;
991
		}
992
	}
993
	ClearError ();
994
 
995
	return true;
996
}
997
 
998
bool CBaseFile::_install_checkVersion(C_File *pFile, const Utils::String &sDestination)
999
{
1000
	// new check if we should install the file
1001
	// first get the version
1002
	if ( !m_bOverrideFiles && pFile->ReadScriptVersion() )
1003
	{
1004
		CLog::log(CLog::Log_Install, 2, "Checking for existing file version");
1005
		C_File checkfile;
175 cycrow 1006
		Utils::String checkfilename = sDestination;
1007
		if ( !checkfilename.empty() ) checkfilename += "/";
1008
		checkfilename += pFile->getNameDirectory(this);
1009
		checkfile.setFilename(checkfilename);
127 cycrow 1010
		checkfile.setFileType(pFile->fileType());
50 cycrow 1011
		if ( checkfile.CheckValidFilePointer() ) {
1012
			if ( checkfile.ReadScriptVersion() > pFile->GetVersion() ) {
1013
				CLog::log(CLog::Log_Install, 1, "Newer version of the file found in directory, skipping");
1014
				return false;
1015
			}
1016
		}
1017
	}
1018
 
1019
	return true;
1020
}
1021
 
1022
Utils::String CBaseFile::_install_adjustFilepointer(C_File *pFile, bool bEnabled, const Utils::String &sDestination)
1023
{
130 cycrow 1024
	Utils::String filename = sDestination;
1025
	if ( !filename.empty() ) filename += "/";
50 cycrow 1026
 
130 cycrow 1027
	if ( (IsPatch()) && (pFile->fileType() == FILETYPE_MOD) )
175 cycrow 1028
		pFile->setDir("Patch");
50 cycrow 1029
 
160 cycrow 1030
	if ( pFile->isInMod() )
50 cycrow 1031
	{
1032
		if ( bEnabled )
160 cycrow 1033
			pFile->setFilename(filename + pFile->getInMod() + "::" + pFile->getNameDirectory(this));
50 cycrow 1034
		else
130 cycrow 1035
			pFile->setFilename(filename + "PluginManager/DisabledFiles.cat::" + pFile->getNameDirectory(this));
50 cycrow 1036
	}
1037
	else
130 cycrow 1038
		pFile->setFilename ( filename + pFile->getNameDirectory(this) );
50 cycrow 1039
 
1040
	if ( !bEnabled )
1041
	{
160 cycrow 1042
		if ( !pFile->isInMod() )
50 cycrow 1043
		{
1044
			if ( pFile->IsFakePatch() )
130 cycrow 1045
				pFile->setFilename ( filename + "PluginManager/Disabled/FakePatches/FakePatch_" + this->getNameValidFile() + "_" + this->author() + "_" + pFile->name() );
1046
			else if ( pFile->isAutoTextFile() )
1047
				pFile->setFilename ( filename + "PluginManager/Disabled/TextFiles/Text_" + this->getNameValidFile() + "_" + this->author() + "_" + pFile->name() );
50 cycrow 1048
			else
178 cycrow 1049
				pFile->setFullDir ( filename + "PluginManager/Disabled/" + pFile->getDirectory(this) );
50 cycrow 1050
		}
1051
		pFile->SetDisabled(true);
1052
	}
1053
 
129 cycrow 1054
	CLog::logf(CLog::Log_Install, 2, "Adjusting the file pointer to correct install destintation, %s", pFile->filePointer().c_str());
50 cycrow 1055
 
130 cycrow 1056
	return filename;
50 cycrow 1057
}
1058
 
175 cycrow 1059
C_File *CBaseFile::_install_checkFile(C_File *pFile, Utils::CStringList *errorStr, bool *bDoFile, CLinkList<C_File> *pFileList)
50 cycrow 1060
{
1061
	if ( !pFile->IsFakePatch() && pFile->GetFileType() != FILETYPE_README )
1062
	{
1063
		C_File *cFile;
1064
		for ( cFile = pFileList->First(); cFile; cFile = pFileList->Next() )
1065
		{
1066
			if ( !cFile->MatchFile(pFile) ) continue;
1067
			if ( !m_bOverrideFiles && !cFile->CompareNew(pFile) ) {
175 cycrow 1068
				if ( errorStr ) errorStr->pushBack(pFile->getNameDirectory(this), ERRORLOG(SPKINSTALL_SKIPFILE));
50 cycrow 1069
				CLog::log(CLog::Log_Install, 1, "Newer version of the file already installed, skipping");
1070
				*bDoFile = false;
1071
			}
1072
			break;
1073
		}
1074
 
1075
		return cFile;
1076
	}
1077
 
1078
	return NULL;
1079
}
1080
 
175 cycrow 1081
bool CBaseFile::_install_checkFileEnable(C_File *pCheckFile, C_File *fit, const Utils::String &sDestination, bool bEnabled, Utils::CStringList *errorStr)
50 cycrow 1082
{
1083
	// found a file, check if its in the disabled directory
125 cycrow 1084
	Utils::String dir = CFileIO(pCheckFile->filePointer()).dir();
1085
	Utils::String lastDir = CDirIO(dir).topDir().lower();
50 cycrow 1086
 
1087
	// if its disabled, rename it so its enabled
125 cycrow 1088
	if ( ((pCheckFile->IsDisabled()) || (lastDir == "disabled") || (dir.lower().isin("/disabled/"))) && (bEnabled) )
50 cycrow 1089
	{
125 cycrow 1090
		CLog::logf(CLog::Log_Install, 2, "Existing file, %s, is disabled, re-enabling it", pCheckFile->filePointer().c_str());
50 cycrow 1091
		// first check if the directory exists
160 cycrow 1092
		if ( pCheckFile->isInMod() ) {
175 cycrow 1093
			Utils::String tofile = pCheckFile->filePointer().token("::", 2);
50 cycrow 1094
 
1095
			CCatFile tocat;
125 cycrow 1096
			int err = tocat.open(fit->filePointer().token("::", 1), "", CATREAD_CATDECRYPT, true);
50 cycrow 1097
			if ( (err == CATERR_NONE) || (err == CATERR_CREATED) ) {
181 cycrow 1098
				tocat.appendFile(pCheckFile->filePointer(), tofile);
125 cycrow 1099
				CLog::logf(CLog::Log_Install, 2, "Adding existing file into new mod File, %s => %s", fit->filePointer().token("::", 1).c_str(), tofile.c_str());
50 cycrow 1100
			}
1101
 
1102
			CCatFile fromcat;
125 cycrow 1103
			err = fromcat.open(pCheckFile->filePointer().token("::", 1), "", CATREAD_CATDECRYPT, false);
50 cycrow 1104
			if ( err == CATERR_NONE ) {
175 cycrow 1105
				fromcat.removeFile(tofile);
125 cycrow 1106
				CLog::logf(CLog::Log_Install, 2, "Removing file from existing mod, %s::%s", pCheckFile->filePointer().token("::", 1).c_str(), tofile.c_str());
50 cycrow 1107
			}
1108
 
125 cycrow 1109
			CLog::logf(CLog::Log_Install, 1, "Adjusting existing file name %s => %s", pCheckFile->filePointer().c_str(), fit->filePointer().c_str());
178 cycrow 1110
			pCheckFile->setFilename(fit->filePointer());
160 cycrow 1111
			CLog::logf(CLog::Log_Install, 2, "Adjusting In Mod setting, %s => %s", pCheckFile->getInMod().c_str(), fit->getInMod().c_str());
1112
			pCheckFile->setInMod(fit->getInMod());
50 cycrow 1113
		}
1114
		else {
160 cycrow 1115
			Utils::String to = pCheckFile->getDirectory(this);
50 cycrow 1116
			CDirIO Dir(sDestination);
160 cycrow 1117
			if ( !Dir.exists(to) ) {
1118
				if ( !Dir.create ( to ) ) {
175 cycrow 1119
					if ( errorStr )	errorStr->pushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
50 cycrow 1120
					return false;
1121
				}
175 cycrow 1122
				if ( errorStr )	errorStr->pushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
50 cycrow 1123
			}
1124
 
175 cycrow 1125
			Utils::String destfile = sDestination + "/" + pCheckFile->getNameDirectory(this);
1126
			if ( CFileIO(destfile).ExistsOld() ) CFileIO::Remove(destfile);
178 cycrow 1127
			CLog::logf(CLog::Log_Install, 1, "Adjusting existing filename, %s => %s", pCheckFile->filePointer().c_str(), destfile.c_str());
175 cycrow 1128
			rename ( pCheckFile->filePointer().c_str(), destfile.c_str() );
1129
			pCheckFile->setFilename (sDestination + "/" + pCheckFile->getNameDirectory(this) );
50 cycrow 1130
		}
1131
		pCheckFile->SetDisabled(false);
1132
 
175 cycrow 1133
		if ( errorStr ) errorStr->pushBack(pCheckFile->getNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));
50 cycrow 1134
	}
1135
 
1136
	return true;
1137
}
51 cycrow 1138
 
175 cycrow 1139
bool CBaseFile::_install_createDirectory(CDirIO &Dir, const Utils::String &sTo, C_File *pFile, Utils::CStringList *errorStr)
51 cycrow 1140
{
134 cycrow 1141
	_sLastError = sTo;
1142
	if ( !sTo.contains( "::" ) )
51 cycrow 1143
	{
121 cycrow 1144
		if ( !Dir.exists(sTo) )
51 cycrow 1145
		{
1146
			CLog::logf(CLog::Log_Install, 2, "Creating directory to install file into, %s", sTo.c_str());
160 cycrow 1147
			if ( !Dir.create(sTo) )
51 cycrow 1148
			{
1149
				if ( errorStr )
175 cycrow 1150
					errorStr->pushBack(sTo, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
51 cycrow 1151
				return false;
1152
			}
1153
			if ( errorStr )
175 cycrow 1154
				errorStr->pushBack(sTo, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
51 cycrow 1155
		}
1156
	}
1157
	else {
129 cycrow 1158
		CLog::logf(CLog::Log_Install, 2, "Adjusting file extension for file in mod, %s => %s", pFile->filePointer().c_str(), CCatFile::PckChangeExtension(pFile->filePointer()).c_str());
134 cycrow 1159
		pFile->setFilename(CCatFile::PckChangeExtension(pFile->filePointer()));
51 cycrow 1160
	}
1161
 
1162
	return true;
1163
}
1164
 
175 cycrow 1165
void CBaseFile::_install_writeFile(C_File *pFile, const Utils::String &sDestination, Utils::CStringList *errorStr)
51 cycrow 1166
{
134 cycrow 1167
	_iLastError = SPKERR_WRITEFILE;
1168
	_sLastError = pFile->filePointer();
1169
	Utils::String sInstalledFile = pFile->getNameDirectory(this);
51 cycrow 1170
	if ( pFile->IsDisabled() )
1171
	{
134 cycrow 1172
		sInstalledFile = pFile->filePointer().findRemove(sDestination);
51 cycrow 1173
		if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )
134 cycrow 1174
			sInstalledFile.erase(0, 1);
51 cycrow 1175
	}
1176
 
129 cycrow 1177
	if ( !pFile->writeFilePointer() )
51 cycrow 1178
	{
1179
		CLog::log(CLog::Log_Install, 1, "Failed to write the file");
1180
		if ( errorStr )
175 cycrow 1181
			errorStr->pushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));
51 cycrow 1182
	}
1183
	else
1184
	{
1185
		CLog::log(CLog::Log_Install, 1, "File written successfully");
1186
		CLog::log(CLog::Log_Install, 2, "Checking signed status of the file");
1187
		pFile->UpdateSigned();
1188
		if ( errorStr )
175 cycrow 1189
			errorStr->pushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));
51 cycrow 1190
 
1191
		switch(pFile->GetFileType())
1192
		{
1193
			case FILETYPE_SCRIPT:
1194
			case FILETYPE_UNINSTALL:
1195
				CLog::log(CLog::Log_Install, 2, "Updating file signature");
160 cycrow 1196
				pFile->updateSignature();
51 cycrow 1197
				break;
1198
		}
1199
	}
1200
}
1201
 
175 cycrow 1202
bool CBaseFile::installFiles(const Utils::String &destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, Utils::CStringList *errorStr, bool enabled, CPackages *packages )
43 cycrow 1203
{
50 cycrow 1204
	//TODO: add errorStr and progress as member variables
43 cycrow 1205
	if ( enabled ) {
14 cycrow 1206
		this->_install_adjustFakePatches(packages);
43 cycrow 1207
		if ( packages ) this->_install_renameText(packages);
6 cycrow 1208
	}
1209
 
50 cycrow 1210
	bool bFailed = false;
1211
 
6 cycrow 1212
	CDirIO Dir(destdir);
1213
	int fileCount = 0;
1214
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1215
	{
1216
		C_File *fit = node->Data();
1217
 
50 cycrow 1218
		// start the install process, check if we need to the file enabled or disabled
178 cycrow 1219
		CLog::logf(CLog::Log_Install, 1, "Preparing to install file: %s", fit->getNameDirectory(this).c_str());
50 cycrow 1220
		bool fileEnabled = _install_setEnabled(enabled, fit);
1221
 
1222
		// check if the file is for the correct game version
147 cycrow 1223
		if (!fit->isForGame(packages->GetGame())) 
1224
		{
1225
			CLog::logf(CLog::Log_Install, 1, "File didn't match game version, skipping, %d != %d", fit->game(), packages->GetGame());
1226
			continue;
6 cycrow 1227
		}
1228
 
50 cycrow 1229
		// update the progress display to show we are processing this file
1230
		if ( progress ) {
1231
			if ( progress->IsSecond() ) progress->SwitchSecond();
6 cycrow 1232
			progress->UpdateFile ( fit );
1233
			progress->UpdateProgress(fileCount++, m_lFiles.size());
1234
			progress->SwitchSecond();
1235
		}
1236
 
1237
		// first uncompress the file
50 cycrow 1238
		//TODO: add this flag to C_File
1239
		bool uncomprToFile;
1240
		if ( !this->_install_uncompress(fit, progress, errorStr, &uncomprToFile) ) {
1241
			bFailed = true;
1242
			continue;
6 cycrow 1243
		}
1244
 
175 cycrow 1245
		bool dofile = _install_checkVersion(fit, destdir);
6 cycrow 1246
 
1247
		// change file pointer
175 cycrow 1248
		Utils::String sInstallDir = _install_adjustFilepointer(fit, fileEnabled, destdir);
6 cycrow 1249
 
1250
		C_File *adjustPointer = NULL;
1251
 
50 cycrow 1252
		if ( filelist ) {
98 cycrow 1253
			C_File *cFile = _install_checkFile(fit, errorStr, &dofile, filelist);
6 cycrow 1254
 
1255
			// no matching file found, adding to main list
50 cycrow 1256
			if ( !cFile ) filelist->push_back ( fit );
6 cycrow 1257
			else
1258
			{
1259
				// if the file is not enabled, we need to check for any that might be enabled
51 cycrow 1260
				if ( !fileEnabled ) //_install_checkDisabled(cFile, destdir, errorStr);
6 cycrow 1261
				{
50 cycrow 1262
					//TODO: check what this is actually doing
160 cycrow 1263
					if ( !cFile->getUsed() )
6 cycrow 1264
					{
160 cycrow 1265
						CFileIO rFile(cFile->filePointer());
52 cycrow 1266
						if ( rFile.exists() )
6 cycrow 1267
						{
1268
							if ( errorStr )
1269
							{
52 cycrow 1270
								if ( rFile.remove() )
175 cycrow 1271
									errorStr->pushBack(cFile->filePointer().findRemove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));
6 cycrow 1272
								else
175 cycrow 1273
									errorStr->pushBack(cFile->filePointer().findRemove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));
6 cycrow 1274
							}
1275
						}
160 cycrow 1276
						cFile->setFilename(fit->filePointer());
6 cycrow 1277
						cFile->SetDisabled(true);
1278
					}
1279
					else
1280
					{
160 cycrow 1281
						fit->setFullDir(sInstallDir + fit->getDirectory(this));
51 cycrow 1282
						fit->SetDisabled(false);
6 cycrow 1283
					}
1284
				}
1285
				// move it to enabled
50 cycrow 1286
				else {
175 cycrow 1287
					if ( !this->_install_checkFileEnable(cFile, fit, destdir, fileEnabled, errorStr) ) {
50 cycrow 1288
						bFailed = true;
1289
						continue;
6 cycrow 1290
					}
1291
				}
1292
 
1293
				adjustPointer = cFile;
50 cycrow 1294
				if ( dofile ) adjustPointer->SetCreationTime(fit->GetCreationTime());
6 cycrow 1295
			}
1296
		}
1297
 
1298
		if ( dofile )
1299
		{
1300
			// uncompressed to file, rename and move
1301
			if ( uncomprToFile )
1302
			{
134 cycrow 1303
				_iLastError = SPKERR_WRITEFILE;
1304
				Utils::String to = fit->getDirectory(this);
1305
				if ( !fileEnabled )	to = "PluginManager/Disabled/" + to;
6 cycrow 1306
 
134 cycrow 1307
				if ( !_install_createDirectory(Dir, to, fit, errorStr) ) {
51 cycrow 1308
					bFailed = true;
1309
					continue;
6 cycrow 1310
				}
1311
 
1312
				int err = 1;
134 cycrow 1313
				_sLastError = to;
160 cycrow 1314
				if ( !fit->getTempFile().empty())	err = rename ( fit->getTempFile().c_str(), to.c_str() );
51 cycrow 1315
				if ( err ) {
1316
					bFailed = true;
1317
					continue;
1318
				}
6 cycrow 1319
			}
1320
			//otherwise, just extract the file
1321
			else
1322
			{
1323
				// old file is found in list, switch to using new one
50 cycrow 1324
				if ( (filelist) && (adjustPointer) ) {
6 cycrow 1325
					adjustPointer->CopyData(fit, false);
50 cycrow 1326
					CLog::log(CLog::Log_Install, 2, "Copying data into existing file");
1327
				}
6 cycrow 1328
 
134 cycrow 1329
				Utils::String fpointer = fit->filePointer();
1330
				_iLastError = SPKERR_CREATEDIRECTORY;
1331
				Utils::String dir = CFileIO(fit->filePointer()).dir();
6 cycrow 1332
 
175 cycrow 1333
				dir = dir.findRemove(destdir);
149 cycrow 1334
				if (!dir.empty() && (dir[0] == '/' || dir[0] == '\\')) 
1335
					dir.erase(0, 1);
6 cycrow 1336
 
134 cycrow 1337
				if ( !_install_createDirectory(Dir, dir, fit, errorStr) ) {
51 cycrow 1338
					bFailed = true;
1339
					continue;
6 cycrow 1340
				}
1341
 
175 cycrow 1342
				_install_writeFile(fit, destdir, errorStr);
6 cycrow 1343
			}
1344
			ClearError ();
1345
		}
1346
 
1347
		if ( adjustPointer )
1348
		{
50 cycrow 1349
			CLog::log(CLog::Log_Install, 2, "Adjusting pointers to existing file and deleting new file pointer");
6 cycrow 1350
			node->ChangeData(adjustPointer);
1351
			delete fit;
1352
		}
50 cycrow 1353
 
1354
		CLog::log(CLog::Log_Install, 1, "File installation completed");
6 cycrow 1355
	}
1356
 
1357
	// now clear or data memory
50 cycrow 1358
	CLog::log(CLog::Log_Install, 2, "Delting temporary file data from memory");
51 cycrow 1359
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) node->Data()->DeleteData();
6 cycrow 1360
 
50 cycrow 1361
	return !bFailed;
6 cycrow 1362
}
1363
 
1364
/*######################################################################################################*/
1365
 
1366
 
1367
/*
1368
	Func:   ParseHeader
1369
	Input:  Header String - string formated directly from the file
1370
	Return: Boolean - If string is a valid header
1371
	Desc:   Splits up the main header string to get all required settings
1372
*/
175 cycrow 1373
bool CBaseFile::_parseHeader(const Utils::String &header)
6 cycrow 1374
{
175 cycrow 1375
	if ( !this->_checkHeader(header.token(";", 1)))
6 cycrow 1376
		return false;
1377
 
175 cycrow 1378
	m_SHeader.fVersion = header.token(";", 2).toFloat();
6 cycrow 1379
	if ( m_SHeader.fVersion > FILEVERSION )
1380
		return false;
1381
 
175 cycrow 1382
	m_SHeader.iValueCompression = header.token(";", 3).toInt();
1383
	m_SHeader.lValueCompressSize = header.token(";", 4).toLong();
6 cycrow 1384
 
1385
	return true;
1386
}
1387
 
175 cycrow 1388
bool CBaseFile::_checkHeader(const Utils::String header) const
6 cycrow 1389
{
1390
	if ( header.Compare("BaseCycrow") )
1391
		return true;
1392
	return false;
1393
}
1394
 
1395
/*
1396
	Func:   ParseFileHeader
1397
	Input:  Header String - string formated directly from the file
1398
	Return: Boolean - If string is a valid header
1399
	Desc:   Splits up the file header string to get all required settings
1400
*/
175 cycrow 1401
bool CBaseFile::_parseFileHeader(const Utils::String &header)
6 cycrow 1402
{
175 cycrow 1403
	if (header.token(";", 1) != "FileHeader")
6 cycrow 1404
		return false;
1405
 
175 cycrow 1406
	m_SHeader2.iNumFiles = header.token(";", 2).toInt();
1407
	m_SHeader2.lSize = header.token(";", 3).toInt();
1408
	m_SHeader2.lFullSize = header.token(";", 4).toInt();
1409
	m_SHeader2.iFileCompression = header.token(";", 5).toInt();
1410
	m_SHeader2.iDataCompression = header.token(";", 6).toInt();
6 cycrow 1411
 
1412
	return true;
1413
}
1414
 
1415
 
1416
/*
1417
	Func:   ParseValueLine
1418
	Input:  String - single line from a file to set
1419
	Return: Boolean - returns true if value exists
1420
	Desc:   Reads the line and assigns the parameters for the file
1421
*/
14 cycrow 1422
bool CBaseFile::ParseValueLine(const Utils::String &sLine)
6 cycrow 1423
{
14 cycrow 1424
	Utils::String first = sLine.token(" ", 1);
1425
	Utils::String rest  = sLine.tokens(" ", 2);
6 cycrow 1426
 
50 cycrow 1427
	if ( first.Compare("Name:") )					this->setName(rest);
1428
	else if ( first.Compare("Author:") )			this->setAuthor(rest);
1429
	else if ( first.Compare("Version:") )			this->setVersion(rest);
14 cycrow 1430
	else if ( first.Compare("fGameVersion:") ) {
6 cycrow 1431
		if ( m_lGames.Back() ) {
1432
			m_lGames.Back()->Data()->sVersion = rest;
1433
		}
1434
	}
14 cycrow 1435
	else if ( first.Compare("GameVersion:") ) {
6 cycrow 1436
		if ( m_lGames.Back() ) {
14 cycrow 1437
			m_lGames.Back()->Data()->iVersion = rest;
6 cycrow 1438
		}
1439
	}
14 cycrow 1440
	else if ( first.Compare("Game:") )
46 cycrow 1441
		this->AddGameCompatability(rest, "");
14 cycrow 1442
	else if ( first.Compare("GameCompat:") )
1443
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
1444
	else if ( first.Compare("GameCompatExact:") )
1445
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
50 cycrow 1446
	else if ( first.Compare("Date:") )				this->setCreationDate(rest);
49 cycrow 1447
	else if ( first.Compare("WebAddress:") )		this->setWebAddress(rest);
1448
	else if ( first.Compare("WebSite:") )			this->setWebSite(rest);
1449
	else if ( first.Compare("Email:") )				this->setEmail(rest);
14 cycrow 1450
	else if ( first.Compare("WebMirror1:") || first.Compare("Mirror1:") || first.Compare("WebMirror:") )
162 cycrow 1451
		this->addWebMirror(rest);
14 cycrow 1452
	else if ( first.Compare("WebMirror2:") || first.Compare("Mirror2:") )
162 cycrow 1453
		this->addWebMirror(rest);
48 cycrow 1454
	else if ( first.Compare("PluginType:") )		this->setPluginType(rest);
1455
	else if ( first.Compare("Desc:") )				this->setDescription(rest);
1456
	else if ( first.Compare("UninstallAfter:") )	this->addUninstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));
1457
	else if ( first.Compare("UninstallBefore:") )	this->addUninstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));
1458
	else if ( first.Compare("InstallAfter:") )		this->addInstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));
1459
	else if ( first.Compare("InstallBefore:") )		this->addInstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));
170 cycrow 1460
	else if ( first.Compare("ScriptName:") )		addName(ParseLanguage(rest.token(":", 1)), rest.token(":", 2));
48 cycrow 1461
	else if ( first.Compare("GameChanging:") )		this->setGameChanging(rest);
1462
	else if ( first.Compare("EaseOfUse:") )			this->setEaseOfUse(rest);
1463
	else if ( first.Compare("Recommended:") )		this->setRecommended(rest);
14 cycrow 1464
	else if ( first.Compare("NeededLibrary:") )
1465
		this->AddNeededLibrary(rest.token("||", 1), rest.token("||", 2), rest.token("||", 3));
1466
	else if ( first.Compare("FakePatchBefore:") )
160 cycrow 1467
		this->addFakePatchOrder(false, rest.token("||", 1), rest.token("||", 2));
14 cycrow 1468
	else if ( first.Compare("FakePatchAfter:") )
160 cycrow 1469
		this->addFakePatchOrder(true, rest.token("||", 1), rest.token("||", 2));
49 cycrow 1470
	else if ( first.Compare("ForumLink:") )			this->setForumLink(rest);
6 cycrow 1471
	else
1472
		return false;
1473
 
1474
	return true;
1475
}
1476
 
48 cycrow 1477
int CBaseFile::ParseLanguage(const Utils::String &lang) const
6 cycrow 1478
{
48 cycrow 1479
	int langID = lang;
1480
	if ( !langID ) {
1481
		if ( lang.Compare("english") )		return 44;
1482
		else if ( lang.Compare("default") )	return 0;
1483
		else if ( lang.Compare("german") )	return 49;
1484
		else if ( lang.Compare("russian") )	return 7;
1485
		else if ( lang.Compare("spanish") )	return 34;
1486
		else if ( lang.Compare("french") )	return 33;
6 cycrow 1487
	}
1488
 
1489
	return langID;
1490
}
1491
 
1492
/*
1493
	Func:   ReadValues
1494
	Input:  String - values in one long line
1495
	Desc:   splits the values data into each line to read the data
1496
*/
175 cycrow 1497
void CBaseFile::_readValues(const Utils::String &values)
6 cycrow 1498
{
1499
	int num = 0;
175 cycrow 1500
	Utils::String *lines = values.tokenise("\n", &num);
6 cycrow 1501
 
1502
	for ( int i = 0; i < num; i++ )
175 cycrow 1503
		ParseValueLine(lines[i]);
6 cycrow 1504
 
1505
	CLEANSPLIT(lines, num)
1506
}
1507
 
1508
/*
1509
	Func:   ParseFilesLine
1510
	Input:  String - single line from a file to set
1511
	Return: Boolean - returns true if value exists
1512
	Desc:   Reads the line and assigns the parameters for the file
1513
*/
175 cycrow 1514
bool CBaseFile::_parseFilesLine(const Utils::String &line)
6 cycrow 1515
{
127 cycrow 1516
	if ( !line.contains(":") )
6 cycrow 1517
		return false;
1518
 
127 cycrow 1519
	Utils::String command = line.token(":", 1);
6 cycrow 1520
 
127 cycrow 1521
	long size = line.token(":", 2).toInt();
1522
	long usize = line.token(":", 3).toInt ();
1523
	long compression = line.token(":", 4).toInt ();
6 cycrow 1524
 
1525
	if ( command == "Icon" )
1526
	{
158 cycrow 1527
		_sIconExt = line.token (":", 5);
6 cycrow 1528
		m_pIconFile = new C_File ();
1529
		m_pIconFile->SetDataSize ( size - 4 );
1530
		m_pIconFile->SetDataCompression ( compression );
1531
		m_pIconFile->SetUncompressedDataSize ( usize );
1532
 
1533
		return true;
1534
	}
1535
 
127 cycrow 1536
	time_t time = line.token(":", 5).toLong();
1537
	bool compressToFile = (line.token(":", 6).toInt() == 1) ? true : false;
1538
	Utils::String name  = line.token(":", 7);
1539
	Utils::String dir = line.token(":", 8);
6 cycrow 1540
 
127 cycrow 1541
	if ( name.empty() )
6 cycrow 1542
		return true;
1543
 
1544
	bool shared = false;
127 cycrow 1545
	if ( command.left(1) == "$" )
6 cycrow 1546
	{
1547
		shared = true;
127 cycrow 1548
		command.erase(0, 1);
6 cycrow 1549
	}
1550
 
127 cycrow 1551
	FileType type = FILETYPE_UNKNOWN;
6 cycrow 1552
	if ( command == "Script" )
1553
		type = FILETYPE_SCRIPT;
1554
	else if ( command == "Text" )
1555
		type = FILETYPE_TEXT;
1556
	else if ( command == "Readme" )
1557
		type = FILETYPE_README;
1558
	else if ( command == "Map" )
1559
		type = FILETYPE_MAP;
1560
	else if ( command == "Mod" )
1561
		type = FILETYPE_MOD;
1562
	else if ( command == "Uninstall" )
1563
		type = FILETYPE_UNINSTALL;
1564
	else if ( command == "Sound" )
1565
		type = FILETYPE_SOUND;
1566
	else if ( command == "Mission" )
1567
		type = FILETYPE_MISSION;
1568
	else if ( command == "Extra" )
1569
		type = FILETYPE_EXTRA;
1570
	else if ( command == "Screen" )
1571
		type = FILETYPE_SCREEN;
1572
	else if ( command == "Backup" )
1573
		type = FILETYPE_BACKUP;
1574
	else if ( command == "Advert" )
1575
		type = FILETYPE_ADVERT;
1576
	else if ( command == "ShipScene" )
1577
		type = FILETYPE_SHIPSCENE;
1578
	else if ( command == "CockpitScene" )
1579
		type = FILETYPE_COCKPITSCENE;
1580
	else if ( command == "ShipOther" )
1581
		type = FILETYPE_SHIPOTHER;
1582
	else if ( command == "ShipModel" )
1583
		type = FILETYPE_SHIPMODEL;
1584
 
127 cycrow 1585
	if (type == FILETYPE_UNKNOWN)
6 cycrow 1586
		return false;
1587
 
127 cycrow 1588
	C_File *file = new C_File();
6 cycrow 1589
 
127 cycrow 1590
	if (dir.left(5).Compare("GAME_")) {
130 cycrow 1591
		unsigned int iGame = dir.token("_", 2).toInt();
1592
		if (!iGame)
1593
			file->setGame(0);
1594
		else
1595
			file->setGame(1 << 31 | 1 << iGame);
127 cycrow 1596
		dir = Utils::String::Null();
6 cycrow 1597
	} 
127 cycrow 1598
	else if ( line.countToken(":") >= 9 ) 
1599
	{
1600
		Utils::String game = line.token(":", 9);
1601
		if (game.contains("_"))
130 cycrow 1602
		{
1603
			unsigned int iGame = game.token("_", 2).toInt();
1604
			if (iGame)
1605
				file->setGame(1 << 31 | 1 << iGame);
1606
			else
1607
				file->setGame(0);
1608
		}
127 cycrow 1609
		else
1610
		{
1611
			int iGame = game.toInt();
1612
			if (iGame & (1 << 31))
1613
				file->setGame(iGame);
130 cycrow 1614
			else if (!iGame)
1615
				file->setGame(0);
127 cycrow 1616
			else
1617
				file->setGame(1 << 31 | 1 << iGame);
1618
		}
6 cycrow 1619
	}
1620
 
127 cycrow 1621
	if (dir.Compare("NULL")) {
1622
		dir = Utils::String::Null();
1623
	}
1624
 
1625
	file->setFileType(type);
6 cycrow 1626
	file->SetCreationTime ( time );
178 cycrow 1627
	file->setName(name);
1628
	file->setDir(dir);
6 cycrow 1629
	file->SetDataSize ( size - 4 );
1630
	file->SetDataCompression ( compression );
1631
	file->SetUncompressedDataSize ( usize );
1632
	file->SetShared ( shared );
1633
	file->SetCompressedToFile ( compressToFile );
1634
 
88 cycrow 1635
	_addFile(file, true);
6 cycrow 1636
 
1637
	return true;
1638
}
1639
 
1640
 
1641
/*
1642
	Func:   ParseFiles
1643
	Input:  String - values in one long line
1644
	Desc:   splits the files data into each line to read the data
1645
*/
175 cycrow 1646
void CBaseFile::_readFiles(const Utils::String &values)
6 cycrow 1647
{
1648
	int num = 0;
175 cycrow 1649
	Utils::String *lines = values.tokenise("\n", &num);
6 cycrow 1650
 
175 cycrow 1651
	for (int i = 0; i < num; i++)
1652
		_parseFilesLine(lines[i]);
6 cycrow 1653
 
1654
	CLEANSPLIT(lines, num)
1655
}
1656
 
1657
 
1658
 
1659
/*
1660
	Func:   ReadFile
1661
	Input:  filename - the name of the file to open and read
1662
			readdata - If falses, dont read the files to memory, just read the headers and values
1663
	Return: boolean - return ture if acceptable format
1664
	Desc:   Opens and reads the spk file and loads all data into class
1665
*/
130 cycrow 1666
bool CBaseFile::readFile(const Utils::String &filename, int readtype, CProgressInfo *progress)
1667
{
1668
	CFileIO File(filename);
58 cycrow 1669
	if ( !File.startRead() ) return false;
6 cycrow 1670
 
58 cycrow 1671
	bool ret = this->readFile(File, readtype, progress);
130 cycrow 1672
	if ( ret ) this->setFilename(filename);
6 cycrow 1673
 
58 cycrow 1674
	File.close();
6 cycrow 1675
	return ret;
1676
}
51 cycrow 1677
 
109 cycrow 1678
int CBaseFile::_read_Header(CFileIO &File, int iReadType, int iMaxProgress, CProgressInfo *pProgress)
6 cycrow 1679
{
51 cycrow 1680
	int doneLen = 0;
6 cycrow 1681
 
51 cycrow 1682
	// read data to memory
1683
	unsigned char *readData;
1684
	try {
1685
		readData = new unsigned char[m_SHeader.lValueCompressSize];
1686
	}
1687
	catch (std::exception &e) {
1688
		CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [header], %d (%s)", m_SHeader.lValueCompressSize, e.what());
1689
		return -1;
1690
	}
6 cycrow 1691
 
51 cycrow 1692
	unsigned char size[4];
109 cycrow 1693
	File.read(size, 4);
1694
	File.read(readData, m_SHeader.lValueCompressSize);
6 cycrow 1695
 
51 cycrow 1696
	unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
6 cycrow 1697
 
51 cycrow 1698
	// check for zlib compression
1699
	if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ) {
1700
		// uncomress the data
1701
		try {
6 cycrow 1702
			unsigned char *uncompr = new unsigned char[uncomprLen];
1703
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );
1704
			// update the progress for each section
51 cycrow 1705
			if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);
175 cycrow 1706
			if ( err == Z_OK ) this->_readValues((char *)uncompr);
6 cycrow 1707
			doneLen = uncomprLen;
1708
			delete uncompr;
1709
		}
51 cycrow 1710
		catch (std::exception &e) {
1711
			CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());
53 cycrow 1712
			delete []readData;
51 cycrow 1713
			return -1;
6 cycrow 1714
		}
51 cycrow 1715
	}
1716
	else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP ) {
1717
		long len = uncomprLen;
1718
		unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lValueCompressSize, (size_t*)&len, NULL );
1719
		// update the progress for each section
1720
		if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);
6 cycrow 1721
 
175 cycrow 1722
		if ( compr ) _readValues((char *)compr);
6 cycrow 1723
	}
51 cycrow 1724
	// no compression
1725
	else
175 cycrow 1726
		_readValues((char *)readData);
6 cycrow 1727
 
53 cycrow 1728
	delete []readData;
6 cycrow 1729
 
51 cycrow 1730
	return doneLen;
1731
}
6 cycrow 1732
 
109 cycrow 1733
int CBaseFile::_read_FileHeader(CFileIO &File, int iReadType, int iMaxProgress, int iDoneLen, CProgressInfo *pProgress)
51 cycrow 1734
{
1735
	unsigned char *readData;
1736
	try {
1737
		readData = new unsigned char[m_SHeader2.lSize];
1738
	}
1739
	catch (std::exception &e) {
1740
		CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [header], %d (%s)", m_SHeader2.lSize, e.what());
1741
		return -1;
1742
	}
6 cycrow 1743
 
51 cycrow 1744
	unsigned char size[4];
109 cycrow 1745
	File.read(size, 4);
1746
	File.read(readData, m_SHeader2.lSize);
6 cycrow 1747
 
51 cycrow 1748
	unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
6 cycrow 1749
 
51 cycrow 1750
	// check for zlib compression
1751
	if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ) {
1752
		if ( uncomprLen < (unsigned long)iDoneLen ) uncomprLen = iDoneLen;
6 cycrow 1753
 
51 cycrow 1754
		try {
6 cycrow 1755
			unsigned char *uncompr = new unsigned char[uncomprLen];
1756
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );
1757
			// update the progress for each section
51 cycrow 1758
			if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);
175 cycrow 1759
			if ( err == Z_OK ) _readFiles((char *)uncompr);
6 cycrow 1760
			delete uncompr;
1761
		}
51 cycrow 1762
		catch (std::exception &e) {
1763
			CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());
53 cycrow 1764
			delete []readData;
51 cycrow 1765
			return -1;
6 cycrow 1766
		}
1767
 
1768
	}
51 cycrow 1769
	else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
1770
	{
1771
		long len = uncomprLen;
1772
		unsigned char *compr = LZMADecode_C ( readData, m_SHeader2.lSize, (size_t*)&len, NULL );
1773
		// update the progress for each section
1774
		if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);
175 cycrow 1775
		if ( compr ) _readFiles((char *)compr);
51 cycrow 1776
	}
1777
	else
175 cycrow 1778
		_readFiles((char *)readData);
6 cycrow 1779
 
53 cycrow 1780
	delete []readData;
51 cycrow 1781
	return true;
1782
}
1783
 
58 cycrow 1784
bool CBaseFile::readFile(CFileIO &File, int readtype, CProgressInfo *progress)
51 cycrow 1785
{
1786
	ClearError ();
1787
 
1788
	// first read the header
175 cycrow 1789
	if ( !_parseHeader(File.readEndOfLine()) ) return false;
51 cycrow 1790
	if ( readtype == SPKREAD_HEADER ) return true;
1791
 
1792
	// update the progress for each section
1793
	int maxProgress = (readtype == SPKREAD_VALUES) ? 3 : 6;
1794
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(1, maxProgress);
1795
 
1796
	long doneLen = 0;
1797
	// next read the data values for the spk files
109 cycrow 1798
	if ( m_SHeader.lValueCompressSize ) doneLen = this->_read_Header(File, readtype, maxProgress, progress);
51 cycrow 1799
 
1800
	// update the progress for each section
1801
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(3, maxProgress);
1802
	if ( readtype == SPKREAD_VALUES ) return true;
1803
 
1804
	// next should be the next header
175 cycrow 1805
	if ( !_parseFileHeader(File.readEndOfLine()) ) return false;
51 cycrow 1806
 
1807
	// clear the current file list
1808
	m_lFiles.clear(true);
88 cycrow 1809
	if ( _pTextDB ) {
1810
		delete _pTextDB;
1811
		_pTextDB = NULL;
1812
	}
51 cycrow 1813
 
1814
	// update the progress for each section
1815
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(4, maxProgress);
1816
 
109 cycrow 1817
	if ( m_SHeader2.lSize ) this->_read_FileHeader(File, readtype, maxProgress, doneLen, progress);
51 cycrow 1818
 
6 cycrow 1819
	// file mismatch
1820
	long numfiles = m_lFiles.size();
51 cycrow 1821
	if ( m_pIconFile ) ++numfiles;
1822
	if ( m_SHeader2.iNumFiles != numfiles ) {
134 cycrow 1823
		_iLastError = SPKERR_FILEMISMATCH;
6 cycrow 1824
		return false;
1825
	}
1826
 
1827
	// update the progress for each section
51 cycrow 1828
	if ( readtype != SPKREAD_ALL && progress )	progress->UpdateProgress(6, maxProgress);
6 cycrow 1829
 
51 cycrow 1830
	if ( readtype == SPKREAD_ALL ) {
6 cycrow 1831
		int fileCount = 2;
58 cycrow 1832
		if ( m_pIconFile ) m_pIconFile->readFromFile(File, m_pIconFile->GetDataSize());
6 cycrow 1833
 
51 cycrow 1834
		// ok finally we need to read all the file
1835
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
58 cycrow 1836
			node->Data()->readFromFile(File, node->Data()->GetDataSize());
51 cycrow 1837
			if ( progress )	progress->UpdateProgress(fileCount++, m_lFiles.size() + 2);
6 cycrow 1838
		}
1839
 
1840
		m_bFullyLoaded = true;
1841
	}
1842
 
1843
	return true;
1844
}
1845
 
1846
bool CBaseFile::IsMod()
1847
{
1848
	// check for any mod files that are not fake patchs
1849
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
1850
	{
1851
		C_File *f = fNode->Data();
1852
		if ( f->GetFileType() != FILETYPE_MOD )
1853
			continue;
1854
 
1855
		if ( !f->IsFakePatch() )
1856
			return true;
1857
	}
1858
 
1859
	return false;
1860
}
1861
 
13 cycrow 1862
bool CBaseFile::IsFakePatch() const
6 cycrow 1863
{
1864
	// check for any mod files that are not fake patchs
1865
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
1866
	{
1867
		C_File *f = fNode->Data();
1868
		if ( f->GetFileType() != FILETYPE_MOD )
1869
			continue;
1870
 
1871
		if ( f->IsFakePatch() )
1872
			return true;
1873
	}
1874
 
1875
	return false;
1876
}
1877
 
175 cycrow 1878
Utils::String CBaseFile::createValuesLine () const
6 cycrow 1879
{
14 cycrow 1880
	Utils::String values("Name: ");
50 cycrow 1881
	values += this->name() + "\n";
1882
	values += "Author: " + this->author() + "\n";
1883
	values += "Version: " + this->version() + "\n";
1884
	if ( !this->creationDate().empty() )values += "Date: "			+ this->creationDate()	+ "\n";
49 cycrow 1885
	if ( !this->webAddress().empty() )	values += "WebAddress: "	+ this->webAddress()	+ "\n";
1886
	if ( !this->webSite().empty() )		values += "WebSite: "		+ this->webSite()		+ "\n";
1887
	if ( !this->email().empty() )		values += "Email: "			+ this->email()			+ "\n";
1888
	if ( !this->forumLink().empty() )	values += "ForumLink: "		+ this->forumLink()		+ "\n";
1889
 
162 cycrow 1890
	for(auto itr = _lMirrors.begin(); itr != _lMirrors.end(); itr++)
1891
		values += Utils::String("WebMirror: ") + (*itr)->str + "\n";
48 cycrow 1892
	if ( !this->description().empty() ) {
1893
		Utils::String desc = this->description();
14 cycrow 1894
		desc = desc.findReplace("<newline>", "<br>");
1895
		desc = desc.findReplace("\n", "<br>");
1896
		desc.remove('\r');
1897
		values += "Desc: " + desc + "\n";
6 cycrow 1898
	}
1899
 
1900
	for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {
46 cycrow 1901
		if ( !gc->Data()->sVersion.empty() )
1902
			values += Utils::String("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion + "\n";
6 cycrow 1903
		else
14 cycrow 1904
			values += Utils::String("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";
6 cycrow 1905
	}
1906
 
175 cycrow 1907
	if (computeSigned(true))
6 cycrow 1908
		values += "Signed\n";
1909
 
46 cycrow 1910
	for ( int j = 0; j < 2; j++ ) {
1911
		const CInstallText *text;
1912
		Utils::String textStart;
1913
		switch(j) {
1914
			case 0:	textStart = "Uninstall"; text = this->uninstallText(); break;
1915
			case 1: textStart = "Install"; text = this->installText(); break;
1916
		}
1917
		for ( unsigned int i = 0; i < text->count(); i++ ) {
1918
			int iLang = text->language(i);
1919
			if ( !text->getBefore(iLang).empty() ) values += textStart + "Before: " + (long)iLang + "|" + text->getBefore(iLang) + "\n";
1920
			if ( !text->getAfter(iLang).empty() ) values += textStart + "After: " + (long)iLang + "|" + text->getAfter(iLang) + "\n";
1921
		}
6 cycrow 1922
	}
1923
 
46 cycrow 1924
	values += Utils::String("GameChanging: ") + (long)gameChanging() + "\n";
1925
	values += Utils::String("EaseOfUse: ") + (long)easeOfUse() + "\n";
1926
	values += Utils::String("Recommended: ") + (long)recommended() + "\n";
6 cycrow 1927
 
170 cycrow 1928
	for(auto itr = namesList()->begin(); itr != namesList()->end(); itr++)
1929
		values += Utils::String("ScriptName: ") + (long)(*itr)->iLanguage + ":" + (*itr)->sName + "\n";
6 cycrow 1930
 
14 cycrow 1931
	for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() ) {
6 cycrow 1932
		SNeededLibrary *l = libNode->Data();
160 cycrow 1933
		values += "NeededLibrary: " + l->sName + "||" + l->sAuthor + "||" + l->sMinVersion + "\n";
6 cycrow 1934
	}
1935
 
160 cycrow 1936
	for (auto itr = _lFakePatchBefore.begin(); itr != _lFakePatchBefore.end(); itr++)
1937
		values += "FakePatchBefore: " + (*itr)->str + "||" + (*itr)->data + "\n";
1938
	for (auto itr = _lFakePatchAfter.begin(); itr != _lFakePatchAfter.end(); itr++)
1939
		values += "FakePatchAfter: " + (*itr)->str + "||" + (*itr)->data + "\n";
6 cycrow 1940
 
48 cycrow 1941
	values += Utils::String("PluginType: ") + (long)this->pluginType() + "\n";
6 cycrow 1942
 
1943
	return values;
1944
}
1945
 
1946
 
1947
/*
1948
	Func:   WriteFile
1949
	Input:  filename - The filename of the spk file to write to
1950
	Desc:   Writes the data to an spk file
1951
*/
175 cycrow 1952
bool CBaseFile::writeFile(const Utils::String &filename, CProgressInfo *progress) const
6 cycrow 1953
{
52 cycrow 1954
	CFileIO File(filename);
175 cycrow 1955
	if ( File.startWrite() ) return writeData(File, progress);
52 cycrow 1956
	return false;
6 cycrow 1957
}
1958
 
175 cycrow 1959
bool CBaseFile::writeHeader(CFileIO &file, int valueheader, int valueComprLen) const
6 cycrow 1960
{
52 cycrow 1961
	return file.write("BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);
6 cycrow 1962
}
1963
 
175 cycrow 1964
bool CBaseFile::writeData(CFileIO &file, CProgressInfo *progress ) const
6 cycrow 1965
{
1966
	int valueheader = m_SHeader.iValueCompression, fileheader = m_SHeader.iValueCompression;
1967
	if ( valueheader == SPKCOMPRESS_7ZIP )
1968
		valueheader = SPKCOMPRESS_ZLIB;
1969
	if ( fileheader == SPKCOMPRESS_7ZIP )
1970
		fileheader = SPKCOMPRESS_ZLIB;
1971
 
1972
	// get the script values
175 cycrow 1973
	Utils::String values = this->createValuesLine();
6 cycrow 1974
 
1975
	// compress the values
175 cycrow 1976
	int valueUncomprLen = (int)values.length();
6 cycrow 1977
	unsigned long valueComprLen = 0;
1978
	unsigned char *valueCompr = NULL;
1979
	bool compressed = false;
1980
	if ( valueheader == SPKCOMPRESS_ZLIB )
1981
	{
1982
		valueComprLen = valueUncomprLen;
1983
		if ( valueComprLen < 100 )
1984
			valueComprLen = 200;
1985
		else if ( valueComprLen < 1000 )
1986
			valueComprLen *= 2;
1987
 
1988
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
175 cycrow 1989
		int err = compress ( (unsigned char *)valueCompr, &valueComprLen, (const unsigned char *)values.c_str(), (unsigned long)values.length(), 0 );
6 cycrow 1990
		if ( err == Z_OK )
1991
			compressed = true;
1992
	}
1993
 
1994
	if ( !compressed )
1995
	{
1996
		valueComprLen = valueUncomprLen;
1997
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
1998
		memcpy ( valueCompr, values.c_str(), valueComprLen );
1999
		valueheader = SPKCOMPRESS_NONE;
2000
	}
2001
 
2002
	// write the main header to the file
175 cycrow 2003
	if ( !this->writeHeader(file, valueheader, valueComprLen) )	return false;
6 cycrow 2004
 
2005
	// write the compressed data to file
52 cycrow 2006
	file.put(static_cast<unsigned char>(valueUncomprLen >> 24));
2007
	file.put(static_cast<unsigned char>(valueUncomprLen >> 16));
2008
	file.put(static_cast<unsigned char>(valueUncomprLen >> 8));
2009
	file.put(static_cast<unsigned char>(valueUncomprLen));
2010
	file.write(valueCompr, valueComprLen);
6 cycrow 2011
	free ( valueCompr );
2012
 
2013
	// now compress the files header
2014
	// create the files values
175 cycrow 2015
	SSPKHeader2 header;
2016
	Utils::String files = createFilesLine(&header, progress);
2017
 
6 cycrow 2018
	// compress the files values
170 cycrow 2019
	long fileUncomprLen = (long)files.length(), fileComprLen = fileUncomprLen;
6 cycrow 2020
	unsigned char *fileCompr = NULL;
2021
 
2022
	compressed = false;
2023
	if ( fileUncomprLen )
2024
	{
2025
		if ( fileheader == SPKCOMPRESS_ZLIB )
2026
		{
2027
			if ( fileComprLen < 100 )
2028
				fileComprLen = 200;
2029
			else if ( fileComprLen < 1000 )
2030
				fileComprLen *= 2;
2031
			fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
170 cycrow 2032
			int err = compress ( (unsigned char *)fileCompr, (unsigned long *)&fileComprLen, (const unsigned char *)files.c_str(), (unsigned long)files.length(), 0 );
6 cycrow 2033
			if ( err == Z_OK )
2034
				compressed = true;
2035
		}
2036
	}
2037
 
2038
	// if unable to compress, store it as plain text
2039
	if ( !compressed )
2040
	{
2041
		fileComprLen = fileUncomprLen;
2042
		fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
2043
		memcpy ( fileCompr, files.c_str(), fileComprLen );
2044
		fileheader = SPKCOMPRESS_NONE;
2045
	}
2046
 
2047
	// now write the file header
175 cycrow 2048
	header.lSize = fileComprLen;
2049
	file.write("FileHeader;%d;%ld;%ld;%d;%d\n", header.iNumFiles, header.lSize, header.lFullSize, fileheader, header.iDataCompression);
6 cycrow 2050
 
52 cycrow 2051
	file.put(static_cast<unsigned char>(fileUncomprLen >> 24));
2052
	file.put(static_cast<unsigned char>(fileUncomprLen >> 16));
2053
	file.put(static_cast<unsigned char>(fileUncomprLen >> 8));
2054
	file.put(static_cast<unsigned char>(fileUncomprLen));
2055
	file.write(fileCompr, fileComprLen);
6 cycrow 2056
	free ( fileCompr );
2057
 
2058
	if ( progress )
2059
	{
2060
		progress->UpdateStatus(STATUS_WRITE);
2061
		progress->SetDone(0);
2062
		long max = 0;
88 cycrow 2063
		for ( CListNode<C_File> *file = m_lFiles.Front(); file; file = file->next() )
2064
			max += file->Data()->GetDataSize();
6 cycrow 2065
		if ( m_pIconFile )
2066
			max += m_pIconFile->GetDataSize();
2067
		progress->SetMax(max);
2068
	}
2069
 
2070
	// now finally, write all the file data
52 cycrow 2071
	if ( m_pIconFile ) {
2072
		if ( progress )	progress->UpdateFile(m_pIconFile);
178 cycrow 2073
		file.writeSize(m_pIconFile->uncompressedDataSize());
52 cycrow 2074
		file.write(m_pIconFile->GetData(), m_pIconFile->GetDataSize());
2075
		if ( progress )	progress->IncDone(m_pIconFile->GetDataSize());
6 cycrow 2076
	}
2077
 
2078
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2079
	{
52 cycrow 2080
		C_File *f = node->Data();
2081
		if ( progress )	progress->UpdateFile(f);
178 cycrow 2082
		file.writeSize(f->uncompressedDataSize());
52 cycrow 2083
		unsigned char *data = f->GetData();
2084
		size_t remaining = f->GetDataSize();
2085
		while ( remaining )	{
6 cycrow 2086
			size_t writeSize = WRITECHUNK;
52 cycrow 2087
			if ( writeSize > remaining ) writeSize = remaining;
6 cycrow 2088
 
52 cycrow 2089
			if ( file.write(data, writeSize) ) {
2090
				data += writeSize;
2091
				remaining -= writeSize;
2092
			}
6 cycrow 2093
 
52 cycrow 2094
			if ( progress ) progress->IncDone((int)writeSize);
6 cycrow 2095
		}
2096
	}
2097
 
2098
	return true;
2099
}
2100
 
131 cycrow 2101
bool CBaseFile::extractFile(C_File *file, const Utils::String &dir, bool includedir, CProgressInfo *progress)
2102
{
2103
	if (ReadFileToMemory(file))
6 cycrow 2104
	{
2105
		// now finally, uncompress the file
2106
		long len = 0;
131 cycrow 2107
		unsigned char *data = file->UncompressData(&len, progress);
2108
		if (!data)
6 cycrow 2109
		{
2110
			// attempt a file decompress
131 cycrow 2111
			if (file->GetCompressionType() == SPKCOMPRESS_7ZIP)
6 cycrow 2112
			{
178 cycrow 2113
				if (file->uncompressToFile(dir, this, includedir, progress))
6 cycrow 2114
					return true;
2115
			}
2116
			return false;
2117
		}
2118
 
131 cycrow 2119
		if (!file->writeToDir(dir, this, includedir, Utils::String::Null(), data, len))
6 cycrow 2120
			return false;
2121
 
2122
		return true;
2123
 
2124
	}
2125
	else
2126
		return false;
2127
}
131 cycrow 2128
bool CBaseFile::extractFile(C_File *file, const Utils::String &dir, unsigned int game, const Utils::CStringList &gameAddons, bool includedir, CProgressInfo *progress)
2129
{
2130
	if (ReadFileToMemory(file))
2131
	{
2132
		CDirIO Dir(dir);
2133
		Utils::String addonDir;
2134
		if (file->isFileInAddon())
2135
		{
2136
			int addonGame = file->getForSingleGame();
2137
			if (!addonGame) addonGame = game;
6 cycrow 2138
 
131 cycrow 2139
			if (addonGame > 0)
2140
				addonDir = gameAddons.findString(Utils::String::Number(addonGame));
2141
		}
2142
 
2143
		if (!addonDir.empty())
2144
			Dir.cd(addonDir);
2145
 
2146
		// create directory first
2147
		Dir.create(file->getDirectory(this));
2148
 
2149
		// now finally, uncompress the file
2150
		long len = 0;
2151
		unsigned char *data = file->UncompressData(&len, progress);
2152
		if (!data)
2153
		{
2154
			// attempt a file decompress
2155
			if (file->GetCompressionType() == SPKCOMPRESS_7ZIP)
2156
			{
178 cycrow 2157
				if (file->uncompressToFile(Dir.dir(), this, includedir, progress))
131 cycrow 2158
					return true;
2159
			}
2160
			return false;
2161
		}
2162
 
2163
		if (!file->writeToDir(Dir.dir(), this, includedir, Utils::String::Null(), data, len))
2164
			return false;
2165
 
2166
		return true;
2167
 
2168
	}
2169
	else
2170
		return false;
2171
}
2172
 
2173
bool CBaseFile::extractFile(int filenum, const Utils::String &dir, unsigned int game, const Utils::CStringList &gameAddons, bool includedir, CProgressInfo *progress)
2174
{
2175
	// invalid valus
2176
	if (filenum < 0)
2177
		return false;
2178
	// out of range
2179
	if (filenum > m_lFiles.size())
2180
		return false;
2181
 
2182
	// get the file pointer
2183
	C_File *file = m_lFiles.Get(filenum);
2184
	return extractFile(file, dir, game, gameAddons, includedir, progress);
2185
}
2186
 
2187
bool CBaseFile::extractFile(int filenum, const Utils::String &dir, bool includedir, CProgressInfo *progress)
2188
{
2189
	// invalid valus
2190
	if (filenum < 0)
2191
		return false;
2192
	// out of range
2193
	if (filenum > m_lFiles.size())
2194
		return false;
2195
 
2196
	// get the file pointer
2197
	C_File *file = m_lFiles.Get(filenum);
175 cycrow 2198
	return extractFile(file, dir, includedir, progress);
131 cycrow 2199
}
2200
 
129 cycrow 2201
bool CBaseFile::extractAll(const Utils::String &dir, int game, const Utils::CStringList &gameAddons, bool includedir, CProgressInfo *progress)
6 cycrow 2202
{
2203
	// no file to read from
129 cycrow 2204
	if (this->filename().empty())
6 cycrow 2205
		return false;
2206
 
2207
	// now open the file
58 cycrow 2208
	CFileIO *File = _startRead();
129 cycrow 2209
	if (!File) return false;
6 cycrow 2210
 
2211
	// now were in the file section
2212
	// skip past each one
129 cycrow 2213
	if (m_pIconFile) File->seek(4 + m_pIconFile->GetDataSize());
6 cycrow 2214
 
134 cycrow 2215
	for (CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next()) 
2216
	{
6 cycrow 2217
		C_File *fit = node->Data();
2218
 
134 cycrow 2219
		if ((!fit->GetDataSize()) || (!fit->GetData())) 
2220
		{
2221
			if (!fit->readFromFile(*File, fit->GetDataSize())) 
2222
				return false;
6 cycrow 2223
		}
2224
		else
58 cycrow 2225
			File->seek(fit->GetDataSize());
6 cycrow 2226
 
129 cycrow 2227
		if (game && !fit->isForGame(game))
2228
			continue;
2229
 
134 cycrow 2230
		if (progress)	
2231
			progress->UpdateFile(fit);
2232
 
129 cycrow 2233
		CDirIO Dir(dir);
2234
		Utils::String addonDir;
2235
		if (fit->isFileInAddon())
2236
		{
2237
			int addonGame = fit->getForSingleGame();
2238
			if (!addonGame) addonGame = game;
2239
 
2240
			if (addonGame > 0)
2241
				addonDir = gameAddons.findString(Utils::String::Number(addonGame));
6 cycrow 2242
		}
2243
 
129 cycrow 2244
		if (!addonDir.empty())
2245
			Dir.cd(addonDir);
2246
 
6 cycrow 2247
		// create directory first
129 cycrow 2248
		Dir.create(fit->getDirectory(this));
6 cycrow 2249
 
2250
		long size = 0;
129 cycrow 2251
		unsigned char *data = fit->UncompressData(&size, progress);
2252
		if ((!data) && (fit->GetCompressionType() == SPKCOMPRESS_7ZIP)) {
178 cycrow 2253
			if (!fit->uncompressToFile(Dir.dir(), this, includedir, progress)) return false;
6 cycrow 2254
		}
129 cycrow 2255
		else if ((!data) || (!fit->writeToDir(Dir.dir(), this, includedir, Utils::String::Null(), data, size))) return false;
6 cycrow 2256
	}
2257
 
58 cycrow 2258
	delete File;
6 cycrow 2259
	return true;
2260
}
2261
 
2262
 
175 cycrow 2263
bool CBaseFile::computeSigned(bool updateFiles) const
6 cycrow 2264
{
175 cycrow 2265
	for (CListNode<C_File>* node = m_lFiles.Front(); node; node = node->next())
6 cycrow 2266
	{
175 cycrow 2267
		C_File* file = node->Data();
2268
		if (updateFiles)
6 cycrow 2269
			file->UpdateSigned();
2270
		// extra, text, soundtrack, readmes and screen files do not require a modified game directly
175 cycrow 2271
		if ((file->GetFileType() == FILETYPE_EXTRA) || (file->GetFileType() == FILETYPE_TEXT) || (file->GetFileType() == FILETYPE_SOUND) || (file->GetFileType() == FILETYPE_SCREEN) || (file->GetFileType() == FILETYPE_README))
6 cycrow 2272
			continue;
2273
		// mods and maps always need modified game
175 cycrow 2274
		else if ((file->GetFileType() == FILETYPE_MOD) || (file->GetFileType() == FILETYPE_MAP))
2275
			return false;
6 cycrow 2276
 
2277
		// else should be a script file, script or uninstall type
2278
		// all scripts must be signed, if any are not, then no signed status
175 cycrow 2279
		if (!file->IsSigned())
2280
			return false;
6 cycrow 2281
	}
2282
 
175 cycrow 2283
	return true;
2284
}
2285
 
2286
bool CBaseFile::updateSigned(bool updateFiles)
2287
{
2288
	m_bSigned = computeSigned(updateFiles);
6 cycrow 2289
	return m_bSigned;
2290
}
2291
 
46 cycrow 2292
bool CBaseFile::IsPackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2293
{
2294
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2295
	{
2296
		SNeededLibrary *l = node->Data();
2297
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2298
			return true;
2299
	}
2300
 
2301
	return false;
2302
}
2303
 
46 cycrow 2304
SNeededLibrary *CBaseFile::FindPackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2305
{
2306
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2307
	{
2308
		SNeededLibrary *l = node->Data();
2309
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2310
			return l;
2311
	}
2312
 
2313
	return NULL;
2314
}
2315
 
160 cycrow 2316
void CBaseFile::removeFakePatchOrder(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2317
{
160 cycrow 2318
	removeFakePatchOrder(true, scriptName, author);
2319
	removeFakePatchOrder(false, scriptName, author);
6 cycrow 2320
}
160 cycrow 2321
void CBaseFile::removeFakePatchOrder(bool after, const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2322
{
160 cycrow 2323
	Utils::CStringList *list;
6 cycrow 2324
	if ( after )
160 cycrow 2325
		list = &_lFakePatchAfter;
6 cycrow 2326
	else
160 cycrow 2327
		list = &_lFakePatchBefore;
6 cycrow 2328
 
160 cycrow 2329
	int found = list->findStringAndData(scriptName, author);
2330
	while (found != -1)
6 cycrow 2331
	{
160 cycrow 2332
		list->removeAt(found);
2333
		found = list->findStringAndData(scriptName, author);
6 cycrow 2334
	}
2335
}
2336
 
160 cycrow 2337
void CBaseFile::addFakePatchOrder(bool after, const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2338
{
160 cycrow 2339
	Utils::CStringList *list;
6 cycrow 2340
	if ( after )
160 cycrow 2341
		list = &_lFakePatchAfter;
6 cycrow 2342
	else
160 cycrow 2343
		list = &_lFakePatchBefore;
6 cycrow 2344
 
2345
	// check if the package already exists
160 cycrow 2346
	if (!list->containsStringAndData(scriptName, author))
6 cycrow 2347
	{
160 cycrow 2348
		// cant have it on both list
2349
		removeFakePatchOrder(!after, scriptName, author);
2350
 
2351
		list->pushBack(scriptName, author);
6 cycrow 2352
	}
2353
}
46 cycrow 2354
void CBaseFile::AddNeededLibrary(const Utils::String &scriptName, const Utils::String &author, const Utils::String &minVersion)
6 cycrow 2355
{
2356
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2357
	if ( !l )
2358
	{
2359
		l = new SNeededLibrary;
2360
		l->sName = scriptName;
2361
		l->sAuthor = author;
2362
		m_lNeededLibrarys.push_back(l);
2363
	}
2364
	l->sMinVersion = minVersion;
2365
}
2366
 
46 cycrow 2367
void CBaseFile::RemovePackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2368
{
2369
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2370
	if ( l )
2371
	{
2372
		m_lNeededLibrarys.remove(l);
2373
		delete l;
2374
	}
2375
}
2376
 
2377
void CBaseFile::ClearNeededPackages()
2378
{
2379
	SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");
46 cycrow 2380
	Utils::String version;
2381
	if ( ns ) version = ns->sMinVersion;
2382
 
6 cycrow 2383
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2384
		node->DeleteData();
2385
	m_lNeededLibrarys.clear();
2386
 
46 cycrow 2387
	if ( !version.empty() )	this->AddNeededLibrary("<package>", "<author>", version);
6 cycrow 2388
}
2389
 
2390
 
127 cycrow 2391
bool CBaseFile::GeneratePackagerScript(bool wildcard, Utils::CStringList *list, int game, const Utils::CStringList &gameAddons, bool datafile)
6 cycrow 2392
{
126 cycrow 2393
	list->pushBack("#");
2394
	list->pushBack("# Packager Script");
2395
	list->pushBack("# -- Generated by SPK Libraries V" + Utils::String::FromFloat(GetLibraryVersion(), 2) + " --");
2396
	list->pushBack("#");
2397
	list->pushBack("");
6 cycrow 2398
	if ( !datafile )
2399
	{
126 cycrow 2400
		list->pushBack("# Variable for your game directory, where to get files from");
2401
		list->pushBack("# $PATH variable is used to get the current path");
2402
		list->pushBack("Variable: $GAMEDIR $PATH");
2403
		list->pushBack("");
6 cycrow 2404
	}
126 cycrow 2405
	list->pushBack("# The name of the script");
2406
	list->pushBack("Name: " + this->name());
2407
	list->pushBack("");
2408
	list->pushBack("# The author of the script, ie, you");
2409
	list->pushBack("Author: " + this->author());
2410
	list->pushBack("");
2411
	list->pushBack("# The creation data, when it was created");
6 cycrow 2412
	if ( datafile )
126 cycrow 2413
		list->pushBack("Date: " + this->creationDate());
50 cycrow 2414
	else {
126 cycrow 2415
		list->pushBack("# $DATE variable is used to get the current date");
2416
		list->pushBack("Date: $DATE");
6 cycrow 2417
	}
126 cycrow 2418
	list->pushBack("");
2419
	list->pushBack("# The version of script");
6 cycrow 2420
	if ( datafile )
126 cycrow 2421
		list->pushBack("Version: " + this->version());
6 cycrow 2422
	else
2423
	{
126 cycrow 2424
		list->pushBack("# $ASK variable is used to get an input when creating");
2425
		list->pushBack("Version: $ASK");
6 cycrow 2426
	}
126 cycrow 2427
	list->pushBack("");
6 cycrow 2428
 
2429
	if ( !m_lGames.empty() ) {
126 cycrow 2430
		list->pushBack("# The game version the script is for <game> <version> (can have multiple games)");
6 cycrow 2431
		for ( SGameCompat *g = m_lGames.First(); g; g = m_lGames.Next() ) {
126 cycrow 2432
			if (game > 0 && g->iGame != game)
2433
				continue;
2434
 
13 cycrow 2435
			Utils::String game = CBaseFile::ConvertGameToString(g->iGame);
6 cycrow 2436
 
46 cycrow 2437
			if ( !g->sVersion.empty() )
6 cycrow 2438
			{
2439
				game += " ";
46 cycrow 2440
				game += g->sVersion;
6 cycrow 2441
			}
2442
			else
2443
			{
2444
				game += " ";
2445
				game += (long)g->iVersion;
2446
			}
2447
 
126 cycrow 2448
			list->pushBack("Game: " + game);
6 cycrow 2449
		}
2450
 
126 cycrow 2451
		list->pushBack("");
6 cycrow 2452
	}
2453
 
48 cycrow 2454
	if ( !this->description().empty() ) {
126 cycrow 2455
		list->pushBack("# The description of the script, displays when installing");
2456
		list->pushBack("Description: " + this->description());
2457
		list->pushBack("");
6 cycrow 2458
	}
2459
 
49 cycrow 2460
	if ( !this->webSite().empty() ) {
126 cycrow 2461
		list->pushBack("# A link to the website for the script, ie for an online help page");
2462
		list->pushBack("WebSite: " + this->webSite());
2463
		list->pushBack("");
6 cycrow 2464
	}
2465
 
49 cycrow 2466
	if ( !this->forumLink().empty() ) {
126 cycrow 2467
		list->pushBack("# A direct link to the thread in the egosoft forum");
2468
		list->pushBack("ForumLink: " + this->forumLink());
2469
		list->pushBack("");
6 cycrow 2470
	}
2471
 
49 cycrow 2472
	if ( !this->webAddress().empty() ) {
126 cycrow 2473
		list->pushBack("# A link to the address for the update file");
2474
		list->pushBack("WebAddress: " + this->webAddress());
2475
		list->pushBack("");
6 cycrow 2476
	}
2477
 
49 cycrow 2478
	if ( !this->email().empty() ) {
126 cycrow 2479
		list->pushBack("# The email address of the author, to allow users to contract if needed");
2480
		list->pushBack("Email: " + this->email());
2481
		list->pushBack("");
6 cycrow 2482
	}
2483
 
162 cycrow 2484
	if (_lMirrors.size())
6 cycrow 2485
	{
126 cycrow 2486
		list->pushBack("# A link to the mirror address for the update file, can have many of these");
162 cycrow 2487
		for(auto itr = _lMirrors.begin(); itr != _lMirrors.end(); itr++)
2488
			list->pushBack(Utils::String("WebMirror: ") + (*itr)->str);
126 cycrow 2489
		list->pushBack("");
6 cycrow 2490
	}
2491
 
2492
	if ( m_bAutoGenerateUpdateFile )
2493
	{
126 cycrow 2494
		list->pushBack("# Auto generate the package update file when created");
2495
		list->pushBack("GenerateUpdateFile");
6 cycrow 2496
	}
2497
 
2498
	if ( m_lNeededLibrarys.size() )
2499
	{
126 cycrow 2500
		list->pushBack("# Needed Library dependacies, require these to be installed");
6 cycrow 2501
		for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
126 cycrow 2502
			list->pushBack("Depend: " + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);
6 cycrow 2503
 
126 cycrow 2504
		list->pushBack("");
6 cycrow 2505
	}
2506
 
46 cycrow 2507
	if ( !_noRatings() )
6 cycrow 2508
	{
126 cycrow 2509
		list->pushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");
2510
		list->pushBack(Utils::String("Ratings: ") + (long)easeOfUse() + " " + (long)gameChanging() + " " + (long)recommended());
2511
		list->pushBack("");
6 cycrow 2512
	}
2513
 
170 cycrow 2514
	if (namesList()->size())
6 cycrow 2515
	{
126 cycrow 2516
		list->pushBack("# Package names, uses different names for different languages");
170 cycrow 2517
		for(auto itr = namesList()->begin(); itr != namesList()->end(); itr++)
2518
			list->pushBack(Utils::String("ScriptName: ") + (long)(*itr)->iLanguage + " " + (*itr)->sName);
126 cycrow 2519
		list->pushBack("");
6 cycrow 2520
	}
2521
 
46 cycrow 2522
	for ( int j = 0; j < 2; j++ ) {
2523
		Utils::String installText = (j == 0) ? "Install" : "Uninstall";
2524
		const CInstallText *pText = (j == 0) ? this->installText() : this->uninstallText();
2525
		if ( pText->any() )
6 cycrow 2526
		{
126 cycrow 2527
			list->pushBack("# " + installText + " Texts, display text before and/or after " + installText + "ing to inform the use of special conditions");
46 cycrow 2528
			for ( unsigned int i = 0; i < pText->count(); i++ ) {
2529
				long iLang = pText->language(i);
126 cycrow 2530
				if ( !pText->getBefore(iLang).empty() )	list->pushBack(installText + "Before: " + iLang + " " + pText->getBefore(iLang));
2531
				if ( !pText->getAfter(iLang).empty()  )	list->pushBack(installText + "After: " + iLang + " " + pText->getAfter(iLang));
46 cycrow 2532
			}
126 cycrow 2533
			list->pushBack("");
6 cycrow 2534
		}
2535
	}
2536
 
126 cycrow 2537
	list->pushBack("# Plugin Type, the type the plugin is, mainly used to show users the type, types include: Normal, Stable, Experimental, Cheat, Mod");
48 cycrow 2538
	switch ( this->pluginType() )
6 cycrow 2539
	{
2540
		case PLUGIN_NORMAL:
126 cycrow 2541
			list->pushBack("PluginType: Normal");
6 cycrow 2542
			break;
2543
		case PLUGIN_STABLE:
126 cycrow 2544
			list->pushBack("PluginType: Stable");
6 cycrow 2545
			break;
2546
		case PLUGIN_EXPERIMENTAL:
126 cycrow 2547
			list->pushBack("PluginType: Experimental");
6 cycrow 2548
			break;
2549
		case PLUGIN_CHEAT:
126 cycrow 2550
			list->pushBack("PluginType: Cheat");
6 cycrow 2551
			break;
2552
		case PLUGIN_MOD:
126 cycrow 2553
			list->pushBack("PluginType: Mod");
6 cycrow 2554
			break;
2555
	}
126 cycrow 2556
	list->pushBack("");
6 cycrow 2557
 
2558
	return true;
2559
}
2560
 
127 cycrow 2561
bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, Utils::CStringList *list, int game, const Utils::CStringList &gameAddons)
6 cycrow 2562
{
2563
	// now do files and wildcards
126 cycrow 2564
	Utils::CStringList files;
6 cycrow 2565
	for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
2566
	{
127 cycrow 2567
		if (game && !(f->Data()->game() & 1 << game))
126 cycrow 2568
			continue;
6 cycrow 2569
 
126 cycrow 2570
		Utils::String name = "$GAMEDIR/";
2571
 
127 cycrow 2572
		// addon directory?
2573
		unsigned int checkGame = f->Data()->game() & ~(1 << 31);
2574
		unsigned int foundGame = 0;
2575
		for (int i = 0; i < 31; ++i)
2576
		{
2577
			if (checkGame == 1 << i)
2578
			{
2579
				foundGame = i;
2580
				break;
2581
			}
2582
		}
2583
 
2584
		if (foundGame)
2585
		{
2586
			Utils::String str = gameAddons.findString(Utils::String::Number(foundGame));
2587
			if(!str.empty())
2588
				name += str + "/";
2589
		}
2590
 
6 cycrow 2591
		bool done = false;
2592
		if ( wildcard )
2593
		{
131 cycrow 2594
			Utils::String base = f->Data()->baseName();
2595
			if ( f->Data()->fileType() == FILETYPE_SCRIPT )
6 cycrow 2596
			{
126 cycrow 2597
				if ( base.token(".", 1).Compare("plugin") || base.token(".", 1).Compare("lib") )
6 cycrow 2598
				{
131 cycrow 2599
					name += f->Data()->getDirectory(this) + "/" + base.tokens(".", 1, 2) + ".*";
6 cycrow 2600
					done = true;
2601
				}
126 cycrow 2602
				else if ( base.token(".", 1).Compare("al") && !base.token(".", 2).Compare("plugin") )
6 cycrow 2603
				{
131 cycrow 2604
					name += f->Data()->getDirectory(this) + "/" + base.tokens(".", 1, 2) + ".*";
6 cycrow 2605
					done = true;
2606
				}
2607
			}
131 cycrow 2608
			else if ( f->Data()->fileType() == FILETYPE_TEXT )
6 cycrow 2609
			{
126 cycrow 2610
				if ( base.contains("-L") )
6 cycrow 2611
				{
131 cycrow 2612
					name += f->Data()->getDirectory(this) + "/" + base.token("-L", 1) + "-L*";
6 cycrow 2613
					done = true;
2614
				}
2615
				else
2616
				{
131 cycrow 2617
					name += f->Data()->getDirectory(this) + "/*" + base.right(4) + ".*";
6 cycrow 2618
					done = true;
2619
				}
2620
			}
2621
		}
2622
 
2623
		if ( !done )
131 cycrow 2624
			name += f->Data()->getNameDirectory(this);
6 cycrow 2625
 
131 cycrow 2626
		if ( !f->Data()->dir().empty() )
6 cycrow 2627
		{
2628
			name += "|";
131 cycrow 2629
			name += f->Data()->dir();
6 cycrow 2630
		}
127 cycrow 2631
		Utils::String s = "GAME ";
2632
		if (!f->Data()->game() || f->Data()->game() == GAME_ALLNEW)
2633
			s += CBaseFile::ConvertGameToString(f->Data()->game());
2634
		else
2635
		{
2636
			bool first = true;
2637
			for (int i = 0; i < 31; ++i) 
2638
			{
2639
				if (f->Data()->game() & 1 << i)
2640
				{
2641
					if (first)
2642
						first = false;
2643
					else
2644
						s += "|";
2645
					s += CBaseFile::ConvertGameToString(i);
2646
				}
2647
			}
2648
		}
2649
 
2650
		s += " " + name;
126 cycrow 2651
		if(!files.contains(s))
178 cycrow 2652
			files.pushBack(s, f->Data()->fileTypeString());
6 cycrow 2653
	}
2654
 
2655
 
126 cycrow 2656
	if ( !files.empty() )
6 cycrow 2657
	{
126 cycrow 2658
		list->pushBack("# Files List, all the files to add, can include wild cards");
2659
		for(auto itr = files.begin(); itr != files.end(); itr++)
2660
			list->pushBack((*itr)->data + ": " + (*itr)->str);
2661
		list->pushBack("");
6 cycrow 2662
	}
2663
 
2664
	return true;
2665
}
2666
 
170 cycrow 2667
Utils::String CBaseFile::getAutosaveName() const
6 cycrow 2668
{
50 cycrow 2669
	return this->name() + "-V" + this->version() + "-" + this->creationDate().findReplace("/", ".");
6 cycrow 2670
}
2671
 
2672
bool CBaseFile::CheckGameCompatability(int game)
2673
{
2674
	if ( m_lGames.empty() )
2675
		return true; // no game compatability added, assume its ok for all
2676
 
2677
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2678
		if ( node->Data()->iGame == 0 || node->Data()->iGame == game )
2679
			return true;
2680
	}
2681
	return false;
2682
}
2683
 
170 cycrow 2684
bool CBaseFile::checkGameVersionCompatability(int game, const Utils::String &sVersion, int iVersion) const
6 cycrow 2685
{
170 cycrow 2686
	if (m_lGames.empty())
6 cycrow 2687
		return true; // no game compatability added, assume its ok for all
2688
 
2689
	bool foundAll = false;
2690
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2691
		if ( node->Data()->iGame == 0 )
2692
			foundAll = true;
2693
		else if ( node->Data()->iGame == game ) { // now check the version
46 cycrow 2694
			if ( node->Data()->sVersion.empty() ) {
170 cycrow 2695
				if (node->Data()->sVersion.compareVersion(sVersion) == COMPARE_OLDER)
6 cycrow 2696
					return false;
2697
				return true;
2698
			}
2699
			else {
2700
				if ( node->Data()->iVersion > iVersion )
2701
					return false;
2702
				return true;
2703
			}
2704
		}
2705
	}
2706
	return foundAll;
2707
}
2708
 
2709
bool CBaseFile::RemoveGameCompatability(int game)
2710
{
2711
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2712
		if ( node->Data()->iGame == game ) {
2713
			m_lGames.remove(node);
50 cycrow 2714
			_changed();
6 cycrow 2715
			return true;
2716
		}
2717
	}
2718
 
2719
	return false;
2720
}
2721
 
2722
SGameCompat *CBaseFile::GetGameCompatability(int game)
2723
{
2724
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2725
		if ( node->Data()->iGame == game ) {
2726
			return node->Data();
2727
		}
2728
	}
2729
 
2730
	return NULL;
2731
}
2732
 
46 cycrow 2733
void CBaseFile::AddGameCompatability(int game, const Utils::String &version)
6 cycrow 2734
{
2735
	// first check if we already have it on the list
2736
	SGameCompat *Found = this->GetGameCompatability(game);
2737
	if ( !Found ) {
2738
		Found = new SGameCompat;
2739
		m_lGames.push_back(Found);
2740
	}
2741
 
2742
	Found->iGame = game;
2743
	Found->iVersion = -1;
46 cycrow 2744
	Found->sVersion = "";
6 cycrow 2745
 
46 cycrow 2746
	if ( version.isin(".") || !version.isNumber() )
6 cycrow 2747
		Found->sVersion = version;
2748
	else
46 cycrow 2749
		Found->iVersion = version;
50 cycrow 2750
	_changed();
6 cycrow 2751
}
2752
 
131 cycrow 2753
Utils::String CBaseFile::_replaceFilename(const Utils::String &fname)
2754
{
2755
	Utils::String filename = fname;
2756
	Utils::String cdate = this->creationDate().findReplace("/", ".").remove(' ');
2757
	if (filename.isin("$AUTOSAVE"))
2758
	{
2759
		if (this->GetType() == TYPE_XSP)
2760
			filename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");
2761
		else
2762
			filename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");
2763
	}
2764
	filename = filename.findReplace("$NAME", this->name().remove(' '));
2765
	filename = filename.findReplace("$AUTHOR", this->author().remove(' '));
2766
	filename = filename.findReplace("$DATE", cdate);
2767
	filename = filename.findReplace("$CDATE", cdate);
2768
	filename = filename.findReplace("$VERSION", this->version());
2769
 
2770
	return filename;
2771
}
134 cycrow 2772
bool CBaseFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames, Utils::CStringList &gameAddons, CProgressInfo *progress)
6 cycrow 2773
{
134 cycrow 2774
	if (sFirst.Compare("Name"))					this->setName(sRest);
2775
	else if (sFirst.Compare("Author"))			this->setAuthor(sRest);
170 cycrow 2776
	else if (sFirst.Compare("ScriptName"))		addName(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
134 cycrow 2777
	else if (sFirst.Compare("UninstallBefore"))	this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));
2778
	else if (sFirst.Compare("UninstallAfter"))	this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));
2779
	else if (sFirst.Compare("InstallBefore"))		this->addInstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));
2780
	else if (sFirst.Compare("InstallAfter"))		this->addInstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));
2781
	else if (sFirst.Compare("Date"))				this->setCreationDate(sRest);
2782
	else if (sFirst.Compare("Version"))			this->setVersion(sRest);
2783
	else if (sFirst.Compare("GameVersion"))
14 cycrow 2784
		this->AddGameCompatability(-1, sRest);
134 cycrow 2785
	else if (sFirst.Compare("PluginType")) {
2786
		if (sRest.isNumber())						this->setPluginType(sRest);
2787
		else if (sRest.Compare("Normal"))			this->setPluginType(PLUGIN_NORMAL);
2788
		else if (sRest.Compare("Stable"))			this->setPluginType(PLUGIN_STABLE);
2789
		else if (sRest.Compare("Experimental"))	this->setPluginType(PLUGIN_EXPERIMENTAL);
2790
		else if (sRest.Compare("Cheat"))			this->setPluginType(PLUGIN_CHEAT);
2791
		else if (sRest.Compare("Mod"))			this->setPluginType(PLUGIN_MOD);
6 cycrow 2792
	}
2793
	// new version
134 cycrow 2794
	else if (sFirst.Compare("GenerateUpdateFile"))
6 cycrow 2795
		m_bAutoGenerateUpdateFile = true;
134 cycrow 2796
	else if (sFirst.Compare("Game"))
6 cycrow 2797
	{
14 cycrow 2798
		Utils::String sGame = sRest.token(" ", 1);
2799
		this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), sRest.token(" ", 2));
6 cycrow 2800
	}
134 cycrow 2801
	else if (sFirst.Compare("Description"))		this->setDescription(sRest);
2802
	else if (sFirst.Compare("AutoSave") || sFirst.Compare("AutoExport") || sFirst.Compare("AutoRarExport") || sFirst.Compare("AutoZipExport"))
6 cycrow 2803
	{
131 cycrow 2804
		Utils::String filename = _replaceFilename(sRest);
6 cycrow 2805
 
134 cycrow 2806
		if (sFirst.Compare("AutoZipExport") || sFirst.Compare("AutoExport"))
131 cycrow 2807
			this->setExportFilename(CFileIO(filename).changeFileExtension("zip"));
134 cycrow 2808
		else if (sFirst.Compare("AutoRarExport"))
131 cycrow 2809
			this->setExportFilename(CFileIO(filename).changeFileExtension("rar"));
6 cycrow 2810
		else
50 cycrow 2811
			this->setFilename(filename);
6 cycrow 2812
	}
134 cycrow 2813
	else if (sFirst.Compare("WebSite"))		this->setWebSite(sRest);
2814
	else if (sFirst.Compare("ForumLink") || sFirst.Compare("Forum")) this->setForumLink(sRest);
2815
	else if (sFirst.Compare("Email"))			this->setEmail(sRest);
2816
	else if (sFirst.Compare("WebAddress"))	this->setWebAddress(sRest);
2817
	else if (sFirst.Compare("WebMirror"))
162 cycrow 2818
		this->addWebMirror(sRest);
134 cycrow 2819
	else if (sFirst.Compare("WebMirror1"))
162 cycrow 2820
		this->addWebMirror(sRest);
134 cycrow 2821
	else if (sFirst.Compare("WebMirror2"))
162 cycrow 2822
		this->addWebMirror(sRest);
134 cycrow 2823
	else if (sFirst.Compare("Ftp"))
170 cycrow 2824
		_sFtpAddr = sRest;
134 cycrow 2825
	else if (sFirst.Compare("Ratings"))		_setRatings(sRest.token(" ", 1), sRest.token(" ", 2), sRest.token(" ", 3));
2826
	else if (sFirst.Compare("EaseOfUse"))		setEaseOfUse(sRest);
2827
	else if (sFirst.Compare("GameChanging"))	setGameChanging(sRest);
2828
	else if (sFirst.Compare("Recommended"))	setRecommended(sRest);
2829
	else if (sFirst.Compare("Depend"))
6 cycrow 2830
	{
46 cycrow 2831
		Utils::String version = sRest.token("|", 2);
2832
		Utils::String name = sRest.token("|", 1);
2833
		Utils::String author = sRest.tokens("|", 3);
6 cycrow 2834
 
2835
		this->AddNeededLibrary(name, author, version);
2836
	}
134 cycrow 2837
	else if (sFirst.Compare("DependPackage"))
6 cycrow 2838
	{
2839
		CPackages p;
182 cycrow 2840
		CBaseFile *spk = p.openPackage(sRest, 0, 0, SPKREAD_VALUES);
134 cycrow 2841
		if (spk)
6 cycrow 2842
		{
50 cycrow 2843
			this->AddNeededLibrary(spk->name(), spk->author(), spk->version());
6 cycrow 2844
			delete spk;
2845
		}
2846
	}
130 cycrow 2847
	else if (sFirst.Compare("Icon"))
6 cycrow 2848
	{
14 cycrow 2849
		C_File *icon = new C_File(sRest.c_str());
134 cycrow 2850
		if (icon->ReadFromFile())
170 cycrow 2851
			this->setIcon(icon, CFileIO(sRest).extension());
6 cycrow 2852
	}
130 cycrow 2853
	else if (sFirst.Compare("CombineGameFiles"))
2854
		_bCombineFiles = sRest.Compare("true") || sRest.Compare("yes") || sRest.toInt();
134 cycrow 2855
	else if (sFirst.Compare("UpdateFile"))
2856
		this->createUpdateFile(sRest);
131 cycrow 2857
	else if (sFirst.Compare("ExportZip"))
2858
	{
2859
		Utils::String ext = "zip";
2860
		Utils::String game = sRest.word(1);
2861
		Utils::String file = _replaceFilename(CFileIO(sRest.words(2)).fullFilename());
2862
		if (game.contains("|"))
2863
		{
2864
			int max;
2865
			Utils::String *games = game.tokenise("|", &max);
2866
			if (games)
2867
			{
2868
				for (int i = 0; i < max; ++i)
2869
				{
2870
					unsigned int g = CBaseFile::GetGameFromString(games[i]);
2871
					Utils::String filename = CFileIO(file).dir() + "/" + CFileIO(file).baseName() + "_" + CBaseFile::ConvertGameToString(g) + "." + ext;
2872
					this->addAutoExport(g, filename);
2873
				}
2874
				CLEANSPLIT(games, max);
2875
			}
2876
		}
2877
		else
2878
		{
2879
			unsigned int g = CBaseFile::GetGameFromString(game);
2880
			Utils::String filename = CFileIO(file).dir() + "/" + CFileIO(file).baseName() + "_" + CBaseFile::ConvertGameToString(g) + "." + ext;
2881
			this->addAutoExport(g, filename);
2882
		}
2883
	}
2884
	else if (sFirst.Compare("Extract"))
2885
	{
2886
		Utils::String game = sRest.word(1);
2887
		Utils::String dir = CDirIO(sRest.words(2)).dir();
2888
		if (game.contains("|"))
2889
		{
2890
			int max;
2891
			Utils::String *games = game.tokenise("|", &max);
2892
			if (games)
2893
			{
2894
				for(int i = 0; i < max; ++i)
2895
					this->addAutoExtract(CBaseFile::GetGameFromString(games[i]), dir);
2896
				CLEANSPLIT(games, max);
2897
			}
2898
		}
2899
		else
2900
			this->addAutoExtract(CBaseFile::GetGameFromString(game), dir);
2901
	}
6 cycrow 2902
	else
2903
	{
14 cycrow 2904
		Utils::String checkType = sFirst;
6 cycrow 2905
		bool shared = false;
155 cycrow 2906
		if (checkType.left(6).Compare("Shared"))
6 cycrow 2907
		{
14 cycrow 2908
			checkType = sFirst.right(-6);
6 cycrow 2909
			shared = true;
2910
		}
155 cycrow 2911
		bool packed = false;
2912
		if (checkType.right(3).Compare("PCK"))
2913
		{
2914
			checkType = sFirst.left(-3);
2915
			packed = true;
2916
		}
6 cycrow 2917
 
2918
		// now check type name
127 cycrow 2919
		FileType filetype = GetFileTypeFromString(checkType);
2920
		if (filetype != FILETYPE_UNKNOWN)
155 cycrow 2921
			this->AddFileScript(filetype, shared, packed, sRest, sMainGame, otherGames, gameAddons, progress);
6 cycrow 2922
		else if ( !checkType.Compare("changelog") )
2923
			return false;
2924
	}
2925
 
2926
	return true;
2927
}
2928
 
155 cycrow 2929
void CBaseFile::AddFileScript(FileType filetype, bool shared, bool packed, const Utils::String &sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames, Utils::CStringList &gameAddons, CProgressInfo *progress)
6 cycrow 2930
{
127 cycrow 2931
	Utils::String dir;
155 cycrow 2932
	Utils::String rest = sRest;
127 cycrow 2933
 
2934
	unsigned int mainGame = CBaseFile::GetGameFromString(sMainGame);
2935
	unsigned int game = 0;
2936
	if ( rest.token(" ", 1).left(4).Compare("GAME") ) {
2937
		Utils::String gameStr = rest.token(" ", 2);
2938
		if (gameStr.contains("|"))
2939
		{
2940
			int max = 0;
2941
			Utils::String *games = gameStr.tokenise("|", &max);
2942
			for (int i = 0; i < max; ++i)
2943
			{
2944
				unsigned int g = CBaseFile::GetGameFromString(games[i]);
2945
				if (g)
2946
					game |= 1 << g;
2947
			}
2948
			CLEANSPLIT(games, max);
2949
		}
2950
		else
131 cycrow 2951
		{
2952
			unsigned int g = CBaseFile::GetGameFromString(gameStr);
2953
			if (g)
2954
				game = 1 << g;
2955
		}
127 cycrow 2956
		rest = rest.tokens(" ", 3);
6 cycrow 2957
	}
127 cycrow 2958
	if (game)
2959
		game |= 1 << 31;
6 cycrow 2960
 
127 cycrow 2961
	if (rest.contains("|"))
2962
	{
2963
		dir = rest.tokens("|", 2);
2964
		rest = rest.token("|", 1);
6 cycrow 2965
	}
2966
 
127 cycrow 2967
	rest = rest.findReplace("\\", "/");
6 cycrow 2968
 
2969
	// wild cards
127 cycrow 2970
	if ( rest.containsAny("*?") )
6 cycrow 2971
	{
102 cycrow 2972
		CDirIO Dir(CFileIO(rest).dir());
160 cycrow 2973
		Utils::CStringList dirList;
2974
		if(Dir.dirList(dirList))
6 cycrow 2975
		{
160 cycrow 2976
			for(auto itr = dirList.begin(); itr != dirList.end(); itr++)
6 cycrow 2977
			{
160 cycrow 2978
				Utils::String file = Dir.file((*itr)->str);
127 cycrow 2979
				if (file.match(rest))
6 cycrow 2980
				{
98 cycrow 2981
					int addGame = game;
2982
					// check if the file exists in the subdirectory too, if it does, add for each game
2983
					if ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {
2984
						CFileIO F(file);
2985
						for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {
102 cycrow 2986
							Utils::String checkDir = F.dir() + "/" + g;
121 cycrow 2987
							if ( CDirIO(checkDir).exists(F.filename()) ) {
98 cycrow 2988
								addGame = mainGame;
155 cycrow 2989
								C_File *newfile = this->appendFile(CDirIO(checkDir).file(F.filename()), filetype, CBaseFile::GetGameFromString(g), packed, dir);
134 cycrow 2990
								if (newfile && progress)
2991
									progress->UpdateFile(newfile);
98 cycrow 2992
								if ( newfile ) newfile->SetShared(shared);
2993
							}
2994
						}
2995
					}
2996
 
160 cycrow 2997
					C_File *newfile = this->appendFile(file, filetype, addGame, packed, dir);
134 cycrow 2998
					if (newfile && progress)
2999
						progress->UpdateFile(newfile);
6 cycrow 3000
					if ( newfile )
3001
						newfile->SetShared(shared);
3002
				}
3003
			}
3004
		}
3005
	}
3006
	else
3007
	{
127 cycrow 3008
		unsigned int addGame = game;
98 cycrow 3009
		// check if the file exists in the subdirectory too, if it does, add for each game
3010
		if ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {
3011
			CFileIO F(rest);
3012
			for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {
102 cycrow 3013
				Utils::String checkDir = F.dir() + "/" + g;
121 cycrow 3014
				if ( CDirIO(checkDir).exists(F.filename()) ) {
98 cycrow 3015
					addGame = mainGame;
155 cycrow 3016
					C_File *newfile = this->appendFile(CDirIO(checkDir).file(F.filename()), filetype, CBaseFile::GetGameFromString(g), packed, dir);
134 cycrow 3017
					if (newfile && progress)
3018
						progress->UpdateFile(newfile);
98 cycrow 3019
					if ( newfile ) newfile->SetShared(shared);
3020
				}
3021
			}
3022
		}
3023
 
127 cycrow 3024
		unsigned int checkGame = addGame & ~(1 << 31);
3025
		unsigned int foundGame = 0;
3026
		for (int i = 0; i < 31; ++i)
3027
		{
3028
			if (1 << i == checkGame)
3029
			{
3030
				foundGame = i;
3031
				break;
3032
			}
3033
		}
3034
 
3035
		C_File *file = NULL;
3036
		if (foundGame)
3037
		{
3038
			Utils::String addon = gameAddons.findString(Utils::String::Number(foundGame));
3039
			if (!addon.empty())
3040
			{
3041
				Utils::String dir = C_File::GetDirectory(filetype, rest, this);
3042
				Utils::String filename = rest;
130 cycrow 3043
				if (CCatFile::IsAddonDir(dir) && !filename.contains(addon))
3044
				{
127 cycrow 3045
					filename = filename.findReplace(dir + "/", addon + "/" + dir + "/");
155 cycrow 3046
					file = this->appendFile(filename, filetype, addGame, packed, dir);
130 cycrow 3047
				}
127 cycrow 3048
			}
3049
		}
3050
 
3051
		if(!file)
155 cycrow 3052
			file = this->appendFile(rest, filetype, addGame, packed, dir);
127 cycrow 3053
 
134 cycrow 3054
		if (file && progress)
3055
			progress->UpdateFile(file);
127 cycrow 3056
		if (file)
6 cycrow 3057
			file->SetShared(shared);
3058
	}
3059
}
3060
 
3061
 
170 cycrow 3062
Utils::String CBaseFile::fileSizeString() const { return SPK::GetSizeString ( this->fileSize() ); }
6 cycrow 3063
 
52 cycrow 3064
// used for a multiple spk file
6 cycrow 3065
unsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress)
3066
{
175 cycrow 3067
	if ( this->writeFile("temp.dat", progress) ) {
52 cycrow 3068
		CFileIO File("temp.dat");
3069
		File.setAutoDelete(true);
3070
		return File.readAll(size);
6 cycrow 3071
	}
3072
	return NULL;
3073
}
3074
 
3075
 
170 cycrow 3076
void CBaseFile::convertNormalMod(C_File *f, const Utils::String &to) const
6 cycrow 3077
{
170 cycrow 3078
	C_File *match = this->findMatchingMod(f);
6 cycrow 3079
	if ( match )
3080
	{
3081
		// file link
3082
		if ( !match->GetData() )
3083
			match->ReadFromFile();
178 cycrow 3084
		match->changeBaseName(to);
6 cycrow 3085
	}
3086
 
3087
	// file link
3088
	if ( !f->GetData() )
3089
		f->ReadFromFile();
3090
 
178 cycrow 3091
	f->changeBaseName(to);
6 cycrow 3092
}
3093
 
170 cycrow 3094
void CBaseFile::convertAutoText(C_File *f) const
6 cycrow 3095
{
170 cycrow 3096
	Utils::String to;
3097
	if ( f->baseName().contains("-L") )
3098
		to = "0000-L" + f->baseName().token("-L", 2);
178 cycrow 3099
	else if ( f->baseName().contains("-l") )
170 cycrow 3100
		to = "0000-L" + f->baseName().token("-l", 2);
6 cycrow 3101
	else
170 cycrow 3102
		to = f->baseName().left(-4) + "0000";
6 cycrow 3103
 
3104
	// file link
3105
	if ( !f->GetData() )
3106
		f->ReadFromFile();
3107
 
178 cycrow 3108
	f->changeBaseName(to);
6 cycrow 3109
}
3110
 
170 cycrow 3111
void CBaseFile::convertFakePatch(C_File *f) const
6 cycrow 3112
{
3113
	// find next available fake patch
3114
	int num = 0;
3115
 
3116
	bool found = true;
3117
	while ( found )
3118
	{
3119
		++num;
3120
		found = false;
170 cycrow 3121
		Utils::String find = Utils::String::PadNumber(num, 2);
6 cycrow 3122
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
3123
		{
3124
			if ( node->Data()->GetFileType() != FILETYPE_MOD )
3125
				continue;
3126
			if ( !node->Data()->IsFakePatch() )
3127
				continue;
170 cycrow 3128
			if ( node->Data()->baseName().Compare(find) )
6 cycrow 3129
			{
3130
				found = true;
3131
				break;
3132
			}
3133
		}
3134
	}
3135
 
170 cycrow 3136
	Utils::String to = Utils::String::PadNumber(num, 2);
3137
	C_File *match = this->findMatchingMod(f);
6 cycrow 3138
 
3139
	// file link
3140
	if ( !f->GetData() )
3141
		f->ReadFromFile();
3142
 
178 cycrow 3143
	f->changeBaseName(to);
6 cycrow 3144
	if ( match )
3145
	{
3146
		// file link
3147
		if ( !match->GetData() )
3148
			match->ReadFromFile();
178 cycrow 3149
		match->changeBaseName(to);
6 cycrow 3150
	}
3151
}
3152
 
170 cycrow 3153
C_File *CBaseFile::findMatchingMod(C_File *f) const
6 cycrow 3154
{
3155
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
3156
	{
3157
		if ( node->Data()->GetFileType() != FILETYPE_MOD )
3158
			continue;
3159
 
178 cycrow 3160
		if ( f->fileExt().Compare(node->Data()->fileExt()) )
6 cycrow 3161
			continue;
3162
 
178 cycrow 3163
		if ( f->baseName().Compare(node->Data()->baseName()) )
6 cycrow 3164
			return node->Data();
3165
	}
3166
 
3167
	return NULL;
3168
}
3169
 
170 cycrow 3170
void CBaseFile::renameFile(C_File *f, const Utils::String &baseName) const
6 cycrow 3171
{
3172
	if ( f->GetFileType() == FILETYPE_MOD )
3173
	{
170 cycrow 3174
		C_File *match = this->findMatchingMod(f);
6 cycrow 3175
		if ( match )
178 cycrow 3176
			match->changeBaseName(baseName);
6 cycrow 3177
	}
3178
 
3179
	// need to edit the file
134 cycrow 3180
	if (f->GetFileType() == FILETYPE_SCRIPT || f->GetFileType() == FILETYPE_UNINSTALL)
178 cycrow 3181
		f->renameScript(baseName);
6 cycrow 3182
 
178 cycrow 3183
	f->changeBaseName(baseName);
6 cycrow 3184
}
3185
 
162 cycrow 3186
void CBaseFile::addWebMirror(const Utils::String& str) 
3187
{ 
3188
	if (!_lMirrors.contains(str))
3189
	{
3190
		_lMirrors.pushBack(str, "");
3191
		_changed();
3192
	}
3193
}
3194
 
3195
void CBaseFile::removeWebMirror(const Utils::String& str) 
3196
{ 
3197
	_lMirrors.remove(str, true); 
3198
	_changed(); 
3199
}
3200
 
134 cycrow 3201
Utils::String CBaseFile::createUpdateFile(const Utils::String &dir) const
6 cycrow 3202
{
134 cycrow 3203
	Utils::String file = this->getNameValidFile() + "_" + this->author() + ".dat";
3204
	file.removeChar(' ');
6 cycrow 3205
 
134 cycrow 3206
	Utils::CStringList write;
3207
	write.pushBack("Package: " + this->name());
3208
	write.pushBack("Author: " + this->author());
3209
	write.pushBack("Version: " + this->version());
3210
	write.pushBack("File: " + CFileIO(this->filename()).filename());
6 cycrow 3211
 
3212
	CFileIO File(dir + "/" + file);
134 cycrow 3213
	if (File.writeFile(&write))
102 cycrow 3214
		return File.fullFilename();
134 cycrow 3215
	return Utils::String::Null();
6 cycrow 3216
}
3217
 
134 cycrow 3218
Utils::String CBaseFile::ErrorString(int error, const Utils::String &errorStr)
6 cycrow 3219
{
134 cycrow 3220
	if (error == SPKERR_NONE) return Utils::String::Null();
6 cycrow 3221
 
134 cycrow 3222
	Utils::String err;
6 cycrow 3223
 
126 cycrow 3224
	switch (error)
6 cycrow 3225
	{
126 cycrow 3226
	case SPKERR_MALLOC:
3227
		err = "Memory Failed";
3228
		break;
3229
	case SPKERR_FILEOPEN:
3230
		err = "Failed to open file";
3231
		break;
3232
	case SPKERR_FILEREAD:
3233
		err = "Failed to read file";
3234
		break;
3235
	case SPKERR_UNCOMPRESS:
3236
		err = "Failed to Uncompress";
3237
		break;
3238
	case SPKERR_WRITEFILE:
3239
		err = "Failed to write file";
3240
		break;
3241
	case SPKERR_CREATEDIRECTORY:
3242
		err = "Failed to create directory";
3243
		break;
3244
	case SPKERR_FILEMISMATCH:
3245
		err = "File count mismatch";
3246
		break;
6 cycrow 3247
	}
3248
 
134 cycrow 3249
	if (!err.empty())
6 cycrow 3250
	{
134 cycrow 3251
		if (!errorStr.empty())
6 cycrow 3252
		{
3253
			err += " (";
3254
			err += errorStr + ")";
3255
		}
3256
		return err;
3257
	}
3258
 
134 cycrow 3259
	return Utils::String::Number((long)error);
6 cycrow 3260
}
3261
 
131 cycrow 3262
bool CBaseFile::saveToArchive(const Utils::String &filename, int game, const CGameExe *exes, CProgressInfo *progress)
3263
{
3264
	CDirIO Dir(CFileIO(filename).dir());
3265
	if (!Dir.exists())
3266
		Dir.create();
3267
 
6 cycrow 3268
	TCHAR buf[5000];
3269
	wsprintf(buf, L"%hs", filename.c_str());
3270
 
3271
	HZIP hz = CreateZip(buf, 0);
126 cycrow 3272
	if (!hz) return false;
6 cycrow 3273
 
3274
	// read files and compress
3275
	ReadAllFilesToMemory();
126 cycrow 3276
	if (!UncompressAllFiles(progress))
6 cycrow 3277
	{
3278
		CloseZip(hz);
3279
		return false;
3280
	}
3281
 
126 cycrow 3282
	for (CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next())
6 cycrow 3283
	{
126 cycrow 3284
		if (game != -1) {
127 cycrow 3285
			if (game && !(node->Data()->game() & (1 << game)))
6 cycrow 3286
				continue;
127 cycrow 3287
			// extracting for all games, so ignore files that have a game set
3288
			if (!game && node->Data()->game() && node->Data()->game() != GAME_ALLNEW)
6 cycrow 3289
				continue;
3290
		}
131 cycrow 3291
		Utils::String fname = node->Data()->getNameDirectory(this);
126 cycrow 3292
 
3293
		// use the addon directory
3294
		if (node->Data()->isFileInAddon() && exes)
3295
		{
127 cycrow 3296
			unsigned int whatGame = game;
126 cycrow 3297
			if (game == -1)
127 cycrow 3298
			{
3299
				unsigned int checkGame = node->Data()->game() & ~GAME_ALLNEW;
3300
				whatGame = 0;
3301
				for (int i = 0; i < 31; ++i)
3302
				{
3303
					if (1 << i == checkGame)
3304
					{
3305
						whatGame = i;
3306
						break;
3307
					}
3308
				}
3309
			}
126 cycrow 3310
 
127 cycrow 3311
			if (whatGame > 0)
126 cycrow 3312
			{
127 cycrow 3313
				SGameExe *e = exes->GetGame(whatGame - 1);
3314
				if (e)
3315
				{
3316
					if (e->iFlags & EXEFLAG_ADDON)
3317
						fname = e->sAddon + "/" + fname;
3318
				}
126 cycrow 3319
			}
3320
		}
3321
 
6 cycrow 3322
		// create the directory
3323
		wsprintf(buf, L"%hs", fname.c_str());
127 cycrow 3324
		if (node->Data()->isExternalFile())
3325
		{
3326
			CFileIO file(node->Data()->filePointer());
3327
			size_t size = 0;
3328
			unsigned char *data = file.readAll(&size);
3329
			ZipAdd(hz, buf, data, size);
3330
			delete data;
3331
		}
3332
		else
3333
			ZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());
6 cycrow 3334
	}
3335
 
109 cycrow 3336
	// if its a ship, then add any generated files
3337
	this->addGeneratedFiles(hz);
3338
 
6 cycrow 3339
	// add the data file
126 cycrow 3340
	Utils::CStringList list;
127 cycrow 3341
	Utils::CStringList addons;
3342
	if ( this->GeneratePackagerScript(false, &list, game, addons, true) )
6 cycrow 3343
	{
126 cycrow 3344
		if ( CFileIO("test.tmp").writeFile(&list) )
6 cycrow 3345
		{
3346
			ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");
52 cycrow 3347
			CFileIO::Remove("test.tmp");
6 cycrow 3348
		}
3349
	}
3350
 
3351
	CloseZip(hz);
3352
 
3353
	return true;
3354
}
3355
 
13 cycrow 3356
int CBaseFile::GetGameFromString(const Utils::String &sGame)
6 cycrow 3357
{
3358
	int iGame = GAME_ALL;
3359
	if ( sGame.Compare("ALL") )
3360
		iGame = GAME_ALL;
3361
	else if ( sGame.Compare("X3") )
3362
		iGame = GAME_X3;
3363
	else if ( sGame.Compare("X2") )
3364
		iGame = GAME_X2;
3365
	else if ( sGame.Compare("X3TC") )
3366
		iGame = GAME_X3TC;
126 cycrow 3367
	else if (sGame.Compare("X3AP"))
6 cycrow 3368
		iGame = GAME_X3AP;
126 cycrow 3369
	else if (sGame.Compare("X3FL"))
3370
		iGame = GAME_X3FL;
13 cycrow 3371
	else if ( sGame.isNumber() )
3372
		iGame = sGame;
6 cycrow 3373
 
3374
	return iGame;
3375
}
3376
 
13 cycrow 3377
Utils::String CBaseFile::ConvertGameToString(int iGame)
6 cycrow 3378
{
13 cycrow 3379
	Utils::String game = "ALL";
6 cycrow 3380
 
3381
	switch(iGame) {
3382
		case GAME_ALL:
127 cycrow 3383
		case GAME_ALLNEW:
6 cycrow 3384
			game = "ALL";
3385
			break;
3386
		case GAME_X2:
3387
			game = "X2";
3388
			break;
3389
		case GAME_X3:
3390
			game = "X3";
3391
			break;
3392
		case GAME_X3TC:
3393
			game = "X3TC";
3394
			break;
3395
		case GAME_X3AP:
3396
			game = "X3AP";
3397
			break;
126 cycrow 3398
		case GAME_X3FL:
3399
			game = "X3FL";
3400
			break;
6 cycrow 3401
		default:
3402
			game = (long)iGame;
3403
	}
3404
 
3405
	return game;
3406
}
3407
 
3408
bool CBaseFile::IsGameInPackage(int game)
3409
{
3410
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3411
		if ( node->Data()->GetGame() == game )
3412
			return true;
3413
	}
3414
 
3415
	return false;
3416
}
3417
 
3418
bool CBaseFile::IsAnyGameInPackage()
3419
{
3420
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3421
		if ( node->Data()->GetGame() )
3422
			return true;
3423
	}
3424
 
3425
	return false;
3426
}
3427
 
88 cycrow 3428
Utils::String builtInWares()
3429
{
3430
	Utils::String str;
3431
	str += "28;0;0;0;0;59;5753;0;35714;1;1;0;35714;-100000;0;0;SS_WARE_SW_NEW1;\n";
3432
	str += "28;0;0;0;0;60;5763;0;33232;1;1;0;33232;0;1043;0;SS_WARE_SW_NEW2;\n";
3433
	str += "28;0;0;0;0;61;5773;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW3;\n";
3434
	str += "28;0;0;0;0;62;5783;0;56;1;1;0;56;-100000;0;0;SS_WARE_SW_NEW4;\n";
3435
	str += "28;0;0;0;0;63;5793;0;88;1;1;0;88;-100000;0;0;SS_WARE_SW_NEW5;\n";
3436
	str += "28;0;0;0;0;64;5803;0;283;1;1;0;283;-100000;0;0;SS_WARE_SW_NEW6;\n";
3437
	str += "28;0;0;0;0;65;5813;0;383;1;1;0;383;-100000;0;0;SS_WARE_SW_NEW7;\n";
3438
	str += "28;0;0;0;0;66;5823;0;1389;1;1;0;1389;-100000;1043;0;SS_WARE_SW_NEW8;\n";
3439
	str += "28;0;0;0;0;67;5833;0;3396;1;1;0;3396;-100000;0;0;SS_WARE_SW_NEW9;\n";
3440
	str += "28;0;0;0;0;68;5843;0;4215;1;1;0;4215;-100000;0;0;SS_WARE_SW_NEW10;\n";
3441
	str += "28;0;0;0;0;69;5853;0;5635;1;1;0;5635;-100000;0;0;SS_WARE_SW_NEW11;\n";
3442
	str += "28;0;0;0;0;70;5863;0;65735;1;1;0;65735;-100000;0;0;SS_WARE_SW_NEW12;\n";
3443
	str += "28;0;0;0;0;71;5873;0;17857;1;1;0;17857;333;1043;0;SS_WARE_SW_NEW13;\n";
3444
	str += "28;0;0;0;0;72;5883;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW14;\n";
3445
	str += "28;0;0;0;0;73;5893;0;324515;1;1;0;324515;-100000;0;0;SS_WARE_SW_NEW15;\n";
3446
	str += "28;0;0;0;0;74;5903;0;638508;1;1;0;638508;-100000;0;0;SS_WARE_SW_NEW16;\n";
3447
	str += "28;0;0;0;0;75;5913;0;225755;1;1;0;225755;-100000;0;0;SS_WARE_SW_NEW17;\n";
3448
	str += "28;0;0;0;0;76;5923;0;1931535;1;1;0;1931535;1000;0;0;SS_WARE_SW_NEW18;\n";
3449
	str += "28;0;0;0;0;77;5933;0;2209150;1;1;0;2209150;-100000;0;0;SS_WARE_SW_NEW19;\n";
3450
	str += "28;0;0;0;0;78;5943;0;6727565;1;1;0;6727565;-100000;0;0;SS_WARE_SW_NEW20;\n";
3451
	str += "28;0;0;0;0;85;9999;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_1;\n";
3452
	str += "28;0;0;0;0;86;15053;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_2;\n";
3453
	str += "28;0;0;0;0;87;15063;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_3;\n";
3454
	str += "28;0;0;0;0;88;15073;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_4;\n";
3455
	str += "28;0;0;0;0;89;15083;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_5;\n";
3456
	str += "28;0;0;0;0;90;15093;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_6;\n";
3457
 
3458
	return str;
3459
}
3460
 
3461
void CBaseFile::_addWaresToList(int iLang, CLinkList<SWareEntry> &list, const Utils::String &wares, enum WareTypes eType)
3462
{
3463
	int totalWares = 0;
3464
	Utils::String *w = wares.tokenise("\n", &totalWares);
3465
 
3466
	for(int i = 0; i < totalWares; i++) {
3467
		int textId = w[i].token(";", 7).toLong();
3468
		int useLang = iLang;
3469
		if ( !_pTextDB->exists(useLang, 17, textId) )
3470
			useLang = 44;
3471
		if ( !_pTextDB->exists(useLang, 17, textId) )
3472
			useLang = 49;
3473
		if ( _pTextDB->exists(useLang, 17, textId) ) {	
3474
			SWareEntry *ware = new SWareEntry;
3475
			ware->name = _pTextDB->get(useLang, 17, textId);
3476
			ware->description = _pTextDB->get(useLang, 17, textId + 1);
3477
			ware->id = w[i].token(";", -2);
3478
			ware->relval = w[i].token(";", 9).toLong();
3479
			ware->notority = w[i].token(";", 14).toLong();
3480
			ware->type = eType;
3481
			ware->position = i;
89 cycrow 3482
			ware->package = this;
88 cycrow 3483
			list.push_back(ware);
3484
		}
3485
	}
3486
 
3487
	CLEANSPLIT(w, totalWares);
3488
}
3489
 
3490
bool CBaseFile::readWares(int iLang, CLinkList<SWareEntry> &list, const Utils::String &empWares)
3491
{
3492
	_pTextDB->setLanguage(iLang);
3493
 
3494
	// now go through all emp wares and get the ones we have text for
3495
	_addWaresToList(iLang, list, empWares, Ware_EMP);
3496
	_addWaresToList(iLang, list, builtInWares(), Ware_BuiltIn);
3497
 
89 cycrow 3498
	return true;
3499
}
88 cycrow 3500
 
89 cycrow 3501
bool CBaseFile::_readCommands(int iLang, int iStartID, CLinkList<SCommandSlot> &list)
3502
{
3503
	_pTextDB->setLanguage(iLang);
3504
 
3505
	for(int i = 2; i <= 13; i++) {
3506
		for(int j = 0; j < 64; j++) {
3507
			int id = (i * 100) + j;
3508
			if ( _pTextDB->exists(iLang, iStartID + 2, id) ) {
3509
				SCommandSlot *slot = new SCommandSlot;
3510
				list.push_back(slot);
3511
 
3512
				slot->id = _pTextDB->get(iLang, iStartID, id);
3513
				slot->name = _pTextDB->get(iLang, iStartID + 2, id);
3514
				slot->shortName = _pTextDB->get(iLang, iStartID + 3, id);
3515
				slot->info = _pTextDB->get(iLang, iStartID + 14, id);
3516
				slot->slot = id;
3517
				slot->package = this;
3518
 			}
3519
		}
3520
	}
3521
 
3522
	for(int i = 1400; i <= 2000; i++) {
3523
		if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {
3524
			SCommandSlot *slot = new SCommandSlot;
3525
			list.push_back(slot);
3526
 
3527
			slot->id = _pTextDB->get(iLang, iStartID, i);
3528
			slot->name = _pTextDB->get(iLang, iStartID + 2, i);
3529
			slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);
3530
			slot->info = _pTextDB->get(iLang, iStartID + 14, i);
3531
			slot->slot = i;
3532
			slot->package = this;
3533
		}
3534
	}
3535
 
3536
	for(int i = 6000; i <= 9999; i++) {
3537
		if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {
3538
			SCommandSlot *slot = new SCommandSlot;
3539
			list.push_back(slot);
3540
 
3541
			slot->id = _pTextDB->get(iLang, iStartID, i);
3542
			slot->name = _pTextDB->get(iLang, iStartID + 2, i);
3543
			slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);
3544
			slot->info = _pTextDB->get(iLang, iStartID + 14, i);
3545
			slot->slot = i;
3546
			slot->package = this;
3547
		}
3548
	}
3549
 
88 cycrow 3550
	return true;
3551
}
3552
 
89 cycrow 3553
bool CBaseFile::readWingCommands(int iLang, CLinkList<SCommandSlot> &list)
3554
{
3555
	return _readCommands(iLang, 2028, list);
3556
}
3557
 
3558
bool CBaseFile::readCommands(int iLang, CLinkList<SCommandSlot> &list)
3559
{
3560
	return _readCommands(iLang, 2008, list);
3561
}
3562
 
6 cycrow 3563
int CBaseFile::FindFirstGameInPackage()
3564
{
3565
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3566
		if ( node->Data()->GetGame() )
3567
			return node->Data()->GetGame();
3568
	}
3569
 
3570
	return 0;
3571
}
3572
bool CBaseFile::IsMultipleGamesInPackage()
3573
{
3574
	int game = 0;
3575
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3576
		if ( node->Data()->GetGame() ) {
3577
			if ( game != node->Data()->GetGame() )
3578
				return true;
3579
			game = node->Data()->GetGame();
3580
		}
3581
	}
3582
 
3583
	return false;
3584
}