Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
#include "spk.h"
2
#include "emp.h"
3
 
4
#include <time.h>
5
#include <vector>
6
 
93 cycrow 7
#include "OriginalFiles.h"
98 cycrow 8
#include "spkdef.h"
160 cycrow 9
#include <set>
93 cycrow 10
 
1 cycrow 11
#ifdef _RAR
12
#include <unrar.h>
13
#endif
14
 
15
enum {READ_START, READ_GLOBAL, READ_SCRIPT, READ_SCRIPTFILE, READ_WARES};
16
enum { EXTRACT, TEST, PRINT, LIST };
17
 
18
typedef struct SDummyEntry {
19
	CyString		sSection;
20
	CyStringList	lEntries;
21
} SDummyEntry;
22
 
23
typedef struct SComponantEntry2 {
24
	CyString		sSection;
25
	CyStringList	lEntries;
26
} SComponantEntry2;
27
 
28
typedef struct SComponantEntry {
29
	CyString		sSection;
30
	CLinkList<SComponantEntry2>	lEntries;
31
} SComponantEntry;
32
 
118 cycrow 33
Utils::String CPackages::m_sTempDir;
79 cycrow 34
 
133 cycrow 35
//////////////////////////////////////////////////////////////////////////////////////
36
 
37
//////////////////////////////////////////////////////////////////////////////////////
38
 
93 cycrow 39
CPackages::CPackages() : m_pCurrentGameExe(NULL),
125 cycrow 40
	_pOriginalFiles(NULL),
41
	_pCurrentDir(NULL)	
1 cycrow 42
{
43
	m_bRenameText = false;
44
	m_iLanguage = 0;
45
	m_iGame = -1;
46
	m_iGameVersion = -1;
47
	m_iGameFlags = 0;
48
	m_bSurpressProtectedWarning = false;
49
	m_iMaxPatch = 1;
50
	m_iLastUpdated = 0;
51
	m_iFakePatch = -1;
52
	m_bVanilla = true;
53
	m_pEnabledMod = NULL;
54
	m_bForceModInstall = false;
55
	m_bLoaded = false;
56
	m_bRedo = false;
57
	m_bOldPlugin = false;
58
	m_bUsedWare = false;
59
	m_pPackageNode = NULL;
60
	m_bRemoveDir = false;
61
	m_bDisableVanilla = false;
62
	m_bLoadVFS = true;
63
	m_iSaveGame = -1;
64
	m_iSaveGameManager = -1;
65
	m_bForceEMP = false;
66
 
67
	for ( int i = 0; i < WAREBUFFERS; i++ )
68
		m_iWareBuffer[i] = 0;
69
	m_iShipBuffer = 0;
70
}
71
 
72
CPackages::~CPackages ()
73
{
74
	m_lDisableList.clear();
75
	m_lEnableList.clear();
76
	this->Reset();
77
}
78
 
158 cycrow 79
void CPackages::setCurrentDir(const Utils::String &dir)
125 cycrow 80
{ 
158 cycrow 81
	m_sCurrentDir = dir;
125 cycrow 82
	if (_pCurrentDir) delete _pCurrentDir;
83
	_pCurrentDir = new GameDirectory();
158 cycrow 84
	_pCurrentDir->dir = dir;
125 cycrow 85
	_pCurrentDir->id = -1;
86
 
87
	m_gameExe.GetDirectoryData(_pCurrentDir);
88
	_pCurrentDir->langid = this->GetGameLanguage(_pCurrentDir->dir);
89
	if (_pCurrentDir->langid > 0)
90
		_pCurrentDir->langname = this->ConvertLanguage(_pCurrentDir->langid);
91
}
92
 
1 cycrow 93
void CPackages::SetVanilla(bool b)
94
{
95
	if ( m_bVanilla != b && b ) {
96
		for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() ) {
97
			pNode->Data()->SetModifiedEnabled(pNode->Data()->IsEnabled());
98
		}
99
	}
100
	m_bVanilla = b;
101
}
102
 
160 cycrow 103
void CPackages::setMod(const Utils::String &mod)
104
{
105
	if (mod != "PluginManager")
106
		m_sSetMod = mod;
107
}
108
 
126 cycrow 109
void CPackages::setSaveGameManager(bool managed)
110
{
111
	m_iSaveGameManager = managed ? 1 : 0;
112
 
113
	if (managed)
114
	{
115
		// find new save directory
116
		CDirIO dir(this->saveDirectory());
117
		if (dir.exists())
118
		{
119
			int id = 1;
120
			while (dir.exists(Utils::String::PadNumber(id, 4)))
121
				++id;
122
			Utils::String d = Utils::String::PadNumber(id, 4);
160 cycrow 123
			dir.create(d);
126 cycrow 124
			_sSaveDir = d;
125
 
126
			CDirIO destDir1(dir.dir(d));
160 cycrow 127
			destDir1.create("Vanilla");
126 cycrow 128
			destDir1.cd("Vanilla");
129
			CDirIO destDir2(dir.dir(d));
160 cycrow 130
			destDir2.create("Modified");
126 cycrow 131
			destDir2.cd("Modified");
132
 
133
			Utils::CStringList files;
134
			if (dir.dirList(files, Utils::String::Null(), "*.sav"))
135
			{
136
				for (auto itr = files.begin(); itr != files.end(); ++itr)
137
				{
138
					Utils::String f = dir.file((*itr)->str);
139
					CFileIO(f).copy(destDir1.file((*itr)->str));
140
					CFileIO(f).copy(destDir2.file((*itr)->str));
141
				}
142
			}
143
		}
144
	}
145
	else
146
	{
147
		_sSaveDir.clear();
148
	}
149
}
150
 
151
 
1 cycrow 152
void CPackages::Reset()
153
{
154
	m_lFiles.MemoryClear();
155
	m_lUninstallFiles.MemoryClear();
156
	for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )
157
		pNode->Data()->GetFileList()->clear();
158
	m_lPackages.MemoryClear();
93 cycrow 159
 
160
	SafeDelete(_pOriginalFiles);
161
 
1 cycrow 162
	m_iFakePatch = -1;
163
	m_bVanilla = false;
164
	m_pEnabledMod = NULL;
165
	m_bLoaded = false;
166
	m_iLanguage = 0;
167
	m_bOldPlugin = false;
168
	m_bRemoveDir = false;
169
	m_bDisableVanilla = false;
170
	m_bSurpressProtectedWarning = false;
171
	m_iSaveGame = -1;
172
	m_iSaveGameManager = -1;
173
	m_sSetMod = "";
174
 
175
	for ( int i = 0; i < WAREBUFFERS; i++ )
176
	{
177
		m_iWareBuffer[i] = 0;
178
		m_lGameWares[i].MemoryClear();
179
	}
180
	m_iShipBuffer = 0;
181
 
182
	m_lGameShips.MemoryClear();
183
	m_lAvailablePackages.MemoryClear();
184
	m_lInstallList.MemoryClear();
185
	m_lEnableList.MemoryClear();
186
	m_lDisableList.MemoryClear();
187
 
160 cycrow 188
	m_lCreatedFiles.clear();
189
	m_lNonRemovedFiles.clear();
190
	m_lGlobals.clear();
191
	m_lFakePatchOrder.clear();
125 cycrow 192
	if (_pCurrentDir)
193
		delete _pCurrentDir;
194
	_pCurrentDir = NULL;
1 cycrow 195
}
196
 
197
void CPackages::LoadVirtualFileSystem()
198
{
199
	if ( !m_bLoadVFS )
200
		return;
201
 
125 cycrow 202
	m_pGameVFS.setAddon(this->getAddonDir());
1 cycrow 203
	if ( m_pEnabledMod )
204
	{
205
		C_File *f;
206
		for ( f = m_pEnabledMod->GetFirstFile(FILETYPE_MOD); f; f = m_pEnabledMod->GetNextFile(f) )
207
		{
208
			if ( f->IsFakePatch() ) continue;
209
			if ( f->CheckFileExt("cat") ) break;
210
		}
211
 
212
		if ( f )
158 cycrow 213
			m_pGameVFS.LoadFilesystem(m_sCurrentDir, f->filePointer(), 0);
1 cycrow 214
		else
158 cycrow 215
			m_pGameVFS.LoadFilesystem(m_sCurrentDir, 0);
1 cycrow 216
	}
217
	else
158 cycrow 218
		m_pGameVFS.LoadFilesystem(m_sCurrentDir, 0);
1 cycrow 219
}
220
 
83 cycrow 221
bool CPackages::isOldDir(const Utils::String &dir)
1 cycrow 222
{
223
	bool oldPlugin = false;
224
 
225
	CFileIO datFile(dir + "/PluginManager/pluginmanager.dat");
52 cycrow 226
	if ( datFile.exists() )
1 cycrow 227
	{
83 cycrow 228
		std::vector<Utils::String> *readFile = datFile.readLines();
1 cycrow 229
		if ( readFile )
230
		{
231
			for ( int i = 0; i < (int)readFile->size(); i++ )
232
			{
83 cycrow 233
				Utils::String line(readFile->at(i));
234
				Utils::String cmd = line.token(":", 1);
235
				if ( cmd.Compare("<script>") || cmd.Compare("</scripts>") )
1 cycrow 236
					break;
83 cycrow 237
				else if ( cmd.Compare("spkinstaller") || cmd.Compare("globalfiles") )
1 cycrow 238
					break;
83 cycrow 239
				else if ( cmd.Compare("pluginmanager") )
1 cycrow 240
				{
241
					oldPlugin = true;
242
					break;
243
				}
244
			}
245
 
246
			delete readFile;
247
		}
248
	}
249
 
250
	return oldPlugin;
251
}
252
 
158 cycrow 253
bool CPackages::Read(CyString dir, CProgressInfo* progress)
1 cycrow 254
{
158 cycrow 255
	return read(dir.ToString(), progress);
121 cycrow 256
}
257
 
158 cycrow 258
bool CPackages::read(const Utils::String& dir, CProgressInfo* progress)
121 cycrow 259
{
1 cycrow 260
	m_sCurrentDir = dir;
158 cycrow 261
	m_sCurrentDir = m_sCurrentDir.findReplace("\\", "/");
262
	this->setCurrentDir(dir);
1 cycrow 263
	m_bOldPlugin = false;
160 cycrow 264
	m_lCreatedFiles.clear();
1 cycrow 265
	m_bRemoveDir = false;
266
	m_bSurpressProtectedWarning = false;
267
	m_iSaveGame = -1;
268
	m_iSaveGameManager = -1;
160 cycrow 269
	m_lNonRemovedFiles.clear();
270
	m_lGlobals.clear();
271
	m_lFakePatchOrder.clear();
1 cycrow 272
 
93 cycrow 273
	if ( _pOriginalFiles ) delete _pOriginalFiles;
158 cycrow 274
	_pOriginalFiles = new COriginalFiles(m_sCurrentDir);
93 cycrow 275
 
1 cycrow 276
	m_bVanilla = true;
277
 
278
	// check the pluginmanager data file exists
279
	CFileIO datFile(m_sCurrentDir + "/PluginManager/pluginmanager.dat");
52 cycrow 280
	if ( datFile.exists() )
1 cycrow 281
	{
83 cycrow 282
		std::vector<Utils::String> *readFile = datFile.readLines();
1 cycrow 283
		if ( readFile )
284
		{
285
			float fVersion = 0;
286
			bool spkinstaller = false;
287
			float fBeta = 0;
288
 
289
			int iStatus = READ_START;
290
			int iCount = 0;
291
			int iWare = -1;
292
			int iShip = -1;
293
 
294
			CBaseFile *packageFile = 0;
295
 
296
			for ( int i = 0; i < (int)readFile->size(); i++ )
297
			{
83 cycrow 298
				Utils::String line(readFile->at(i));
1 cycrow 299
 
83 cycrow 300
				Utils::String cmd = line.token(":", 1).lower();
301
				Utils::String rest = line.tokens(":", 2).removeFirstSpace();
1 cycrow 302
 
303
				if ( iStatus == READ_GLOBAL )
304
				{
305
					if ( cmd == "<script>" )
306
					{
307
						packageFile = new CSpkFile();
308
						iStatus = READ_SCRIPT;
309
					}
310
					else if ( cmd == "<ship>" )
311
					{
312
						packageFile = new CXspFile();
313
						iStatus = READ_SCRIPT;
314
					}
315
					else if ( cmd == "<base>" )
316
					{
317
						packageFile = new CBaseFile();
318
						iStatus = READ_SCRIPT;
319
					}
320
					else if ( cmd == "<archive>" )
321
					{
322
						packageFile = new CArchiveFile();
323
						iStatus = READ_SCRIPT;
324
					}
325
					else if ( cmd != "</scripts>" )
326
					{
327
						int game = 0;
328
						bool disabled = false;
83 cycrow 329
						Utils::String fileName = line.tokens(":", 5);
330
						Utils::String origName;
331
						if ( fileName.left(2) == "D#" )
1 cycrow 332
						{
83 cycrow 333
							fileName.erase(0, 2);
1 cycrow 334
							disabled = true;
335
						}
83 cycrow 336
						if ( fileName.left(2) == "G#" ) {
337
							fileName.erase(0, 2);
338
							game = fileName.token("#", 1).toLong();
339
							fileName = fileName.tokens("#", 2);
1 cycrow 340
						}
83 cycrow 341
						if ( fileName.isin("O#") )
1 cycrow 342
						{
83 cycrow 343
							origName = fileName.token("O#", 2);
344
							fileName = fileName.token("O#", 1);
1 cycrow 345
						}
346
 
158 cycrow 347
						C_File *newFile = new C_File(m_sCurrentDir + fileName);
127 cycrow 348
						newFile->setGame(game);
1 cycrow 349
						newFile->SetOriginalName(origName);
350
						newFile->SetDisabled(disabled);
127 cycrow 351
						newFile->setFileType((FileType)line.token(":", 1).toLong());
83 cycrow 352
						newFile->SetCreationTime((time_t)line.token(":", 2).toLong());
353
						newFile->SetDir(line.token(":", 3));
354
						if ( line.token(":", 4).toLong() )
1 cycrow 355
							newFile->SetShared(true);
356
						newFile->UpdateSigned();
357
 
358
						m_lFiles.push_back(newFile);
359
					}
360
				}
361
				else if ( iStatus == READ_SCRIPT )
362
				{
363
					if ( cmd == "installspk" )
83 cycrow 364
						packageFile->setFilename(rest);
1 cycrow 365
					else if ( cmd == "files" )
366
					{
367
						iStatus = READ_SCRIPTFILE;
368
						if ( spkinstaller )
369
						{
370
							int max;
83 cycrow 371
							Utils::String *files = rest.tokenise(" ", &max);
1 cycrow 372
 
373
							for ( int i = 0; i < max; i++ )
374
							{
83 cycrow 375
								int fileNum = files[i].toLong();
1 cycrow 376
								if ( fileNum >= 0 && fileNum < m_lFiles.size() )
377
									packageFile->AddFile(m_lFiles[fileNum]);
378
							}
379
 
380
							CLEANSPLIT(files, max);
381
						}
382
					}
383
					else if ( cmd == "disabled" )
384
						packageFile->SetEnabled(false);
385
					else if ( cmd == "modifieddisabled" )
386
						packageFile->SetModifiedEnabled(false);
387
					else if ( cmd == "icon" )
388
					{
127 cycrow 389
						C_File *icon = new C_File(rest.tokens(" ", 2));
83 cycrow 390
						packageFile->SetIcon(icon, rest.token(" ", 1));
1 cycrow 391
					}
392
					else
83 cycrow 393
						packageFile->ParseValueLine(line);
1 cycrow 394
				}
395
				else if ( iStatus == READ_SCRIPTFILE )
396
				{
397
					if ( cmd == "<script>" )
398
					{
399
						if ( packageFile->IsMod() && packageFile->IsEnabled() )
400
							m_pEnabledMod = packageFile;
401
 
402
						m_lPackages.push_back(packageFile);
403
						this->ConvertOldPackage(packageFile);
404
						packageFile = new CSpkFile();
405
						iStatus = READ_SCRIPT;
406
 
407
					}
408
					else if ( cmd == "<ship>" )
409
					{
410
						m_lPackages.push_back(packageFile);
411
						this->ConvertOldPackage(packageFile);
412
						packageFile = new CXspFile();
413
						iStatus = READ_SCRIPT;
414
					}
415
					else if ( cmd == "<base>" )
416
					{
417
						m_lPackages.push_back(packageFile);
418
						this->ConvertOldPackage(packageFile);
419
						packageFile = new CBaseFile();
420
						iStatus = READ_SCRIPT;
421
					}
422
					else if ( cmd == "<archive>" )
423
					{
424
						m_lPackages.push_back(packageFile);
425
						this->ConvertOldPackage(packageFile);
426
						packageFile = new CArchiveFile();
427
						iStatus = READ_SCRIPT;
428
					}
429
					else if ( cmd == "</scripts>" )
430
					{
431
						if ( packageFile->IsMod() && packageFile->IsEnabled() )
432
							m_pEnabledMod = packageFile;
433
 
434
						m_lPackages.push_back(packageFile);
435
						this->ConvertOldPackage(packageFile);
436
					}
437
					else
438
					{
83 cycrow 439
						int fileNum = line.token("::", 1).toLong();
1 cycrow 440
						if ( fileNum >= 0 && fileNum < m_lFiles.size() )
441
							packageFile->AddFile(m_lFiles[fileNum]);
442
					}
443
				}
444
				else if ( iWare != -1 )
445
				{
446
					--iCount;
447
 
448
					SGameWare *gm = new SGameWare;
83 cycrow 449
					gm->iPos = line.token(" ", 1).toLong();
450
					gm->iType = line.token(" ", 2).toLong();
451
					gm->cType = line.token(" ", 3)[0];
1 cycrow 452
					gm->pWare = NULL;
83 cycrow 453
					gm->sWareName = line.tokens(" ", 4);
1 cycrow 454
					m_lGameWares[iWare].push_back(gm);
455
					if ( iCount <= 0 )
456
						iWare = -1;
457
				}
458
				else if ( iShip != -1 )
459
				{
460
					--iCount;
461
 
462
					SGameShip *gm = new SGameShip;
83 cycrow 463
					gm->iType = line.token(" ", 1).toLong();
464
					if ( line.token(" ", 2).left(4) == "$#C:" )
1 cycrow 465
					{
83 cycrow 466
						gm->sShipClass = line.token(" ", 2).right(-4);
467
						gm->sShipID = line.tokens(" ", 3);
1 cycrow 468
					}
469
					else
470
					{
83 cycrow 471
						gm->sShipID = line.tokens(" ", 2);
1 cycrow 472
						gm->sShipClass = "OBJ_SHIP_M5";
473
					}
474
					gm->pPackage = NULL;
475
					m_lGameShips.push_back(gm);
476
					if ( iCount <= 0 )
477
						iShip = -1;
478
				}
479
				else if ( cmd.Compare("savegamemanager") )
83 cycrow 480
					m_iSaveGameManager = rest.toLong();
1 cycrow 481
				else if ( cmd.Compare("savegame") )
83 cycrow 482
					m_iSaveGame = rest.toLong();
1 cycrow 483
				else if ( cmd == "fakepatch" )
83 cycrow 484
					m_iFakePatch = rest.toLong();
1 cycrow 485
				else if ( cmd == "updatetime" )
83 cycrow 486
					m_iLastUpdated = rest.toLong();
1 cycrow 487
				else if ( cmd == "surpressprotectedwarning" )
488
					m_bSurpressProtectedWarning = true;
489
				else if ( cmd == "pluginmanager" )
490
				{
83 cycrow 491
					fVersion = rest.toFloat();
1 cycrow 492
					m_bOldPlugin = true;
493
				}
494
				else if ( cmd == "setmod" )
495
					m_sSetMod = rest;
496
				else if ( cmd == "shipbuffer" )
83 cycrow 497
					m_iShipBuffer = rest.toLong();
126 cycrow 498
				else if(cmd == "savedir")
499
					_sSaveDir = rest;
1 cycrow 500
				else if ( cmd == "warebuffers" )
501
				{
83 cycrow 502
					int max = rest.countToken(" ");
1 cycrow 503
					for ( int i = 0; i < WAREBUFFERS; i++ )
504
					{
505
						if ( i > max )
506
							m_iWareBuffer[i] = 0;
507
						else
83 cycrow 508
							m_iWareBuffer[i] = rest.token(" ", i + 1).toLong();
1 cycrow 509
					}
510
				}
511
				else if ( cmd == "createdfile" )
160 cycrow 512
					m_lCreatedFiles.pushBack(rest);
1 cycrow 513
				else if ( cmd == "wares" )
514
				{
83 cycrow 515
					iWare = rest.token(" ", 1).toLong();
516
					iCount = rest.token(" ", 2).toLong();
1 cycrow 517
				}
518
				else if ( cmd == "ships" )
519
				{
520
					iShip = 1;
83 cycrow 521
					iCount = rest.token(" ", 1).toLong();
1 cycrow 522
				}
523
				else if ( cmd == "modified" )
524
					m_bVanilla = false;
525
				else if ( cmd == "spkinstaller" )
526
				{
83 cycrow 527
					fVersion = rest.toFloat();
1 cycrow 528
					spkinstaller = true;
529
				}
93 cycrow 530
				else if ( cmd == "betaversion" )
83 cycrow 531
					fBeta = rest.toFloat();
93 cycrow 532
				else if ( cmd == "uninstall" )
1 cycrow 533
				{
534
					C_File *uf = new C_File();
160 cycrow 535
					uf->setFileType(FILETYPE_SCRIPT);
83 cycrow 536
					uf->SetCreationTime(rest.token(" ", 1).toLong());
537
					uf->SetFilename(m_sCurrentDir + "/Scripts/" + rest.tokens(" ", 2));
1 cycrow 538
					m_lUninstallFiles.push_back(uf);
539
				}
93 cycrow 540
				else if ( cmd == "nonremovedfile" )
1 cycrow 541
				{
83 cycrow 542
					if ( !CFileIO::Remove(rest) )
160 cycrow 543
						m_lNonRemovedFiles.pushBack(rest);
1 cycrow 544
				}
93 cycrow 545
				else if ( cmd == "original" )
546
					_pOriginalFiles->parse(rest);
1 cycrow 547
				else if ( cmd.Compare("GlobalSetting") )
160 cycrow 548
					m_lGlobals.pushBack(rest.token(":", 1), rest.tokens(":", 2));
1 cycrow 549
				else if ( cmd.Compare("FakePatchOrder") )
160 cycrow 550
					m_lFakePatchOrder.pushBack(rest.token(":", 1), rest.tokens(":", 2));
88 cycrow 551
				else if ( cmd.Compare("EMPPriceOverride") )
552
					this->addEMPPriceOverride(rest.token(" ", 1).toLong(), rest.token(" ", 2).toLong());
553
				else if ( cmd.Compare("EMPNotoOverride") )
554
					this->addEMPNotoOverride(rest.token(" ", 1).toLong(), rest.token(" ", 2).toLong());
555
				else if ( cmd.Compare("BuiltInWarePriceOverride") )
556
					this->addBuiltInWarePriceOverride(rest.token(" ", 1).toLong(), rest.token(" ", 2).toLong());
557
				else if ( cmd.Compare("BuiltInWareNotoOverride") )
558
					this->addBuiltInWareNotoOverride(rest.token(" ", 1).toLong(), rest.token(" ", 2).toLong());
559
				else if ( cmd.Compare("CustomWarePriceOverride") )
560
					this->addCustomWarePriceOverride(rest.token(";", 1), rest.token(";", 2).toLong());
561
				else if ( cmd.Compare("CustomWareNotoOverride") )
562
					this->addCustomWareNotoOverride(rest.token(";", 1), rest.token(";", 2).toLong());
1 cycrow 563
				else if ( cmd == "globalfiles" )
564
					iStatus = READ_GLOBAL;
565
 
566
				if ( progress )
567
				{
568
					progress->UpdateProgress((long)i, (long)readFile->size());
569
				}
570
			}
571
			readFile->clear();
572
 
573
			if ( !spkinstaller )
574
				m_bRedo = true;
575
 
576
			delete readFile;
577
		}
578
	}
579
 
580
	if ( m_pEnabledMod && !m_pEnabledMod->IsEnabled() )
581
		m_pEnabledMod = NULL;
582
 
158 cycrow 583
	m_iGame = m_gameExe.GetGameType(m_sCurrentDir) + 1;
584
	m_pCurrentGameExe = m_gameExe.GetGame(m_gameExe.GetGameType(m_sCurrentDir));
56 cycrow 585
	Utils::String sGameVersion;
158 cycrow 586
	m_iGameVersion = m_gameExe.GetGameVersion(m_sCurrentDir, &sGameVersion) + 1;
56 cycrow 587
	m_sGameVersion = sGameVersion;
1 cycrow 588
	m_iGameFlags = m_gameExe.GetGameFlags(m_iGame - 1);
589
	m_iMaxPatch = m_gameExe.GetMaxPatch(m_iGame - 1);
590
 
591
	// find the fake patch
592
	if ( !ReadyFakePatch() )
593
		return false;
594
 
595
	this->RemoveCreatedFiles();
87 cycrow 596
	this->createPluginManagerOpenText();
1 cycrow 597
 
598
	// match up wares
599
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
600
	{
601
		if ( node->Data()->GetType() == TYPE_SPK )
602
		{
603
			CSpkFile *p = (CSpkFile *)node->Data();
604
			for ( CListNode<SWares> *wNode = p->GetWaresList()->Front(); wNode; wNode = wNode->next() )
605
			{
606
				SWares *w = wNode->Data();
607
				for ( CListNode<SGameWare> *gNode = m_lGameWares[CPackages::ConvertWareType(w->cType)].Front(); gNode; gNode = gNode->next() )
608
				{
160 cycrow 609
					if ( w->sID == gNode->Data()->sWareName )
1 cycrow 610
					{
611
						gNode->Data()->pWare = w;
612
						break;
613
					}
614
				}
615
			}
616
		}
617
		else if ( node->Data()->GetType() == TYPE_XSP )
618
		{
619
			CXspFile *p = (CXspFile *)node->Data();
620
			for ( CListNode<SGameShip> *gNode = m_lGameShips.Front(); gNode; gNode = gNode->next() )
621
			{
160 cycrow 622
				if ( p->GetShipID().Compare(gNode->Data()->sShipID) )
1 cycrow 623
				{
624
					gNode->Data()->pPackage = p;
625
					break;
626
				}
627
			}
628
		}
629
	}
630
 
631
	// check the purged time
632
	this->PurgeGameObjects();
633
 
634
	m_bLoaded = true;
635
 
636
	return true;
637
}
638
 
639
void CPackages::RemoveCreatedFiles()
640
{
160 cycrow 641
	for(auto itr = m_lCreatedFiles.begin(); itr != m_lCreatedFiles.end(); itr++)
1 cycrow 642
	{
160 cycrow 643
		if ( CFileIO::Exists((*itr)->str) )
644
			CFileIO::Remove((*itr)->str);
645
		else if ( CFileIO::Exists(m_sCurrentDir + "/" + (*itr)->str) )
646
			CFileIO::Remove(m_sCurrentDir + "/" + (*itr)->str);
1 cycrow 647
	}
648
 
160 cycrow 649
	m_lCreatedFiles.clear();
1 cycrow 650
}
651
 
652
void CPackages::PurgeGameObjects()
653
{
654
	// check for the log file
102 cycrow 655
	Utils::String logDir = logDirectory();
656
	CFileIO LogFile(logDir + "/log0" + Utils::String::PadNumber(PMTEXTFILE, 4) + ".txt");
52 cycrow 657
	if ( LogFile.exists() )
1 cycrow 658
	{
659
		// read the log file to memory
160 cycrow 660
		std::vector<Utils::String> *lines = LogFile.readLines();
1 cycrow 661
		if ( lines )
662
		{
663
			for ( int i = 0; i < (int)lines->size(); i++ )
664
			{
160 cycrow 665
				Utils::String line(lines->at(i));
666
				Utils::String start = line.token(":", 1).toLower();
667
				Utils::String rest = line.token(":", 2).removeFirstSpace();
1 cycrow 668
				if ( start.Compare("purged") )
669
				{
160 cycrow 670
					long time = rest.toLong();
1 cycrow 671
					if ( time == m_iLastUpdated )
672
					{
673
						this->PurgeWares();
674
						this->PurgeShips();
675
						this->RemoveUninstallScripts();
676
					}
677
				}
678
			}
679
 
680
			delete lines;
681
		}
682
		// remove the log file
52 cycrow 683
		LogFile.remove();
1 cycrow 684
	}
685
}
686
 
687
void CPackages::PurgeWares()
688
{
689
	// mark all delete wares as available
690
	for ( int i = 0; i < WAREBUFFERS; i++ )
691
	{
692
		for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() )
693
		{
694
			SGameWare *w = node->Data();
695
			if ( !w ) continue;
696
			if ( w->iType == WARETYPE_DELETED )
697
				w->iType = WARETYPE_NONE;
698
		}
699
		m_lGameWares[i].RemoveEmpty();
700
	}
701
}
702
 
703
void CPackages::PurgeShips()
704
{
705
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
706
	{
707
		if ( !node->Data() )
708
			continue;
709
		if ( node->Data()->iType == WARETYPE_DELETED )
710
			node->Data()->iType = WARETYPE_NONE;
711
	}
712
	m_lGameShips.RemoveEmpty();
713
}
714
 
102 cycrow 715
Utils::String CPackages::logDirectory()
1 cycrow 716
{
158 cycrow 717
	Utils::String logDir = m_sCurrentDir;
56 cycrow 718
	if ( m_iGameFlags & EXEFLAG_MYDOCLOG ) {
1 cycrow 719
		SGameExe *exe = m_gameExe.GetGame(m_iGame - 1);
56 cycrow 720
		if ( exe ) {
721
			if ( !exe->sMyDoc.empty() )
127 cycrow 722
				logDir = m_sMyDoc + "/" + exe->sMyDoc;
1 cycrow 723
		}
724
	}
725
 
726
	return logDir;
727
}
728
 
102 cycrow 729
Utils::String CPackages::logDirectory(const Utils::String &gameExe)
1 cycrow 730
{
158 cycrow 731
	Utils::String logDir = m_sCurrentDir;
1 cycrow 732
	if ( m_iGameFlags & EXEFLAG_MYDOCLOG )
733
	{
57 cycrow 734
		SGameExe *exe = m_gameExe.gameExe(CFileIO(gameExe).filename());
1 cycrow 735
		if ( exe )
736
		{
56 cycrow 737
			if ( !exe->sMyDoc.empty() )
127 cycrow 738
				logDir = m_sMyDoc + "/" + exe->sMyDoc;
1 cycrow 739
		}
740
	}
741
 
102 cycrow 742
	return CFileIO(logDir).fullFilename();
1 cycrow 743
}
744
 
102 cycrow 745
Utils::String CPackages::saveDirectory()
1 cycrow 746
{
102 cycrow 747
	Utils::String logDir = this->logDirectory();
1 cycrow 748
	if ( m_iGameFlags & EXEFLAG_NOSAVESUBDIR )
749
		return logDir;
750
 
751
	return logDir + "/save";
752
}
753
 
754
bool CPackages::ReadyFakePatch()
755
{
756
	// already exists, lets skip it
52 cycrow 757
	if ( CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat").ExistsOld() && CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat").ExistsOld() )
1 cycrow 758
		return true;
759
 
760
	// if only one of them exists, lets remove them
52 cycrow 761
	if ( CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat").ExistsOld() )
158 cycrow 762
		CFileIO::Remove(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat");
52 cycrow 763
	if ( CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat").ExistsOld() )
158 cycrow 764
		CFileIO::Remove(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat");
1 cycrow 765
 
85 cycrow 766
	// fake patch is not being used
767
	if ( m_iFakePatch < 0 ) return true;
1 cycrow 768
	// now lets find the fake patch
158 cycrow 769
	Utils::String useFile;
1 cycrow 770
	if ( m_iFakePatch > 0 )
771
	{
158 cycrow 772
		Utils::String file = Utils::String::PadNumber(m_iFakePatch, 2);
1 cycrow 773
		if ( CheckValidPluginManagerFile(file) )
774
			useFile = file;
775
		else if ( CheckIfPluginManagerFile(file) )
776
			useFile = file;
777
	}
778
 
158 cycrow 779
	if ( useFile.empty() )
1 cycrow 780
	{
781
		int nextfree = this->FindNextFakePatch();
782
		--nextfree; // gets the end fake patch
783
 
784
		// work backwards till we find a valid one
785
		while ( nextfree > m_iMaxPatch )
786
		{
158 cycrow 787
			Utils::String file = Utils::String::PadNumber(nextfree, 2);
1 cycrow 788
			if ( CheckValidPluginManagerFile(file) )
789
			{
790
				useFile = file;
791
				break;
792
			}
793
			--nextfree;
794
		}
795
	}
796
 
797
	CyString addonDir = this->GetAddonDir();
798
 
799
	// couldn't find the correct file, lets search for it
158 cycrow 800
	if ( useFile.empty() ) {
1 cycrow 801
		int nextfree = this->FindNextFakePatch();
802
		--nextfree; // gets the end fake patch
803
 
804
		// work backwards till we find a valid one
805
		while ( nextfree > m_iMaxPatch )
806
		{
158 cycrow 807
			Utils::String file = Utils::String::PadNumber(nextfree, 2);
1 cycrow 808
			if ( CheckIfPluginManagerFile(file) )
809
			{
810
				useFile = file;
811
				break;
812
			}
813
			--nextfree;
814
		}		
815
	}
816
 
158 cycrow 817
	if ( !useFile.empty() )
1 cycrow 818
	{
819
		// lets check whats in the file first
820
		CCatFile openCat;
158 cycrow 821
		if ( openCat.open(m_sCurrentDir + "/" + useFile + ".cat", addonDir.ToString(), CATREAD_CATDECRYPT, false) == CATERR_NONE )
1 cycrow 822
		{
124 cycrow 823
			std::vector<SInCatFile *> *files = openCat.GetFiles();
1 cycrow 824
			bool found = false;
825
			if ( files )
826
			{
124 cycrow 827
				Utils::String useAddonDir = addonDir.ToString();
828
				if ( !useAddonDir.empty() ) useAddonDir += "\\";
829
				for (auto itr = files->cbegin(); itr != files->cend(); itr++)
1 cycrow 830
				{
124 cycrow 831
					if ((*itr)->sFile.Compare("PlugMan\\TFake.pck") )
1 cycrow 832
						continue;
124 cycrow 833
					if ((*itr)->sFile.Compare(useAddonDir + "t\\44" + Utils::String::PadNumber(PMTEXTFILE, 4) + ".pck") )
1 cycrow 834
						continue;
124 cycrow 835
					if ((*itr)->sFile.Compare(useAddonDir + "t\\" + Utils::String::PadNumber(PMTEXTFILE, 4) + "-L044.pck") )
1 cycrow 836
						continue;
837
 
838
					found = true;
839
					break;
840
				}
841
			}
842
 
843
			// no files, jsut delete them
844
			CFileIO catFile(m_sCurrentDir + "/" + useFile + ".cat");
845
			if ( !files || !found )
846
			{
52 cycrow 847
				if ( catFile.remove() )
1 cycrow 848
				{
849
					CFileIO datFile(m_sCurrentDir + "/" + useFile + ".dat");
52 cycrow 850
					if ( datFile.remove() )
1 cycrow 851
						return true;
852
				}
853
			}
854
			else
855
			{
856
				if ( catFile.Rename(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat") )
857
				{
858
					CFileIO datFile(m_sCurrentDir + "/" + useFile + ".dat");
859
 
860
					if ( datFile.Rename(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat") )
861
						return true;
862
 
863
					// TODO: it failed, restore cat file and do error
864
				}
865
			}
866
		}
867
 
868
		// if we're here, we tryed, and failed
869
		return false;
870
	}
85 cycrow 871
	// no files found, but we have a fake patch ? restore from backup
872
	else if ( m_iFakePatch > 0 ) {
873
		CLog::log(CLog::Log_Directory, 1, "PlugMan FakePatch seems to be missing (" + Utils::String::Number(m_iFakePatch) + "), Restoring from backup");
874
		CFileIO catFile(m_sCurrentDir + "/PluginManager/Backup/PlugMan_Fake.cat");
875
		if ( catFile.exists() ) {
158 cycrow 876
			catFile.copy(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat");
85 cycrow 877
			CFileIO datFile(m_sCurrentDir + "/PluginManager/Backup/PlugMan_Fake.dat");
158 cycrow 878
			if ( datFile.exists() ) datFile.copy(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat");
85 cycrow 879
		}
880
	}
1 cycrow 881
 
882
	// otherwise we didn't need to (hopefully)
883
	return true;
884
}
885
 
886
 
887
bool CPackages::CheckIfPluginManagerFile(CyString filename)
888
{
889
	bool found = false;
890
 
158 cycrow 891
	CFileIO catFile(m_sCurrentDir + "/" + filename.ToString() + ".cat");
892
	if ( catFile.exists() && CFileIO::Exists(m_sCurrentDir + "/" + filename.ToString() + ".dat"))
1 cycrow 893
	{
894
		CCatFile openFile;
125 cycrow 895
		if ( openFile.open(catFile.fullFilename(), this->getAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE )
1 cycrow 896
		{
85 cycrow 897
//			if ( openFile.internaldatFilename().Compare("PlugMan_Fake.dat") ) return true;
1 cycrow 898
			int count = 0;
899
			int noncount = 0;
900
 
901
			// check for some of the files
902
			for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
903
				if ( node->Data()->GetFullDir().IsIn("::") ) {
111 cycrow 904
					if (CFileIO(node->Data()->GetFullDir().GetToken("::", 1, 1)).filename().Compare("PlugMan_Fake.cat") ) {
905
						Utils::String filename = node->Data()->GetFilePointer().GetToken("::", 2, 2).ToString();
906
						filename = filename.findReplace("/", "\\");
1 cycrow 907
						if ( openFile.FindData(filename) )
908
							++count;
909
						else
910
							++noncount;
911
					}
912
				}
913
			}
914
 
915
			if ( (count && !noncount) || (count > noncount) )
916
				found = true;
917
		}
918
	}
919
 
920
	return found;
921
}
922
 
923
bool CPackages::CheckValidPluginManagerFile(CyString filename)
924
{
925
	// both the cat file and dat file exists, lets open it
158 cycrow 926
	CFileIO catFile(m_sCurrentDir + "/" + filename.ToString() + ".cat");
927
	if ( catFile.exists() && CFileIO::Exists(m_sCurrentDir + "/" + filename.ToString() + ".dat"))
1 cycrow 928
	{
929
		CCatFile openFile;
125 cycrow 930
		if ( openFile.open(catFile.fullFilename(), this->getAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE )
1 cycrow 931
		{
932
			if ( openFile.FindData("PlugMan\\TFake.pck") )
933
				return true;
934
			if ( openFile.FindData("pluginmanagerfake.pck") )
935
				return true;
936
		}
937
	}
938
 
85 cycrow 939
	return false;
1 cycrow 940
}
941
 
942
/**
943
 * Converts a package in old format
944
 *
945
 * Some entries in older packages need to be changed for the new installer
946
 * These Include:
947
 *		- Game Version, old format is an id of position in the Data/exe file, new is 2 values, one for game, one for the version
948
 */
949
void CPackages::ConvertOldPackage(CBaseFile *package)
950
{
951
	for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {
952
		if ( gNode->Data()->iGame == -1 ) {
953
			// all versions
954
			if ( gNode->Data()->iVersion == 0 )
955
				gNode->Data()->iGame = 0;
956
			else
957
			{
958
				int version = 0;
959
				gNode->Data()->iGame = m_gameExe.ConvertGameType(gNode->Data()->iVersion, &version);
960
				gNode->Data()->iVersion = version;
961
			}
962
		}
963
	}
964
 
49 cycrow 965
	if ( package->forumLink().empty() && package->webSite().isin("forum.egosoft")) {
966
		package->setForumLink(package->webSite());
967
		package->setWebSite("");
1 cycrow 968
	}
969
 
970
	// convert the version
971
	if ( package->GetType() == TYPE_SPK )
972
	{
973
		CSpkFile *spk = (CSpkFile *)package;
6 cycrow 974
		if ( spk->GetScriptType() == CSpkFile::SCRIPTTYPE_CUSTOM )
1 cycrow 975
		{
976
			CyString type = spk->GetScriptTypeString(44);
977
			if ( type.Compare("Ship Upgrade") )
6 cycrow 978
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_SHIPUPGRADE);
1 cycrow 979
			else if ( type.Compare("Trade Script") )
6 cycrow 980
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_TRADE);
1 cycrow 981
			else if ( type.Compare("Fleet Management") )
6 cycrow 982
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_FLEET);
1 cycrow 983
			else if ( type.Compare("Navigation Script") )
6 cycrow 984
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_NAVIGATION);
1 cycrow 985
			else if ( type.Compare("Piracy") )
6 cycrow 986
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_PIRACY);
1 cycrow 987
			else if ( type.Compare("Other") )
6 cycrow 988
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_OTHER);
1 cycrow 989
			else if ( type.Compare("Ship Command") )
6 cycrow 990
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_SHIPCOMMAND);
1 cycrow 991
			else if ( type.Compare("Station Command") )
6 cycrow 992
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_STATIONCOMMAND);
1 cycrow 993
			else if ( type.Compare("al plugin") )
6 cycrow 994
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_ALPLUGIN);
1 cycrow 995
			else if ( type.Compare("combat script") )
6 cycrow 996
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_COMBAT);
1 cycrow 997
			else if ( type.Compare("bbs and missions") )
6 cycrow 998
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_MISSION);
1 cycrow 999
			else if ( type.Compare("extension mod") )
6 cycrow 1000
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_EXTENSION);
1 cycrow 1001
			else if ( type.Compare("rebalance mod") )
6 cycrow 1002
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_REBALANCE);
1 cycrow 1003
			else if ( type.Compare("general mod") )
6 cycrow 1004
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_GENERALMOD);
1 cycrow 1005
			else if ( type.Compare("total conversion") )
6 cycrow 1006
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_TOTAL);
1 cycrow 1007
			else if ( type.Compare("cheat script") )
6 cycrow 1008
				spk->SetScriptType(CSpkFile::SCRIPTTYPE_CHEAT);
1 cycrow 1009
			else if ( type == "Library Script" )
1010
			{
1011
				spk->SetScriptType("");
1012
				spk->SetLibrary();
1013
			}
1014
 
6 cycrow 1015
			if ( spk->GetScriptType() != CSpkFile::SCRIPTTYPE_CUSTOM )
1 cycrow 1016
				spk->SetScriptType("");
1017
		}
1018
	}
1019
	else if ( package->GetType() == TYPE_XSP )
1020
	{
1021
		CXspFile *xsp = (CXspFile *)package;
14 cycrow 1022
		Utils::String data = xsp->GetShipData();
1 cycrow 1023
 
1024
		for ( int i = 17; i <= 18; i++ )
1025
		{
14 cycrow 1026
			Utils::String model = data.token(";", i);
1027
			Utils::String modelExt = model.right(4);
1 cycrow 1028
			// check file extension
1029
			if ( modelExt.Compare(".bod") || modelExt.Compare(".pbd") )
14 cycrow 1030
				data = data.replaceToken(";", i, model.left(-4));
1 cycrow 1031
		}
1032
 
1033
		xsp->SetShipData(data);
1034
	}
1035
 
1036
	// any extra files that are in director folder
1037
	if ( package->AnyFileType(FILETYPE_EXTRA) )
1038
	{
1039
		for ( C_File *f = package->GetFirstFile(FILETYPE_EXTRA); f; f = package->GetNextFile(f) )
1040
		{
1041
			if ( !f->GetDir().Compare("director") )
1042
				continue;
1043
			if ( f->CheckFileExt("xml") || f->CheckFileExt("pck") )
1044
			{
160 cycrow 1045
				f->setDir("");
1046
				f->setFileType(FILETYPE_MISSION);
1 cycrow 1047
			}
1048
		}
1049
	}
1050
}
1051
 
1052
void CPackages::UpdatePackage(CBaseFile *p)
1053
{
1054
	if ( p->GetType() != TYPE_SPK )
1055
		return;
1056
 
1057
	CSpkFile *package = (CSpkFile *)p;
1058
 
1059
	// update the signed status
1060
	package->UpdateSigned(true);
1061
 
1062
	// check for another mod
1063
	if ( !package->IsAnotherMod() )
1064
		return;
1065
 
1066
	package->SetParent((CSpkFile *)FindSpkPackage(package->GetOtherName(), package->GetOtherAuthor()));
1067
}
1068
 
1069
/**
1070
 * Updates the package list once data has been read
1071
 *
1072
 * Finds any original Files
1073
 * Updates Signed status of all packages
1074
 */
1075
bool CPackages::UpdatePackages(int doStatus, bool individual)
1076
{
1077
	// if theres no original files, then set the current structure as the base
1078
	if ( doStatus == 0 || doStatus == -1 )
1079
	{
93 cycrow 1080
		_pOriginalFiles->update(m_bRedo, &m_lFiles);
1 cycrow 1081
	}
1082
 
1083
	// update each package
1084
	// parent/child, signed status
1085
	if ( doStatus == -1 || doStatus == 1 )
1086
	{
1087
		if ( individual )
1088
		{
1089
			// no package, most likly none installed
1090
			if ( !m_pPackageNode )
1091
				return false;
1092
 
1093
			this->UpdatePackage(m_pPackageNode->Data());
1094
 
1095
			// move to the next package
1096
			m_pPackageNode = m_pPackageNode->next();
1097
			if ( !m_pPackageNode )
1098
				return false;
1099
		}
1100
		else
1101
		{
1102
			for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
1103
				this->UpdatePackage(node->Data());
1104
		}
1105
	}
1106
 
1107
	if ( doStatus == -1 || doStatus == 2 )
1108
		this->LoadVirtualFileSystem();
1109
 
1110
	// adjust save games
1111
	if ( doStatus == -1 || doStatus == 3 )
1112
	{
1113
	}
1114
 
1115
	m_bRedo = false;
1116
	return true;
1117
}
1118
 
1119
int CPackages::CheckOpenPackage(CyString file, int *error)
1120
{
1121
	// first check if it exists
52 cycrow 1122
	if ( !CFileIO(file).ExistsOld() )
1 cycrow 1123
	{
1124
		*error = INSTALLERR_NOEXIST;
1125
		return -1;
1126
	}
1127
 
1128
	// open the spk file
1129
	float fVersion = 0.0f;
1130
	int check = CBaseFile::CheckFile(file, &fVersion);
1131
 
1132
	// wrong version
1133
	if ( fVersion > (float)FILEVERSION )
1134
	{
1135
		*error = INSTALLERR_VERSION;
1136
		return -1;
1137
	}
1138
 
1139
	return check;
1140
}
1141
 
1142
CMultiSpkFile *CPackages::OpenMultiPackage(CyString file, int *error, CProgressInfo *progress)
1143
{
1144
	int check = CheckOpenPackage(file, error);
1145
	if ( *error == -1 )
1146
		return false;
1147
 
1148
	if ( check != SPKFILE_MULTI )
1149
	{
1150
		*error = INSTALLERR_NOMULTI;
1151
		return false;
1152
	}
1153
 
1154
	*error = INSTALLERR_NONE;
1155
 
1156
	CMultiSpkFile *package = new CMultiSpkFile;
1157
 
1158
	bool ret = false;
1159
	if ( package->ReadFile(file, true) )
1160
	{
1161
		if ( package->ReadAllPackages(SPKREAD_NODATA) )
1162
		{
1163
			for ( CListNode<SMultiSpkFile> *node = package->GetFileList()->Front(); node; node = node->next() )
1164
				this->ConvertOldPackage(node->Data()->pFile);
1165
 
1166
			ret = true;
1167
		}
1168
	}
1169
 
1170
	if ( ret )
1171
		return package;
1172
 
1173
	delete package;
1174
	return NULL;
1175
}
1176
 
1177
bool CPackages::OpenMultiPackage ( CyString file, CLinkList<CBaseFile> *packageList, int *error, CProgressInfo *progress )
1178
{
1179
	int check = CheckOpenPackage(file, error);
1180
	if ( *error == -1 )
1181
		return false;
1182
 
1183
	if ( check != SPKFILE_MULTI )
1184
	{
1185
		*error = INSTALLERR_NOMULTI;
1186
		return false;
1187
	}
1188
 
1189
	*error = INSTALLERR_NONE;
1190
 
1191
	CMultiSpkFile *package = new CMultiSpkFile;
1192
 
1193
	bool ret = false;
1194
	if ( package->ReadFile(file, true) )
1195
	{
1196
		if ( package->ReadAllPackages(SPKREAD_ALL, packageList) )
1197
		{
1198
			for ( CListNode<CBaseFile> *node = packageList->Front(); node; node = node->next() )
1199
				this->ConvertOldPackage(node->Data());
1200
 
1201
 
1202
			ret = true;
1203
		}
1204
	}
1205
 
1206
	delete package;
1207
 
1208
	return ret;
1209
}
1210
 
1211
int CPackages::PrepareMultiPackage ( CyString file, CLinkList<CBaseFile> *errorPackageList, int *error, CProgressInfo *progress )
1212
{
1213
	int check = CheckOpenPackage(file, error);
1214
	if ( *error == -1 )
1215
		return 0;
1216
 
1217
	if ( check != SPKFILE_MULTI )
1218
	{
1219
		*error = INSTALLERR_NOMULTI;
1220
		return 0;
1221
	}
1222
 
1223
	*error = INSTALLERR_NONE;
1224
 
1225
	CMultiSpkFile *package = new CMultiSpkFile;
1226
 
1227
	int count = 0;
1228
	if ( package->ReadFile(file, true) )
1229
	{
1230
		CLinkList<CBaseFile> packageList;
1231
		if ( package->ReadAllPackages(SPKREAD_ALL, &packageList) )
1232
		{
1233
			for ( CListNode<CBaseFile> *node = packageList.Front(); node; node = node->next() )
1234
			{
1235
				CBaseFile *p = node->Data();
1236
				this->ConvertOldPackage(p);
1237
				int error = this->PrepareInstallPackage(p);
1238
				if ( error )
1239
				{
1240
					node->Data()->SetLoadError(error);
1241
					errorPackageList->push_back(p);
1242
				}
1243
				else
1244
					++count;
1245
			}
1246
		}
1247
		packageList.clear();
1248
	}
1249
 
1250
	for ( SMultiSpkFile *ms = package->GetFileList()->First(); ms; ms = package->GetFileList()->Next() )
1251
		ms->pFile = NULL;
1252
	delete package;
1253
 
1254
	return count;
1255
}
1256
 
1257
CBaseFile *CPackages::OpenPackage(CyString file, int *error, CProgressInfo *progress, int readtype, int flags)
1258
{
1259
	int check = CheckOpenPackage(file, error);
1260
	if ( *error == -1 )
1261
		return NULL;
1262
 
1263
	CBaseFile *installFile = 0;
1264
 
1265
	if ( progress )
1266
		progress->DoHalf();
1267
 
1268
	switch (check)
1269
	{
1270
		case SPKFILE_OLD:
1271
			*error = INSTALLERR_OLD;
1272
			return NULL;
1273
		case SPKFILE_INVALID:
1274
			// convert xsp
130 cycrow 1275
			if ( CFileIO(file).isFileExtension("xsp") )
1 cycrow 1276
			{
1277
				installFile = new CXspFile();
39 cycrow 1278
				if ( !((CXspFile *)installFile)->ConvertOld(file.ToString()) )
1 cycrow 1279
				{
1280
					delete installFile;
1281
					return NULL;
1282
				}
1283
				break;
1284
			}
1285
			*error = INSTALLERR_INVALID;
1286
			return NULL;
1287
		case SPKFILE_BASE:
1288
			installFile = new CBaseFile();
130 cycrow 1289
			if ( !installFile->readFile(file.ToString(), readtype, progress) )
1 cycrow 1290
			{
1291
				delete installFile;
1292
				return NULL;
1293
			}
1294
			break;
1295
		case SPKFILE_SINGLE:
1296
			installFile = new CSpkFile();
130 cycrow 1297
			if ( !((CSpkFile *)installFile)->readFile(file.ToString(), readtype, progress) )
1 cycrow 1298
			{
1299
				delete installFile;
1300
				return NULL;
1301
			}
1302
			break;
1303
		case SPKFILE_MULTI:
1304
			*error = INSTALLERR_NOMULTI;
1305
			return NULL;
1306
		case SPKFILE_SINGLESHIP:
1307
			installFile = new CXspFile();
160 cycrow 1308
			if ( !((CXspFile *)installFile)->readFile(file.ToString(), readtype, progress))
1 cycrow 1309
			{
1310
				delete installFile;
1311
				return NULL;
1312
			}
1313
			break;
1314
 
1315
		default:
1316
			*error = INSTALLERR_UNKNOWN;
1317
			return NULL;
1318
	}
1319
 
1320
	if ( progress )
1321
		progress->SecondHalf();
1322
 
1323
	// now uncomress all files
1324
	if ( !(flags & READFLAG_NOUNCOMPRESS) )
1325
		installFile->UncompressAllFiles(progress);
1326
 
1327
	this->ConvertOldPackage (installFile);
1328
 
1329
	return installFile;
1330
}
1331
 
1332
void CPackages::PurgeUninstallScripts(CBaseFile *package, CyStringList *errors)
1333
{
1334
	for ( CListNode<C_File> *fNode = m_lUninstallFiles.Front(); fNode; fNode = fNode->next() )
1335
	{
1336
		C_File *uf = fNode->Data();
1337
		// check against any script files
1338
		for ( CListNode<C_File> *checkNode = package->GetFileList()->Front(); checkNode; checkNode = checkNode->next() )
1339
		{
1340
			C_File *checkFile = checkNode->Data();
1341
			if ( !checkFile ) continue;
1342
 
1343
			if ( checkFile->GetFileType() != FILETYPE_UNINSTALL && checkFile->GetFileType() != FILETYPE_SCRIPT )
1344
				continue;
1345
 
158 cycrow 1346
			if ( uf->filename().Compare(checkFile->filename()) )
1 cycrow 1347
			{
1348
				if ( RemoveUninstallFile(uf, errors) )
1349
					fNode->DeleteData();
1350
				break;
1351
			}
1352
		}
1353
	}
1354
 
1355
	m_lUninstallFiles.RemoveEmpty();
1356
 
1357
	this->WriteData();
1358
}
1359
 
1360
int CPackages::InstallPreparedPackages(CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *errored, CLinkList<CBaseFile> *installedList)
1361
{
1362
	if ( m_lInstallList.empty() ) return false;
1363
 
1364
	int installed = 0;
1365
	for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
1366
	{
1367
		CBaseFile *p = node->Data();
1368
		if ( this->InstallPackage(p, errors, progress, !p->IsEnabled()) )
1369
		{
1370
			++installed;
1371
			if ( installedList )
1372
				installedList->push_back(p);
1373
		}
1374
		else if ( errored )
1375
		{
1376
			m_lPackages.remove(p);
1377
			errored->push_back(p);
1378
		}
1379
	}
1380
 
1381
	m_lInstallList.clear();
1382
 
1383
	this->WriteData();
1384
 
1385
	return installed;
1386
}
1387
 
50 cycrow 1388
void CPackages::_addToFakePatch(CBaseFile *pPackage)
1389
{
1390
	CCatFile cat;
158 cycrow 1391
	if ( CCatFile::Opened(cat.open(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat", this->getAddonDir(), CATREAD_DAT)) ) {
50 cycrow 1392
		for ( CListNode<C_File> *f = pPackage->GetFileList()->Front(); f; f = f->next() ) {
51 cycrow 1393
			if ( f->Data()->GetFileType() != FILETYPE_SHIPSCENE && f->Data()->GetFileType() != FILETYPE_COCKPITSCENE && f->Data()->GetFileType() != FILETYPE_SHIPMODEL && f->Data()->GetFileType() != FILETYPE_SHIPOTHER ) {
50 cycrow 1394
				continue;
51 cycrow 1395
			}
127 cycrow 1396
			if ( CCatFile::IsAddonDir(f->Data()->GetNameDirectory(pPackage).ToString()) ) {
50 cycrow 1397
				continue;
51 cycrow 1398
			}
1399
			// check if its already in the fake patch
1400
			if ( f->Data()->GetFullDir().IsIn("::") ) {
1401
				continue;
1402
			}
52 cycrow 1403
			Utils::String toFile;
129 cycrow 1404
			if ( cat.AppendFile(f->Data()->filePointer(), f->Data()->GetNameDirectory(pPackage).ToString(), true, (m_iGameFlags & EXEFLAG_NOXOR) ? false : true, &toFile) ) {
54 cycrow 1405
				CLog::logf(CLog::Log_Install, 2, "Adding file: %s into the fake patch", f->Data()->GetNameDirectory(pPackage).c_str());
129 cycrow 1406
				CFileIO::Remove(f->Data()->filePointer());
158 cycrow 1407
				f->Data()->setFilename(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat::" + toFile);
50 cycrow 1408
			}
1409
		}
1410
	}
1411
}
1412
 
85 cycrow 1413
bool CPackages::_checkForDisable(CBaseFile *package, bool disabled, CBaseFile *oldPackage)
1 cycrow 1414
{
85 cycrow 1415
	bool prevDisabled = disabled;
1416
 
1 cycrow 1417
	// first check if we are installed a mod
50 cycrow 1418
	if ( package->IsMod() && m_pEnabledMod && !m_bForceModInstall ) {
1 cycrow 1419
		disabled = true;
50 cycrow 1420
		CLog::log(CLog::Log_Install, 2, "Package is a mod and another mod is already enabled, setting to disabled");
1421
	}
1 cycrow 1422
	// if vanilla nad package aint signed
50 cycrow 1423
	if ( m_bVanilla && !package->IsSigned() ) {
1 cycrow 1424
		disabled = true;
50 cycrow 1425
		CLog::log(CLog::Log_Install, 2, "Package is a not signed and are we in vanilla mode, setting to disabled");
1426
	}
1 cycrow 1427
 
1428
	// check any depancies
50 cycrow 1429
	if ( !disabled && !this->CheckEnabledDependacy(package) ) {
1 cycrow 1430
		disabled = true;
50 cycrow 1431
		CLog::log(CLog::Log_Install, 2, "Dependacies missing for package, setting to disabled");
1432
	}
1 cycrow 1433
 
1434
	// search for an old version
1435
	if ( oldPackage && oldPackage == m_pEnabledMod && disabled )
1436
		disabled = prevDisabled;
1437
 
85 cycrow 1438
	return disabled;
1439
}
1440
 
125 cycrow 1441
Utils::String CPackages::getCurrentDirectory() const
1442
{ 
1443
	return (_pCurrentDir) ? _pCurrentDir->dir : Utils::String::Null(); 
1444
}
1445
 
1446
 
85 cycrow 1447
bool CPackages::InstallPackage ( CBaseFile *package, CyStringList *errors, CProgressInfo *progress, bool disabled )
1448
{
1449
	CLog::logf(CLog::Log_Install, 1, "Starting to install new package, %s by %s (Version: %s)", package->name().c_str(), package->author().c_str(), package->version().c_str());
1450
 
1451
	CBaseFile *oldPackage = FindPackage(package);
1452
	disabled = _checkForDisable(package, disabled, oldPackage);
1453
 
1 cycrow 1454
	// update packages must have an old package installed already (should have been checked for already)
1455
	if ( package->GetType() == TYPE_SPK )
1456
	{
1457
		if ( ((CSpkFile *)package)->IsPackageUpdate() )
1458
		{
50 cycrow 1459
			CLog::log(CLog::Log_Install, 3, "Package is an Update, checking for existing package installed");
1460
			if ( !oldPackage ) {
1461
				CLog::log(CLog::Log_Install, 2, "Package is an Update but no existing package found, cancelling install");
1 cycrow 1462
				return false;
50 cycrow 1463
			}
1 cycrow 1464
			// change any mods to temp ones
1465
			for ( CListNode<C_File> *f = package->GetFileList()->Front(); f; f = f->next() )
1466
			{
1467
				if ( f->Data()->GetFileType() != FILETYPE_MOD )
1468
					continue;
1469
 
1470
				f->Data()->SetDir("temp");
50 cycrow 1471
				if ( f->Data()->IsFakePatch() ) {
1472
					CLog::logf(CLog::Log_Install, 2, "Moving fake package to temporary location to preper for update, %s", f->Data()->GetFilePointer().c_str());
1 cycrow 1473
					f->Data()->SetName(CyString("Fake_") + f->Data()->GetName());
50 cycrow 1474
				}
1 cycrow 1475
			}
1476
		}
1477
	}
1478
 
1479
	// no need to backup if we're disabling them
1480
	if ( !disabled )
1481
	{
1482
		// find any uninstall files and remove them
50 cycrow 1483
		CLog::log(CLog::Log_Install, 3, "Purging uninstall scripts");
1 cycrow 1484
		this->PurgeUninstallScripts(package, errors);
1485
 
1486
		// backup any original files before installing
93 cycrow 1487
		_pOriginalFiles->backup(package, errors);
1 cycrow 1488
	}
1489
 
1490
	// install all the files
50 cycrow 1491
	CLog::log(CLog::Log_Install, 3, "Checking for any existing files");
1 cycrow 1492
	if ( oldPackage )
1493
	{
50 cycrow 1494
		CLog::logf(CLog::Log_Install, 3, "Excluding existing package (%s) from file check list", oldPackage->version().c_str());
1 cycrow 1495
		CLinkList<CBaseFile> excludeList;
1496
		excludeList.push_back(oldPackage);
1497
		this->UpdateUsedFiles(&excludeList, true);
1498
	}
1499
	else
1500
		this->UpdateUsedFiles(0, true);
1501
 
50 cycrow 1502
	CLog::log(CLog::Log_Install, 3, "Reading all files into memory");
1 cycrow 1503
	package->ReadAllFilesToMemory();
50 cycrow 1504
 
1505
	CLog::log(CLog::Log_Install, 3, "Starting to install files");
1 cycrow 1506
	if ( !package->InstallFiles (m_sCurrentDir, progress, &m_lFiles, errors, !disabled, this) )
1507
	{
50 cycrow 1508
		CLog::log(CLog::Log_Install, 2, "There was an error installing files!!");
1509
 
1 cycrow 1510
		// TODO: clear up installed files
1511
		return false;
1512
	}
1513
 
105 cycrow 1514
	_pOriginalFiles->installed(package);
1515
 
1 cycrow 1516
	// if we're installing an addon, lets use the fake patch method for object files
50 cycrow 1517
	if ( m_iGameFlags & EXEFLAG_ADDON ) this->_addToFakePatch(package);
1 cycrow 1518
 
160 cycrow 1519
	bool shuffle = package->anyFakePatchOrder();
1 cycrow 1520
 
1521
	// merge the update into the old package
1522
	bool dontAdd = false;
1523
	if ( package->GetType() == TYPE_SPK )
1524
	{
1525
		if ( ((CSpkFile *)package)->IsPackageUpdate() )
1526
		{
1527
			// now copy any files from a mod
1528
			for ( CListNode<C_File> *f = package->GetFileList()->Front(); f; f = f->next() )
1529
			{
1530
				if ( !f->Data() )
1531
					continue;
1532
				if ( f->Data()->GetFileType() != FILETYPE_MOD )
1533
					continue;
1534
				// we only need the cat file
1535
				if ( !f->Data()->CheckFileExt("cat") )
1536
					continue;
1537
 
1538
				// if fake patch, find first fake patch in package
1539
				C_File *findMatching = NULL;
1540
				if ( f->Data()->GetBaseName().Left(5).Compare("fake_") )
1541
				{
1542
					for ( CListNode<C_File> *node = oldPackage->GetFileList()->Front(); node; node = node->next() )
1543
					{
1544
						if ( !node->Data() )
1545
							continue;
1546
						if ( node->Data()->GetFileType() != FILETYPE_MOD )
1547
							continue;
1548
						// we only need the cat file
1549
						if ( !node->Data()->CheckFileExt("cat") )
1550
							continue;
1551
						if ( !node->Data()->IsFakePatch() )
1552
							continue;
1553
 
1554
						findMatching = node->Data();
1555
						break;
1556
					}
1557
				}
1558
				// otherwise, just add to the mod of the same name
1559
				else
1560
				{
1561
					for ( CListNode<C_File> *node = oldPackage->GetFileList()->Front(); node; node = node->next() )
1562
					{
1563
						if ( !node->Data() )
1564
							continue;
1565
						if ( node->Data()->GetFileType() != FILETYPE_MOD )
1566
							continue;
1567
						// we only need the cat file
1568
						if ( !node->Data()->CheckFileExt("cat") )
1569
							continue;
1570
 
1571
						if ( node->Data()->GetName().Compare(f->Data()->GetName()) )
1572
						{
1573
							findMatching = node->Data();
1574
							break;
1575
						}
1576
					}
1577
				}
1578
 
1579
				if ( findMatching )
1580
				{
1581
					// copy accross all mods
1582
					CCatFile catTo, catFrom;
125 cycrow 1583
					if ( catFrom.open(f->Data()->filePointer(), this->getAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE )
1 cycrow 1584
					{
125 cycrow 1585
						if ( catTo.open(findMatching->filePointer(), this->getAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE )
1 cycrow 1586
						{
124 cycrow 1587
							for (unsigned int i = 0; i < catFrom.GetNumFiles(); i++ )
1 cycrow 1588
							{
1589
								SInCatFile *c = catFrom.GetFile(i);								 
129 cycrow 1590
								catTo.AppendFile(f->Data()->filePointer() + "::" + c->sFile, c->sFile);
1 cycrow 1591
							}
1592
						}
1593
					}
1594
 
1595
					// now remove the files
1596
					C_File *m = package->FindMatchingMod(f->Data());
1597
					RemoveFile(f->Data(), errors);
1598
					m_lFiles.remove(f->Data());
1599
					f->ChangeData(NULL);
1600
					if ( m )
1601
					{
1602
						int pos = package->GetFileList()->FindPos(m);
1603
						RemoveFile(m, errors);
1604
						m_lFiles.remove(m);
1605
						if ( pos != -1 )
1606
							package->GetFileList()->GetNode(pos)->ChangeData(NULL);
1607
					}
1608
				}
1609
				// no matching file, then we shall just renaming back
1610
				else
1611
				{
1612
					if ( f->Data()->GetBaseName().Left(5).Compare("fake_") )
1613
					{
1614
						shuffle = true;
1615
						C_File *match = package->FindMatchingMod(f->Data());
158 cycrow 1616
						Utils::String next = Utils::String::PadNumber(this->FindNextFakePatch(), 2);
1 cycrow 1617
 
1618
						CyString oldFilePointer = f->Data()->GetFilePointer();
158 cycrow 1619
						f->Data()->setDir("");
1620
						f->Data()->changeBaseName(next);
1621
						if ( CFileIO(oldFilePointer).Rename(m_sCurrentDir + "/" + f->Data()->getNameDirectory(package)) )
1622
							f->Data()->setFilename(m_sCurrentDir + "/" + f->Data()->getNameDirectory(package));
1 cycrow 1623
 
1624
						if ( match )
1625
						{
158 cycrow 1626
							Utils::String oldFilePointer = match->filePointer();
1627
							match->setDir("");
1628
							match->changeBaseName(next);
1629
							if ( CFileIO(oldFilePointer).Rename(m_sCurrentDir + "/" + match->getNameDirectory(package)) )
1630
								match->setFilename(m_sCurrentDir + "/" + match->getNameDirectory(package));
1 cycrow 1631
						}
1632
					}
1633
					else
1634
					{
1635
						C_File *match = package->FindMatchingMod(f->Data());
1636
 
158 cycrow 1637
						f->Data()->setDir("");
1638
						if ( CFileIO(f->Data()->GetFilePointer()).Rename(m_sCurrentDir + "/" + f->Data()->getNameDirectory(package)) )
1639
							f->Data()->setFilename(m_sCurrentDir + "/" + f->Data()->getNameDirectory(package));
1 cycrow 1640
						if ( match )
1641
						{
158 cycrow 1642
							match->setDir("");
1643
							if ( CFileIO(match->filePointer()).Rename(m_sCurrentDir + "/" + match->getNameDirectory(package)) )
1644
								match->setFilename(m_sCurrentDir + "/" + match->getNameDirectory(package));
1 cycrow 1645
						}
1646
					}
1647
				}
1648
			}
1649
 
1650
			package->GetFileList()->RemoveEmpty();
1651
			((CSpkFile *)oldPackage)->MergePackage(package);
1652
			delete package;
1653
			package = oldPackage;
1654
			oldPackage = false;
1655
			dontAdd = true;
1656
 
160 cycrow 1657
			CDirIO(m_sCurrentDir).removeDir("temp");
1658
			CDirIO(m_sCurrentDir).removeDir("Mods/temp");
1 cycrow 1659
		}
1660
	}
1661
 
1662
	// if theres an icon, write it
1663
	if ( package->GetIcon() )
1664
	{
50 cycrow 1665
		CLog::log(CLog::Log_Install, 3, "Checking to install icon display file");
1 cycrow 1666
		C_File *icon = package->GetIcon();
50 cycrow 1667
		if ( !icon->GetData() || !icon->GetDataSize() ) {
1 cycrow 1668
			package->SetIcon(NULL, "");
50 cycrow 1669
			CLog::log(CLog::Log_Install, 2, "Unable to extract icon, clearing");
1670
		}
1 cycrow 1671
		else
1672
		{
1673
			CDirIO Dir(m_sCurrentDir);
1674
			bool ready = true;
121 cycrow 1675
			if ( !Dir.exists("PluginManager") )
1 cycrow 1676
			{
160 cycrow 1677
				if ( !Dir.create("PluginManager") )
1 cycrow 1678
					ready = false;
1679
			}
121 cycrow 1680
			if ( ready && !Dir.exists("PluginManager/Icons") )
1 cycrow 1681
			{
160 cycrow 1682
				if ( !Dir.create("PluginManager/Icons") )
1 cycrow 1683
					ready = false;
1684
			}
1685
 
1686
			if ( ready )
1687
			{
1688
				if ( !icon->UncompressData() )
1689
					package->SetIcon(NULL, "");
1690
				else
1691
				{
158 cycrow 1692
					CFileIO iconFile(m_sCurrentDir + "/PluginManager/Icons/" + package->author() + "_" + package->name() + "." + package->iconExt());
1 cycrow 1693
					if ( iconFile.WriteData((const char *)icon->GetData(), icon->GetDataSize()) )
1694
					{
158 cycrow 1695
						icon->SetFilename(CyString(package->author()) + "_" + package->name() + "." + package->iconExt());
1 cycrow 1696
						icon->SetFullDir(m_sCurrentDir + "/PluginManager/Icons");
1697
					}
1698
					else
1699
						package->SetIcon(NULL, "");
1700
				}
1701
			}
1702
 
1703
			if ( package->GetIcon() )
1704
				package->GetIcon()->DeleteData();
1705
		}
1706
	}
1707
 
1708
	// remove all data
50 cycrow 1709
	CLog::log(CLog::Log_Install, 3, "Clearing all unneeded file data");
1 cycrow 1710
	package->ClearFileData();
1711
 
1712
	// add to list
1713
	if ( !dontAdd )
1714
	{
50 cycrow 1715
		CLog::log(CLog::Log_Install, 1, "Adding package into main list");
1 cycrow 1716
		if ( oldPackage )
1717
		{
98 cycrow 1718
			// find all other packages that has the old package as parent and switch to new
1719
			for(CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next()) {
1720
				if ( node->Data()->GetParent() == oldPackage ) {
1721
					node->Data()->SetParent(package);
1722
				}
1723
			}
1724
 
1725
			// remove olld package from list, and replace it with the new one
1 cycrow 1726
			m_lPackages.insert(oldPackage, package);
1727
			m_lPackages.remove(oldPackage, false);
1728
		}
1729
		else
1730
			m_lPackages.push_back (package);
1731
	}
1732
 
50 cycrow 1733
	CLog::log(CLog::Log_Install, 2, "Updating file used count");
1 cycrow 1734
	UpdateUsedFiles();
1735
 
50 cycrow 1736
	if ( disabled ) package->SetEnabled(false);
1 cycrow 1737
 
1738
	// remove any files no longer used by old package
1739
	if ( oldPackage )
1740
	{
50 cycrow 1741
		CLog::log(CLog::Log_Install, 3, "Removing any unused files from previous package");
1742
 
1 cycrow 1743
		CListNode<C_File> *fnode = oldPackage->GetFileList()->Front();
1744
		while ( fnode )
1745
		{
1746
			C_File *f = fnode->Data();
1747
 
1748
			// no longer used
160 cycrow 1749
			if ( !f->getUsed() )
1 cycrow 1750
			{
1751
				// remove from file list
1752
				m_lFiles.remove(f, false);
1753
 
85 cycrow 1754
				// if its a readme file, then check if its in the new package
1755
				bool dontRemove = false;
1756
				if ( f->GetFileType() == FILETYPE_README ) {
158 cycrow 1757
					if ( package->FindFile(f->filename(), FILETYPE_README) )
85 cycrow 1758
						dontRemove = true;
1759
				}
1760
 
1 cycrow 1761
				// remove from hard drive
85 cycrow 1762
				if ( !dontRemove && RemoveFile(f, errors) )
1 cycrow 1763
				{
50 cycrow 1764
					CLog::logf(CLog::Log_Install, 1, "Removed unused file: %s", f->GetFilePointer().c_str());
1 cycrow 1765
					// if a fake patch, we need to shufle
1766
					if ( f->IsFakePatch() )
1767
						shuffle = true;
130 cycrow 1768
					else if ( f->isAutoTextFile() )
1 cycrow 1769
						shuffle = true;
1770
				}
1771
			}
1772
 
1773
			fnode = fnode->next();
1774
		}
1775
 
1776
	}
1777
 
1778
	if ( shuffle )
1779
	{
50 cycrow 1780
		CLog::log(CLog::Log_Install, 2, "Shuffling Fake patches");
1 cycrow 1781
		ShuffleFakePatches(errors);
50 cycrow 1782
		CLog::log(CLog::Log_Install, 2, "Shuffling Text Files");
1 cycrow 1783
		ShuffleTextFiles(errors);
1784
	}
1785
 
1786
	// now we need to link any child/parent packages
1787
	if ( package->GetType() == TYPE_SPK )
1788
	{
1789
		CSpkFile *spk = (CSpkFile *)package;
50 cycrow 1790
		if ( spk->IsAnotherMod() ) {
1 cycrow 1791
			spk->SetParent((CSpkFile *)FindSpkPackage(spk->GetOtherName(), spk->GetOtherAuthor()));
50 cycrow 1792
			CLog::logf(CLog::Log_Install, 2, "Linking to parent package: %s by %s (Version: %s)", spk->name().c_str(), spk->author().c_str(), spk->version().c_str());
1793
		}
1 cycrow 1794
	}
1795
 
1796
	// store enabled mod
50 cycrow 1797
	if ( package->IsMod() && !disabled ) {
1 cycrow 1798
		m_pEnabledMod = package;
50 cycrow 1799
		CLog::log(CLog::Log_Install, 1, "Setting package as primary mod");
1800
	}
1 cycrow 1801
 
88 cycrow 1802
	package->updateTextDB();
1803
 
1 cycrow 1804
	m_bRemoveDir = true;
1805
 
50 cycrow 1806
	CLog::log(CLog::Log_Install, 1, "Saving data to file");
1 cycrow 1807
	this->WriteData();
1808
 
50 cycrow 1809
	CLog::log(CLog::Log_Install, 1, "Installation Finished");
1 cycrow 1810
	return true;
1811
}
1812
 
1813
bool CPackages::UninstallPreparedPackages(CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *uninstalledPackages, CLinkList<CBaseFile> *disabledPackages)
1814
{
1815
	if ( m_lInstallList.empty() ) return false;
1816
 
1817
	// update the used status, excluding all packages we are about to remove
1818
	UpdateUsedFiles(&m_lInstallList);
1819
 
1820
	CyStringList removeDirs;
1821
	CLinkList<C_File> uninstallFiles;
1822
	CLinkList<C_File> fileList;
1823
	bool readme = false, original = false, shuffle = false;
1824
 
1825
	// find all files that need to be removed
1826
	int maxFiles = 0;
1827
	for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
1828
	{
1829
		CBaseFile *p = node->Data();
1830
		maxFiles += this->GetAllPackageFiles(p, &fileList, true);
1831
 
1832
		// disable any dependants
1833
		if ( p->GetType() == TYPE_SPK && ((CSpkFile *)p)->IsLibrary() )
1834
		{
1835
			CLinkList<CBaseFile> depList;
1836
			if ( this->GetDependacyList(p, &depList) )
1837
			{
1838
				for ( CBaseFile *depP = depList.First(); depP; depP = depList.Next() )
1839
				{
1840
					if ( depP->IsEnabled() )
1841
						this->PrepareDisablePackage(depP);
1842
				}
1843
 
1844
				if ( m_lDisableList.size() )
1845
					this->DisablePreparedPackages(errors, progress, disabledPackages);
1846
			}
1847
		}
1848
	}
1849
 
1850
	// interate through all the files in the package
1851
	int fileCount = 0;
1852
	for ( CListNode<C_File> *node = fileList.Front(); node; node = node->next() )
1853
	{
1854
		C_File *f = node->Data();
1855
 
1856
		// display progress if needed
1857
		if ( progress )
1858
		{
1859
			progress->UpdateProgress(fileCount++, maxFiles);
1860
			progress->UpdateFile(f);
1861
		}
1862
 
1863
		// skip uninstall files
1864
		if ( f->GetFileType() == FILETYPE_UNINSTALL )
1865
		{
1866
			uninstallFiles.push_back(f);
1867
			continue;
1868
		}
1869
 
1870
		// only delete files that are not used
1871
		// if its a shared file, we skip it
160 cycrow 1872
		if ( f->getUsed() || f->IsShared() )
1 cycrow 1873
			continue;
1874
 
1875
		if ( f->GetFileType() == FILETYPE_README )
1876
			readme = true;
1877
		else if ( f->GetFileType() == FILETYPE_UNINSTALL || f->GetFileType() == FILETYPE_MAP || f->GetFileType() == FILETYPE_SOUND || f->GetFileType() == FILETYPE_EXTRA || f->GetFileType() == FILETYPE_SHIPSCENE || f->GetFileType() == FILETYPE_COCKPITSCENE || f->GetFileType() == FILETYPE_SHIPOTHER || f->GetFileType() == FILETYPE_SHIPMODEL || f->GetFileType() == FILETYPE_ADVERT )
1878
		{
1879
			CyString dir = f->GetDirectory(NULL);
1880
			removeDirs.PushBack(dir, true);
1881
			dir = dir.FindReplace("\\", "/");
1882
			if ( dir.IsIn("/") )
1883
			{
1884
				for ( int i = dir.NumToken("/"); i; i-- )
1885
				{
1886
					CyString remDir = dir.GetToken("/", 1, i);
1887
					removeDirs.PushBack(remDir, true);
1888
				}
1889
			}
1890
		}
1891
 
1892
		if ( f->GetFileType() == FILETYPE_EXTRA && f->GetDir().Left(6).lower() == "extras" )
1893
			removeDirs.PushBack("Extras", true);
1894
 
1895
		if ( RemoveFile(f, errors) )
1896
		{
93 cycrow 1897
			original = _pOriginalFiles->restoreFile(f, errors);
1 cycrow 1898
		}
1899
		else // problem removeing (try when the program closes)
160 cycrow 1900
			m_lNonRemovedFiles.pushBack(f->filePointer());
1 cycrow 1901
 
1902
		// check for fake patchs
1903
		if ( f->IsFakePatch() )
1904
			shuffle = true;
130 cycrow 1905
		else if ( f->isAutoTextFile() )
1 cycrow 1906
			shuffle = true;
1907
 
1908
		// remove the file from the main list as swell
1909
		m_lFiles.remove(f, false);
1910
		delete f;
1911
	}
1912
 
1913
	// remove all the packages from memory
1914
	for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
1915
	{
1916
		CBaseFile *p = node->Data();
1917
		p->GetFileList()->clear();
1918
		m_lPackages.remove(p);
1919
 
1920
		if ( p == m_pEnabledMod )
1921
			m_pEnabledMod = NULL;
1922
 
1923
		if ( uninstalledPackages )
1924
			uninstalledPackages->push_back(p);
1925
		else
1926
			delete p;
1927
	}
1928
 
1929
	m_lInstallList.clear();
1930
 
1931
	// check unistall files
1932
	if ( !uninstallFiles.empty() )
1933
	{
1934
		removeDirs.PushBack(CyString("PluginManager/Uninstall"));
1935
 
1936
		// make sure the scripts directory is created, even thou it should always be there anyways
1937
		CDirIO scriptDir(m_sCurrentDir);
121 cycrow 1938
		if ( !scriptDir.exists("scripts") )
1 cycrow 1939
		{
160 cycrow 1940
			if ( scriptDir.create("Scripts") )
1 cycrow 1941
				this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY, "Scripts", errors);
1942
			else
1943
				this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, "Scripts", errors);
1944
		}
1945
 
1946
		for ( C_File *uf = uninstallFiles.First(); uf; uf = uninstallFiles.Next() )
1947
		{
1948
			C_File *newFile = new C_File();
160 cycrow 1949
			newFile->setFileType(FILETYPE_SCRIPT);
158 cycrow 1950
			newFile->setFilename(uf->filename());
1 cycrow 1951
			newFile->SetCreationTime(uf->GetCreationTime());
1952
 
1953
			// other installed packages use this file as well, copy it
158 cycrow 1954
			Utils::String newFilename = m_sCurrentDir + "/" + newFile->getNameDirectory(NULL);
1955
			CFileIO file(uf->filePointer());
1 cycrow 1956
 
160 cycrow 1957
			if ( uf->getUsed() )
1 cycrow 1958
			{
158 cycrow 1959
				if ( file.copy(newFilename) )
1960
					this->AddLogEntry(SPKINSTALL_UNINSTALL_COPY, newFile->getNameDirectory(NULL), errors);
1 cycrow 1961
				else
1962
				{
158 cycrow 1963
					this->AddLogEntry(SPKINSTALL_UNINSTALL_COPY_FAIL, newFile->getNameDirectory(NULL), errors);
1 cycrow 1964
					delete newFile;
1965
					newFile = NULL;
1966
				}
1967
			}
1968
			// otherwise just move it
1969
			else
1970
			{
1971
				if ( file.Rename(newFilename) )
158 cycrow 1972
					this->AddLogEntry(SPKINSTALL_UNINSTALL_MOVE, newFile->getNameDirectory(NULL), errors);
1 cycrow 1973
				else
1974
				{
158 cycrow 1975
					this->AddLogEntry(SPKINSTALL_UNINSTALL_MOVE_FAIL, newFile->getNameDirectory(NULL), errors);
1 cycrow 1976
					delete newFile;
1977
					newFile = NULL;
1978
				}
1979
 
1980
				m_lFiles.remove(uf, false);
1981
				delete uf;
1982
			}
1983
 
1984
			// add to the list
1985
			if ( newFile )
1986
			{
1987
				// first check if theres a matching one
1988
				bool found = false;
1989
				for ( CListNode<C_File> *node = m_lUninstallFiles.Front(); node; node = node->next() )
1990
				{
1991
					C_File *checkFile = node->Data();
158 cycrow 1992
					if ( checkFile->filename().Compare(newFile->filename()) )
1 cycrow 1993
					{
1994
						found = true;
1995
						break;
1996
					}
1997
				}
1998
 
1999
				// not found, so add it
2000
				if ( !found )
2001
					m_lUninstallFiles.push_back(newFile);
2002
				else
2003
					delete newFile;
2004
			}
2005
		}
2006
	}
106 cycrow 2007
 
1 cycrow 2008
	uninstallFiles.clear();
2009
 
2010
	// remove all directies that we're not using
2011
	if ( readme )
2012
	{
2013
		removeDirs.PushBack(CyString("PluginManager/Readme"));
2014
		removeDirs.PushBack(CyString("Readme"));
2015
	}
105 cycrow 2016
	if ( original ) {
2017
		removeDirs.PushBack(CyString("PluginManager/Original/Replacements"));
1 cycrow 2018
		removeDirs.PushBack(CyString("PluginManager/Original"));
105 cycrow 2019
	}
1 cycrow 2020
	removeDirs.PushBack(CyString("PluginManager/Disabled"));
2021
	RemoveUnusedDirectories(removeDirs, errors);
2022
 
2023
	// finally lets shuffle any fake patchs to fill in gaps
2024
	if ( shuffle )
2025
	{
2026
		ShuffleFakePatches(errors);
2027
		ShuffleTextFiles(errors);
2028
	}
2029
 
2030
	this->WriteData();
2031
 
2032
	return true;
2033
}
2034
 
2035
/**
2036
 * Prepares a package to be uninstalled
2037
 *
2038
 * Adds the package, and all its children onto the uninstall list to be used by UninstallPreparePackages
2039
 */
2040
void CPackages::PrepareUninstallPackage(CBaseFile *package)
2041
{
2042
	// add package to list
2043
	if ( !m_lInstallList.FindData(package) )
2044
		m_lInstallList.push_back(package);
2045
 
2046
	// add all children
2047
	CLinkList<CBaseFile> children;
2048
	if ( this->GetChildPackages(package, &children, true) )
2049
	{
2050
		for ( CBaseFile *p = children.First(); p; p = children.Next() )
2051
		{
2052
			if ( !m_lInstallList.FindData(p) )
2053
				m_lInstallList.push_back(p);
2054
		}
2055
	}
2056
}
2057
 
2058
bool CPackages::PrepareEnablePackage(CBaseFile *package)
2059
{
2060
	ClearError();
2061
 
2062
	if ( package->GetParent() && !package->GetParent()->IsEnabled() )
2063
	{
2064
		m_iError = PKERR_NOPARENT;
2065
		return false;
2066
	}
2067
 
2068
	if ( m_bVanilla && !package->IsSigned() )
2069
	{
2070
		m_iError = PKERR_MODIFIED;
2071
		return false;
2072
	}
2073
 
2074
	// check if it needs depancies
2075
	if ( package->AnyDependacies() )
2076
	{
2077
		if ( this->GetMissingDependacies(package, NULL, true) )
2078
		{
2079
			m_iError = PKERR_MISSINGDEP;
2080
			return false;
2081
		}
2082
	}
2083
 
2084
	if ( !m_lEnableList.FindData(package) )
2085
	{
2086
		if ( !package->IsEnabled() )
2087
			m_lEnableList.push_back(package);
2088
 
2089
		// do all the children as well
2090
		if ( m_bAutoEnableChild )
2091
		{
2092
			CLinkList<CBaseFile> childList;
2093
			this->GetChildPackages(package, &childList, true);
2094
 
2095
			// add all disabled packages to list
2096
			for ( CBaseFile *p = childList.First(); p; p = childList.Next() )
2097
			{
2098
				if ( !p->IsEnabled() )
2099
					m_lEnableList.push_back(p);
2100
			}
2101
		}
2102
	}
2103
 
2104
	m_bRemoveDir = true;
2105
 
2106
	return true;
2107
}
2108
 
2109
bool CPackages::PrepareDisableForVanilla()
2110
{
2111
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
2112
	{
2113
		CBaseFile *p = node->Data();
2114
		if ( !p->IsSigned() && p->IsEnabled() )
2115
		{
2116
			this->PrepareDisablePackage(p);
2117
			m_bDisableVanilla = true;
2118
		}
2119
	}
2120
 
2121
	return true;
2122
}
2123
 
2124
bool CPackages::PrepareEnableLibrarys()
2125
{
2126
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
2127
	{
2128
		CBaseFile *p = node->Data();
2129
		if ( p->GetType() != TYPE_SPK )
2130
			continue;
2131
 
2132
		if ( !p->IsEnabled() && ((CSpkFile *)p)->IsLibrary() )
2133
			this->PrepareEnablePackage(p);
2134
	}
2135
 
2136
	return true;
2137
}
2138
 
2139
bool CPackages::PrepareEnableFromVanilla()
2140
{
2141
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
2142
	{
2143
		CBaseFile *p = node->Data();
2144
		if ( !p->IsEnabled() && p->IsModifiedEnabled() ) {
2145
			this->PrepareEnablePackage(p);
2146
		}
2147
	}
2148
 
2149
	return true;
2150
}
2151
 
2152
int CPackages::GetDependacyList(CBaseFile *package, CLinkList<CBaseFile> *list)
2153
{
2154
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
2155
	{
2156
		CBaseFile *p = node->Data();
50 cycrow 2157
		if ( p->IsPackageNeeded(package->name(), package->author()) )
1 cycrow 2158
			list->push_back(p);
2159
	}
2160
 
2161
	return list->size();
2162
}
2163
 
2164
bool CPackages::PrepareDisablePackage(CBaseFile *package)
2165
{
2166
	if ( !m_lDisableList.FindData(package) )
2167
	{
2168
		if ( package->IsEnabled() )
2169
			m_lDisableList.push_back(package);
2170
 
2171
		CLinkList<CBaseFile> childList;
2172
		this->GetChildPackages(package, &childList, true);
2173
 
2174
		// add all disabled packages to list
2175
		for ( CBaseFile *p = childList.First(); p; p = childList.Next() )
2176
		{
2177
			if ( p->IsEnabled() && !m_lDisableList.FindData(p) )
2178
				m_lDisableList.push_back(p);
2179
		}
2180
 
2181
		// if its a library, check for any dependacies
2182
		if ( package->GetType() == TYPE_SPK && ((CSpkFile *)package)->IsLibrary() )
2183
		{
2184
			CLinkList<CBaseFile> depList;
2185
			if ( this->GetDependacyList(package, &depList) )
2186
			{
2187
				for ( CBaseFile *p = depList.First(); p; p = depList.Next() )
2188
				{
2189
					if ( !m_lDisableList.FindData(p) )
2190
						this->PrepareDisablePackage(p);
2191
				}
2192
			}
2193
		}
2194
	}
2195
	return true;
2196
}
2197
 
2198
/**
2199
 * Prepares a package to be installed
2200
 */
2201
int CPackages::PrepareInstallPackage(CBaseFile *package, bool disabled, bool force, int check)
2202
{
2203
	// add package to list
2204
	if ( !m_lInstallList.FindData(package) )
2205
	{
2206
		int error = this->CheckInstallPackage(package, check);
2207
		if ( error == INSTALLCHECK_OK || force )
2208
		{
2209
			if ( disabled )
2210
				package->SetEnabled(false);
2211
 
2212
			bool added = false;
2213
			if ( package->GetType() == TYPE_SPK )
2214
			{
2215
				// find other mods in the currently added list
2216
				CSpkFile *spk = (CSpkFile *)package;
2217
				if ( spk->IsAnotherMod() )
2218
				{
2219
					for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
2220
					{
2221
						CBaseFile *p = node->Data();
133 cycrow 2222
						if ( spk->otherName().Compare(p->name()) && spk->otherAuthor().Compare(p->author()) )
1 cycrow 2223
						{
2224
							m_lInstallList.insert(m_lInstallList.FindPos(p) + 2, package);
2225
							added = true;
2226
							break;
2227
						}
2228
					}
2229
				}
2230
			}
2231
 
2232
			if ( !added )
2233
			{
2234
				// check if we are a parent
2235
				for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
2236
				{
2237
					if ( node->Data()->GetType() != TYPE_SPK )
2238
						continue;
2239
 
2240
					CSpkFile *spk = (CSpkFile *)node->Data();
133 cycrow 2241
					if ( !spk->isAnotherMod() )
1 cycrow 2242
						continue;
2243
 
133 cycrow 2244
					if ( spk->otherName().Compare(package->name()) && spk->otherAuthor().Compare(package->author()) )
1 cycrow 2245
					{
2246
						added = true;
2247
						m_lInstallList.insert(node->Data(), package);
2248
						break;
2249
					}
2250
				}
2251
 
2252
				if ( !added )
2253
					m_lInstallList.push_back(package);
2254
			}
2255
 
2256
			return INSTALLCHECK_OK;
2257
		}
2258
 
2259
		package->SetLoadError(error);
2260
		return error;
2261
	}
2262
 
2263
	return INSTALLCHECK_ALREADYQUEUED;
2264
}
2265
 
2266
void CPackages::RemovePreparedInstall(CBaseFile *package)
2267
{
2268
	if ( !package )
2269
	{
2270
		m_lInstallList.MemoryClear();
2271
	}
2272
	else
2273
	{
2274
		if ( m_lInstallList.FindData(package) )
2275
		{
2276
			m_lInstallList.remove(package, true);
2277
		}
2278
	}
2279
}
2280
 
2281
char CPackages::ConvertWareTypeBack(int w)
2282
{
2283
	switch ( w )
2284
	{
2285
		case WARES_BIO:
2286
			return 'b';
2287
		case WARES_ENERGY:
2288
			return 'e';
2289
		case WARES_FOOD:
2290
			return 'f';
2291
		case WARES_MINERAL:
2292
			return 'm';
2293
		case WARES_TECH:
2294
			return 't';
2295
		case WARES_NATURAL:
2296
			return 'n';
2297
	}
2298
	return 't';
2299
}
2300
int CPackages::ConvertWareType(char w)
2301
{
2302
	switch ( LOWER(w) )
2303
	{
2304
		case 'b':
2305
			return WARES_BIO;
2306
		case 'e':
2307
			return WARES_ENERGY;
2308
		case 'f':
2309
			return WARES_FOOD;
2310
		case 'm':
2311
			return WARES_MINERAL;
2312
		case 't':
2313
			return WARES_TECH;
2314
		case 'n':
2315
			return WARES_NATURAL;
2316
	}
2317
	return WARES_TECH;
2318
}
2319
 
2320
void CPackages::SetupShips()
2321
{
2322
	for ( CListNode<SGameShip> *wNode = m_lGameShips.Front(); wNode; wNode = wNode->next() )
2323
	{
2324
		if ( wNode->Data()->iType != WARETYPE_NONE )
2325
			wNode->Data()->iType = WARETYPE_DELETED;
2326
	}
2327
 
2328
	// find any new ships to add to the list
2329
	for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )
2330
	{
2331
		if ( pNode->Data()->GetType() != TYPE_XSP )
2332
			continue;
2333
		CXspFile *p = (CXspFile *)pNode->Data();
2334
 
2335
		bool found = false;
2336
		for ( CListNode<SGameShip> *wNode = m_lGameShips.Front(); wNode; wNode = wNode->next() )
2337
		{
14 cycrow 2338
			if ( wNode->Data()->sShipID.Compare(p->GetShipID().c_str()) )
1 cycrow 2339
			{
2340
				if ( !p->IsEnabled() )
2341
					wNode->Data()->iType = WARETYPE_DISABLED;
2342
				else
2343
					wNode->Data()->iType = WARETYPE_ADDED;
2344
				found = true;
2345
				wNode->Data()->pPackage = p;
2346
				wNode->Data()->sShipClass = p->GetShipClass();
2347
				break;
2348
			}
2349
		}
2350
 
2351
		if ( found || !p->IsEnabled() )
2352
			continue;
2353
 
2354
		// first find any free
2355
		SGameShip *gw = NULL;
2356
		for ( CListNode<SGameShip> *wNode = m_lGameShips.Front(); wNode; wNode = wNode->next() )
2357
		{
2358
			if ( (!gw) && (wNode->Data()->iType == WARETYPE_NONE) )
2359
				gw = wNode->Data();
2360
			// find an old entry for the ware and add it to the same place
14 cycrow 2361
			if ( wNode->Data()->sShipID.Compare(p->GetShipID().c_str()) )
1 cycrow 2362
			{
2363
				gw = wNode->Data();
2364
				break;
2365
			}
2366
		}
2367
 
2368
		// none found, create one
2369
		if ( !gw )
2370
		{
2371
			gw = new SGameShip;
2372
			gw->sShipID = p->GetShipID();
2373
			gw->sShipClass = p->GetShipClass();
2374
			gw->pPackage = p;
2375
			m_lGameShips.push_back(gw);
2376
		}
2377
		gw->iType = WARETYPE_ADDED;
2378
	}
2379
}
2380
 
2381
void CPackages::SetupWares()
2382
{
2383
	for ( int i = 0; i < WAREBUFFERS; i++ )
2384
	{
2385
		for ( CListNode<SGameWare> *wNode = m_lGameWares[i].Front(); wNode; wNode = wNode->next() )
2386
		{
2387
			if ( wNode->Data()->iType != WARETYPE_NONE )
2388
				wNode->Data()->iType = WARETYPE_DELETED;
2389
		}
2390
	}
2391
 
2392
	// find any new wares to add to the list
2393
	for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )
2394
	{
2395
		if ( pNode->Data()->GetType() != TYPE_SPK )
2396
			continue;
2397
		CSpkFile *p = (CSpkFile *)pNode->Data();
2398
 
2399
		for ( CListNode<SWares> *node = p->GetWaresList()->Front(); node; node = node->next() )
2400
		{
2401
			SWares *w = node->Data();
2402
			int wareType = CPackages::ConvertWareType(w->cType);
2403
 
2404
			// check if its on the list
2405
			bool found = false;
2406
			for ( CListNode<SGameWare> *wNode = m_lGameWares[wareType].Front(); wNode; wNode = wNode->next() )
2407
			{
2408
				if ( wNode->Data()->sWareName == w->sID )
2409
				{
2410
					if ( !p->IsEnabled() )
2411
						wNode->Data()->iType = WARETYPE_DISABLED;
2412
					else
2413
						wNode->Data()->iType = WARETYPE_ADDED;
2414
					wNode->Data()->pWare = w;
2415
					found = true;
2416
					break;
2417
				}
2418
			}
2419
 
2420
			if ( found || !p->IsEnabled() )
2421
				continue;
2422
 
2423
			// first find any free
2424
			SGameWare *gw = NULL;
2425
			for ( CListNode<SGameWare> *wNode = m_lGameWares[wareType].Front(); wNode; wNode = wNode->next() )
2426
			{
2427
				if ( (!gw) && (wNode->Data()->iType == WARETYPE_NONE) )
2428
					gw = wNode->Data();
2429
				// find an old entry for the ware and add it to the same place
2430
				if ( wNode->Data()->sWareName == w->sID )
2431
				{
2432
					gw = wNode->Data();
2433
					break;
2434
				}
2435
			}
2436
 
2437
			// none found, create one
2438
			if ( !gw )
2439
			{
2440
				gw = new SGameWare;
2441
				gw->sWareName = w->sID;
2442
				gw->iPos = m_lGameWares[wareType].size();
2443
				gw->pWare = w;
2444
				gw->cType = w->cType;
2445
				m_lGameWares[wareType].push_back(gw);
2446
			}
2447
			gw->iType = WARETYPE_ADDED;
2448
		}
2449
	}
2450
}
2451
 
2452
/**
2453
 * Closing the current directory
2454
 *
2455
 * When existing, program needs to close the directory
2456
 */
2457
bool CPackages::CloseDir ( CyStringList *errors, CProgressInfo *progress, bool removedir )
2458
{
158 cycrow 2459
	if ( m_sCurrentDir.empty() )
1 cycrow 2460
		return true;
2461
	if ( !m_bLoaded )
2462
		return true;
2463
 
160 cycrow 2464
	Utils::CStringList lErrors;
2465
 
158 cycrow 2466
	CLog::log(CLog::Log_Directory, 1, "closing directory: " + m_sCurrentDir);
1 cycrow 2467
 
84 cycrow 2468
	if ( m_bRenameText ) {
2469
		CLog::log(CLog::Log_Directory, 2, "Creating other language files for game");
160 cycrow 2470
		CreateLanguageTextFiles(&lErrors);
84 cycrow 2471
	}
1 cycrow 2472
 
84 cycrow 2473
	CLog::log(CLog::Log_Directory, 2, "Backing up save game files");
1 cycrow 2474
 
160 cycrow 2475
	if ( CFileIO::Exists(m_sCurrentDir + "/mods/PluginManager.dat") ) {
84 cycrow 2476
		CLog::log(CLog::Log_IO, 3, "Removing old PluginManager.dat file");
158 cycrow 2477
		CFileIO::Remove(m_sCurrentDir + "/mods/PluginManager.dat");
84 cycrow 2478
	}
160 cycrow 2479
	if ( CFileIO::Exists(m_sCurrentDir + "/mods/PluginManager.cat") ) {
84 cycrow 2480
		CLog::log(CLog::Log_IO, 3, "Removing old PluginManager.cat file");
158 cycrow 2481
		CFileIO::Remove(m_sCurrentDir + "/mods/PluginManager.cat");
84 cycrow 2482
	}
1 cycrow 2483
 
2484
	if ( !m_bVanilla )
2485
	{
2486
		// base mode for Reunion
2487
		if ( m_iGame == GAME_X3 && m_pEnabledMod )
2488
		{
2489
			C_File *fDat = m_pEnabledMod->GetFirstFile(FILETYPE_MOD);
2490
			while ( fDat && !fDat->IsFakePatch() && !fDat->CheckFileExt("dat") )
2491
				fDat = m_pEnabledMod->GetNextFile(fDat);
2492
 
2493
			if ( fDat )
2494
			{
2495
				C_File *fCat = m_pEnabledMod->GetFirstFile(FILETYPE_MOD);
2496
				while ( fCat && !fCat->IsFakePatch() && !fCat->CheckFileExt("cat") && !fCat->GetBaseName().Compare(fDat->GetBaseName()) )
2497
					fCat = m_pEnabledMod->GetNextFile(fCat);
2498
 
2499
				if ( fCat )
2500
				{
160 cycrow 2501
					CFileIO(fDat->filePointer()).copy(m_sCurrentDir + "/mods/PluginManager.dat");
2502
					CFileIO(fCat->filePointer()).copy(m_sCurrentDir + "/mods/PluginManager.cat");
1 cycrow 2503
				}
2504
			}
2505
		}
160 cycrow 2506
		else if ( m_iGame == GAME_X3 && !m_sSetMod.empty() && CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat").ExistsOld() && CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".dat").ExistsOld())
1 cycrow 2507
		{
160 cycrow 2508
			CLog::log(CLog::Log_Directory, 2, "Copying mod file: " + m_sSetMod + ", to PluginManager.cat");
2509
			CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".dat").copy(m_sCurrentDir + "/mods/PluginManager.dat");
2510
			CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat").copy(m_sCurrentDir + "/mods/PluginManager.cat");
1 cycrow 2511
		}
2512
 
121 cycrow 2513
		if ( !CDirIO(m_sCurrentDir).exists("mods") )
160 cycrow 2514
			CDirIO(m_sCurrentDir).create("mods");
1 cycrow 2515
 
2516
		SetupWares();
2517
		SetupShips();
2518
		CreateEMPFile();
2519
		CreateWareFiles();
2520
		CreateDummies();
2521
		CreateComponants();
2522
		CreateTShips();
2523
		CreateCutData();
2524
		CreateBodies();
2525
		CreateAnimations();
2526
		CreateCustomStarts();
2527
		CreateGlobals();
2528
		CreatePluginManagerText();
2529
		RestoreFakePatch();
2530
	}
2531
 
2532
	RemoveFailedFiles();
2533
 
2534
	WriteData();
2535
	if ( removedir && m_bRemoveDir )
2536
	{
2537
		m_bRemoveDir = false;
160 cycrow 2538
		Utils::CStringList removeDirs;
2539
		removeDirs.pushBack(".");
2540
		removeUnusedDirectories(removeDirs, &lErrors);
1 cycrow 2541
	}
2542
 
158 cycrow 2543
	this->setCurrentDir("");
125 cycrow 2544
 
160 cycrow 2545
	//TEMP: switch to errors
2546
	if (errors)
2547
	{
2548
		for (auto itr = lErrors.begin(); itr != lErrors.end(); itr++)
2549
			errors->PushBack(CyString((*itr)->str), CyString((*itr)->data));
2550
	}
2551
 
1 cycrow 2552
	m_bLoaded = false;
2553
	return true;
2554
}
2555
 
2556
CyString CPackages::GetModKey()
2557
{
2558
	return m_gameExe.GetModKey(m_iGame - 1);
2559
}
160 cycrow 2560
Utils::String CPackages::selectedModName() const
1 cycrow 2561
{
2562
	if ( !m_pEnabledMod )
2563
	{
160 cycrow 2564
		if ( m_sSetMod.empty() && m_iGame == GAME_X3 )
1 cycrow 2565
			return "PluginManager";
2566
		return m_sSetMod;
2567
	}
2568
 
2569
	if ( !m_pEnabledMod->IsEnabled() )
2570
		return m_sSetMod;
2571
 
2572
	C_File *f = m_pEnabledMod->GetFirstFile(FILETYPE_MOD);
2573
	if ( !f )
2574
		return m_sSetMod;
2575
 
160 cycrow 2576
	Utils::String name = f->filename();
2577
	name = name.left(-4);
1 cycrow 2578
	return name;
2579
 
2580
}
2581
 
2582
bool CPackages::RestoreFakePatch()
2583
{
84 cycrow 2584
	CLog::log(CLog::Log_Directory, 1, "Restoring PluginManager fake patch into game");
2585
 	m_iFakePatch = -1;
1 cycrow 2586
 
2587
	CFileIO catFile(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat");
2588
	CFileIO datFile(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat");
2589
 
2590
	// if only 1 exists, remove it
52 cycrow 2591
	if ( catFile.exists() && !datFile.exists() ) {
84 cycrow 2592
		CLog::log(CLog::Log_Directory, 1, "WARNING: cat/dat file mismatch, dat file seems to be missing, removing cat file");
52 cycrow 2593
		if ( !catFile.remove() ) return false;
1 cycrow 2594
	}
52 cycrow 2595
	else if ( !catFile.exists() && datFile.exists() ) {
84 cycrow 2596
		CLog::log(CLog::Log_Directory, 1, "WARNING: cat/dat file mismatch, cat file seems to be missing, removing dat file");
52 cycrow 2597
		if ( !datFile.remove() ) return false;
1 cycrow 2598
	}
2599
 
2600
	// if both exists, lets rename them
52 cycrow 2601
	if ( catFile.exists() && datFile.exists() )
1 cycrow 2602
	{
84 cycrow 2603
		CLog::log(CLog::Log_Directory, 3, "Creating pluginmanagerfake.txt file to add to Fake Patch");
1 cycrow 2604
		// we need to add the plugin manager file in
2605
		CyString file = m_sTempDir;
2606
		if ( !file.Empty() )
2607
			file += "/";
2608
		file += "pluginmanagerfake.txt";
2609
		file = file.FindReplace("\\", "/");
2610
		CFileIO fakeFile(file);
160 cycrow 2611
		std::vector<Utils::String> lines;
1 cycrow 2612
		lines.push_back("//pluginmanager fake patch");
84 cycrow 2613
		CLog::log(CLog::Log_Directory, 3, "Writing pluginmanagerfake.txt file to add to Fake Patch");
160 cycrow 2614
		if ( !fakeFile.writeFile(&lines) ) {
84 cycrow 2615
			CLog::log(CLog::Log_Directory, 3, "Writing pluginmanagerfake.txt failed!!");
2616
		}
2617
		else {
85 cycrow 2618
/*
84 cycrow 2619
			CLog::log(CLog::Log_Directory, 2, "Adding TFake.pck file into FakePatch");
2620
			CCatFile fakePatch;
2621
			if ( fakePatch.Open(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat", this->GetAddonDir(), CATREAD_DAT, false) == CATERR_NONE )
1 cycrow 2622
			{
84 cycrow 2623
				if ( fakePatch.AppendFile(file.ToString(), "PlugMan\\TFake.pck") )
2624
					fakePatch.WriteCatFile();
85 cycrow 2625
			}	*/		
84 cycrow 2626
		}
1 cycrow 2627
 
85 cycrow 2628
		// backup existing mod files incase something happens to them
2629
		if ( !datFile.exists() || !catFile.exists() ) {
2630
			CLog::log(CLog::Log_Directory, 2, Utils::String("ERROR: ") + (!catFile.exists() ? "cat" : "dat") + " file appears to be missing");
2631
		}
2632
		else {
160 cycrow 2633
			catFile.GetDirIO().create("Backup");
85 cycrow 2634
			catFile.copy(catFile.dir() + "/Backup/" + catFile.filename());
2635
			datFile.copy(datFile.dir() + "/Backup/" + datFile.filename());
2636
		}
2637
 
2638
 
84 cycrow 2639
		// find next available fake patch
2640
		m_iFakePatch = this->FindNextFakePatch();
2641
		CLog::log(CLog::Log_Directory, 2, "Finding next available fake patch number: " + (long)m_iFakePatch);
1 cycrow 2642
 
84 cycrow 2643
		Utils::String filename = Utils::String::PadNumber(m_iFakePatch, 2);
2644
		CLog::log(CLog::Log_Directory, 2, "Renaming cat file to: " + filename + ".cat");
2645
		if ( catFile.Rename(m_sCurrentDir + "/" + filename + ".cat") )
2646
		{
2647
			CLog::log(CLog::Log_Directory, 2, "Renaming dat file to: " + filename + ".dat");
2648
			if ( datFile.Rename(m_sCurrentDir + "/" + filename + ".dat") ){
2649
				CLog::log(CLog::Log_Directory, 3, "Deleting pluginmanagerfake.txt temporary file");
2650
				fakeFile.remove();
2651
				return true;
1 cycrow 2652
			}
84 cycrow 2653
			else {
2654
				CLog::log(CLog::Log_Directory, 2, "ERROR: failed to rename dat file");
2655
			}
2656
 
2657
			// TODO: restore cat file
1 cycrow 2658
		}
84 cycrow 2659
		else {
2660
			CLog::log(CLog::Log_Directory, 2, "ERROR: failed to rename cat file");
2661
		}
1 cycrow 2662
 
84 cycrow 2663
		CLog::log(CLog::Log_Directory, 3, "Deleting pluginmanagerfake.txt temporary file");
52 cycrow 2664
		fakeFile.remove();
1 cycrow 2665
		return false;
2666
	}
2667
 
2668
	return true;
2669
}
2670
 
2671
 
2672
/**
2673
 * Save package detail to date file
2674
 *
2675
 * Writes the current package list data into pluginmanager.dat file
2676
 */
2677
void CPackages::WriteData()
2678
{
158 cycrow 2679
	if ( m_sCurrentDir.empty() )
1 cycrow 2680
		return;
2681
 
158 cycrow 2682
	CLog::log(CLog::Log_Directory, 1, "Writing data file for current directory: " + m_sCurrentDir);
84 cycrow 2683
 
160 cycrow 2684
	Utils::CStringList lines;
2685
	Utils::String version = "SpkInstaller: " + Utils::String::FromFloat(GetLibraryVersion(), 2);
2686
	lines.pushBack(version);
1 cycrow 2687
 
160 cycrow 2688
	lines.pushBack(Utils::String("UpdateTime: ") + (long)m_iLastUpdated);
1 cycrow 2689
	if ( m_iFakePatch != -1 )
160 cycrow 2690
		lines.pushBack(Utils::String("FakePatch: ") + (long)m_iFakePatch);
1 cycrow 2691
	if ( m_iSaveGame != -1 )
160 cycrow 2692
		lines.pushBack(Utils::String("SaveGame: ") + (long)m_iSaveGame);
2693
	lines.pushBack(Utils::String("SaveGameManager: ") + (long)m_iSaveGameManager);
1 cycrow 2694
	if ( !m_bVanilla )
160 cycrow 2695
		lines.pushBack("Modified");
1 cycrow 2696
	if ( m_bUsedWare )
160 cycrow 2697
		lines.pushBack("UsedWare");
1 cycrow 2698
	if ( m_bSurpressProtectedWarning )
160 cycrow 2699
		lines.pushBack("SurpressProtectedWarning");
2700
	if ( !m_sSetMod.empty() )
2701
		lines.pushBack("SetMod: " + m_sSetMod);
126 cycrow 2702
	if (!_sSaveDir.empty())
160 cycrow 2703
		lines.pushBack("SaveDir: " + _sSaveDir);
2704
	lines.pushBack(Utils::String("ShipBuffer: ") + (long)m_iShipBuffer);
2705
	Utils::String wareBuffer = "WareBuffers:";
1 cycrow 2706
	for ( int i = 0; i < WAREBUFFERS; i++ )
160 cycrow 2707
		wareBuffer += Utils::String(" ") + (long)m_iWareBuffer[i];
2708
	lines.pushBack(wareBuffer);
1 cycrow 2709
	for ( int i = 0; i < WAREBUFFERS; i++ )
2710
	{
2711
		if ( !m_lGameWares[i].size() )
2712
			continue;
160 cycrow 2713
		lines.pushBack(Utils::String("Wares: ") + (long)i + " " + (long)m_lGameWares[i].size());
1 cycrow 2714
 
2715
		for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() )
2716
		{
2717
			SGameWare *gm = node->Data();
160 cycrow 2718
			lines.pushBack(Utils::String((long)gm->iPos) + " " + (long)gm->iType + " " + Utils::String((char)gm->cType) + " " + gm->sWareName);
1 cycrow 2719
		}
2720
	}
2721
 
160 cycrow 2722
	for(auto itr = m_lNonRemovedFiles.begin(); itr != m_lNonRemovedFiles.end(); itr++)
2723
		lines.pushBack("NonRemovedFile: " + (*itr)->str);
1 cycrow 2724
 
2725
	if ( m_lGameShips.size() )
2726
	{
160 cycrow 2727
		lines.pushBack(Utils::String("Ships: ") + (long)m_lGameShips.size());
1 cycrow 2728
 
2729
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
2730
		{
2731
			SGameShip *gm = node->Data();
160 cycrow 2732
			lines.pushBack(Utils::String((long)gm->iType) + " $#C:" + gm->sShipClass + " " + gm->sShipID);
1 cycrow 2733
		}
2734
	}
2735
 
2736
	// write created Files
160 cycrow 2737
	if ( !m_lCreatedFiles.empty() )
1 cycrow 2738
	{
160 cycrow 2739
		for(auto itr = m_lCreatedFiles.begin(); itr != m_lCreatedFiles.end(); itr++)
2740
			lines.pushBack("CreatedFile: " + (*itr)->str.findRemove(m_sCurrentDir));
1 cycrow 2741
	}
2742
 
2743
	// write uninstall files
2744
	if ( !m_lUninstallFiles.empty() )
2745
	{
2746
		for ( CListNode<C_File> *node = m_lUninstallFiles.Front(); node; node = node->next() )
2747
		{
2748
			C_File *uf = node->Data();
160 cycrow 2749
			Utils::String uString = "Uninstall: ";
2750
			uString += Utils::String::Number((long)uf->GetCreationTime()) + " ";
158 cycrow 2751
			uString += uf->filename();
160 cycrow 2752
			lines.pushBack(uString);
1 cycrow 2753
		}
2754
	}
2755
 
2756
	// write the original file data
160 cycrow 2757
	_pOriginalFiles->writeData(lines);
1 cycrow 2758
 
2759
	// write the global changes
160 cycrow 2760
	if ( !m_lGlobals.empty() )
1 cycrow 2761
	{
160 cycrow 2762
		for(auto itr = m_lGlobals.begin(); itr != m_lGlobals.end(); itr++)
2763
			lines.pushBack("GlobalSetting: " + (*itr)->str + ":" + (*itr)->data.findRemove(";"));
1 cycrow 2764
	}
2765
 
2766
	// write the fake patch ordering
160 cycrow 2767
	if ( !m_lFakePatchOrder.empty() )
1 cycrow 2768
	{
160 cycrow 2769
		for(auto itr = m_lFakePatchOrder.begin(); itr != m_lFakePatchOrder.end(); itr++)
2770
			lines.pushBack("FakePatchOrder: " + (*itr)->str + ":" + (*itr)->data);
1 cycrow 2771
	}
2772
 
88 cycrow 2773
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
2774
		SWarePriceOverride *ware = node->Data();
2775
		switch(ware->type) {
2776
			case Ware_EMP:
160 cycrow 2777
				lines.pushBack(Utils::String("EMPPriceOverride:") + (long)ware->pos + " " + (long)ware->relval);
88 cycrow 2778
				if ( ware->bNotority )
160 cycrow 2779
					lines.pushBack(Utils::String("EMPNotoOverride:") + (long)ware->pos + " " + (long)ware->notority);
88 cycrow 2780
				break;
2781
			case Ware_Custom:
160 cycrow 2782
				lines.pushBack(Utils::String("CustomWarePriceOverride:") + ware->id + ";" + (long)ware->relval);
88 cycrow 2783
				if ( ware->bNotority )
160 cycrow 2784
					lines.pushBack(Utils::String("CustomWareNotoOverride:") + ware->id + ";" + (long)ware->notority);
88 cycrow 2785
				break;
2786
			case Ware_BuiltIn:
160 cycrow 2787
				lines.pushBack(Utils::String("BuiltInWarePriceOverride:") + (long)ware->pos + " " + (long)ware->relval);
88 cycrow 2788
				if ( ware->bNotority )
160 cycrow 2789
					lines.pushBack(Utils::String("BuiltInWareNotoOverride:") + (long)ware->pos + " " + (long)ware->notority);
88 cycrow 2790
				break;
2791
		}
2792
	}
2793
 
1 cycrow 2794
	// write the global file list
160 cycrow 2795
	lines.pushBack("GlobalFiles:");
1 cycrow 2796
	int num = 0;
2797
	for ( CListNode<C_File> *fn = m_lFiles.Front(); fn; fn = fn->next() )
2798
	{
2799
		C_File *f = fn->Data();
2800
		f->SetPos(num++);
2801
 
160 cycrow 2802
		Utils::String line = Utils::String::Number(f->GetFileType()) + ":" + Utils::String::Number((long)f->GetCreationTime()) + ":" + f->dir() + ":";
1 cycrow 2803
		if ( f->IsShared() && !f->IsFakePatch() )
2804
			line += "1:";
2805
		else
2806
			line += "0:";
2807
 
160 cycrow 2808
		Utils::String filename = f->filePointer().findRemove(m_sCurrentDir);
1 cycrow 2809
 
2810
		if ( f->IsDisabled() )
2811
			line += "D#";
2812
 
2813
		line += "G#";
2814
		line += (long)f->GetGame();
2815
		line += "#";
2816
 
2817
		line += filename;
2818
 
160 cycrow 2819
		if ( !f->originalName().empty() )
1 cycrow 2820
		{
2821
			line += "O#";
160 cycrow 2822
			line += f->originalName();
1 cycrow 2823
		}
2824
 
160 cycrow 2825
		lines.pushBack(line);
1 cycrow 2826
	}
2827
 
2828
	// write the package list
2829
	for ( CListNode<CBaseFile> *pn = m_lPackages.Front(); pn; pn = pn->next() )
2830
	{
2831
		CBaseFile *package = pn->Data();
2832
 
2833
		if ( package->GetType() == TYPE_SPK )
160 cycrow 2834
			lines.pushBack("<script>");
1 cycrow 2835
		else if ( package->GetType() == TYPE_XSP )
160 cycrow 2836
			lines.pushBack("<ship>");
1 cycrow 2837
		else if ( package->GetType() == TYPE_ARCHIVE )
160 cycrow 2838
			lines.pushBack("<archive>");
1 cycrow 2839
		else if ( package->GetType() == TYPE_BASE )
160 cycrow 2840
			lines.pushBack("<base>");
1 cycrow 2841
		else
2842
			continue;
2843
 
50 cycrow 2844
		if ( !package->filename().empty() )
160 cycrow 2845
			lines.pushBack("Installspk: " + package->filename());
1 cycrow 2846
 
160 cycrow 2847
		Utils::String valuesline = package->CreateValuesLine();
2848
		if ( valuesline.back() == '\n')
2849
			valuesline.truncate((int)valuesline.length() - 1);
2850
		lines.pushBack(valuesline);
1 cycrow 2851
 
2852
		if ( !package->IsEnabled() )
160 cycrow 2853
			lines.pushBack("Disabled");
1 cycrow 2854
		if ( !package->IsModifiedEnabled() )
160 cycrow 2855
			lines.pushBack("ModifiedDisabled");
1 cycrow 2856
 
2857
		if ( package->GetIcon() )
160 cycrow 2858
			lines.pushBack("Icon: " + package->iconExt() + " " + package->GetIcon()->filePointer() );
1 cycrow 2859
 
160 cycrow 2860
		Utils::String fileline("Files:");
1 cycrow 2861
		for ( CListNode<C_File> *fn = package->GetFileList()->Front(); fn; fn = fn->next() )
2862
		{
2863
			C_File *f = fn->Data();
2864
			fileline += " ";
160 cycrow 2865
			fileline += Utils::String::Number(f->GetPos());
1 cycrow 2866
		}
160 cycrow 2867
		lines.pushBack(fileline);
1 cycrow 2868
	}
2869
 
160 cycrow 2870
	lines.pushBack("</scripts>");
1 cycrow 2871
 
84 cycrow 2872
	CFileIO datFile(m_sCurrentDir + "/PluginManager/PluginManager.new");
1 cycrow 2873
 
2874
	CDirIO Dir(m_sCurrentDir);
121 cycrow 2875
	if ( !Dir.exists("PluginManager") ) {
84 cycrow 2876
		CLog::log(CLog::Log_IO, 2, "Creating PluginManager directory");
160 cycrow 2877
 		Dir.create("PluginManager");
84 cycrow 2878
	}
1 cycrow 2879
 
158 cycrow 2880
	CLog::log(CLog::Log_IO, 2, "Writing data file: " + m_sCurrentDir + "/PluginManager/PluginManager.new");
160 cycrow 2881
	if ( !datFile.writeFile(&lines) )
1 cycrow 2882
	{
84 cycrow 2883
		CLog::log(CLog::Log_IO, 1, "ERROR: Failed to write data file");
1 cycrow 2884
	}
84 cycrow 2885
	else {
158 cycrow 2886
		CLog::log(CLog::Log_IO, 2, "Removing old data file: " + m_sCurrentDir + "/PluginManager/PluginManager.dat");
2887
		if ( !CFileIO::Exists(m_sCurrentDir + "/PluginManager/PluginManager.dat") || CFileIO::Remove(m_sCurrentDir + "/PluginManager/PluginManager.dat") ) {
84 cycrow 2888
			CLog::log(CLog::Log_IO, 2, "Renaming data file: PluginManager.new => PluginManager.dat");
2889
			datFile.Rename(m_sCurrentDir + "/PluginManager/PluginManager.dat");
2890
		}
2891
	}
1 cycrow 2892
}
2893
 
2894
 
2895
/**
2896
 * Get All Files
2897
 *
2898
 * Gets a list of all files, includes any child package files
2899
 */
2900
int CPackages::GetAllPackageFiles(CBaseFile *package, CLinkList<C_File> *fileList, bool includeChild)
2901
{
2902
	for ( CListNode<C_File> *node = package->GetFileList()->Front(); node; node = node->next() )
2903
	{
2904
		C_File *f = node->Data();
2905
		if ( !fileList->FindData(f) )
2906
			fileList->push_back(f);
2907
	}
2908
 
2909
	if ( includeChild )
2910
	{
2911
		CLinkList<CBaseFile> childList;
2912
		if ( this->GetChildPackages(package, &childList) )
2913
		{
2914
			for ( CBaseFile *child = childList.First(); child; child = childList.Next() )
2915
				this->GetAllPackageFiles(child, fileList, includeChild);
2916
		}
2917
	}
2918
 
2919
	// disablign for vanilla, make sure we add all files
2920
	if ( m_bDisableVanilla )
2921
	{
2922
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2923
		{
2924
			C_File *f = node->Data();
2925
			if ( !fileList->FindData(f) )
2926
				fileList->push_back(f);
2927
		}
2928
	}
2929
 
2930
	return fileList->size();
2931
}
2932
 
2933
int CPackages::GetAllPackageFiles(CLinkList<CBaseFile> *list, CLinkList<C_File> *fileList, bool includeChild)
2934
{
2935
	for ( CListNode<CBaseFile> *node = list->Front(); node; node = node->next() )
2936
		this->GetAllPackageFiles(node->Data(), fileList, includeChild);
2937
	return fileList->size();
2938
}
2939
 
2940
/**
2941
 * Add Log
2942
 *
2943
 * Adds a log entry to displayed at end
2944
 */
160 cycrow 2945
void CPackages::AddLogEntry(int type, CyString args, CyStringList* errors)
1 cycrow 2946
{
160 cycrow 2947
	if (!errors)
1 cycrow 2948
		return;
2949
 
134 cycrow 2950
	errors->PushBack(args, ERRORLOG_OLD(type));
1 cycrow 2951
}
160 cycrow 2952
void CPackages::addLogEntry(int type, const Utils::String &args, Utils::CStringList *errors)
2953
{
2954
	if (!errors)
2955
		return;
1 cycrow 2956
 
160 cycrow 2957
	errors->pushBack(args, ERRORLOG(type));
2958
}
2959
 
1 cycrow 2960
/**
2961
 * Enable a package
2962
 *
2963
 * Enables all files in the package, unless they are already enabled, ie, used by other packages
2964
 * Backs up any original files before attempting to enable the file
2965
 *
2966
 * Fake patches are renamed to the next available slot
2967
 *
2968
 * Clears up the "PluginManager/Disabled" directory
2969
 *
2970
 * param: package		- The package class to be removed
2971
 * param: errors		- The string list for all the status for debugging, ie has an entry for whats happened to every file
2972
 * param: progress		- The progress class, updates a progress screen of the derived class
2973
 *
2974
 * return: boolen - Returns true if the package enabling was successful
2975
 */
2976
bool CPackages::EnablePackage ( CBaseFile *package, CyStringList *errors, CProgressInfo *progress )
2977
{
2978
	ClearError();
2979
 
2980
	// if already enabled, just skip
2981
	if ( package->IsEnabled() )
2982
		return true;
2983
 
2984
	// check if parent is enabled
2985
	if ( package->GetParent() && !package->GetParent()->IsEnabled() )
2986
	{
2987
		m_iError = PKERR_NOPARENT;
2988
		return false;
2989
	}
2990
 
2991
	// check for modified
2992
	if ( m_bVanilla && !package->IsSigned() )
2993
	{
2994
		m_iError = PKERR_MODIFIED;
2995
		return false;
2996
	}
2997
 
2998
	if ( this->PrepareEnablePackage(package) )
2999
		return this->EnablePreparedPackages(errors, progress);
3000
 
3001
	return false;
3002
}
3003
bool CPackages::EnablePreparedPackages ( CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *enabledPackages )
3004
{
3005
	ClearError();
3006
 
3007
	// get all files, including children
3008
	CLinkList<C_File> fileList;
3009
	int maxFiles = this->GetAllPackageFiles(&m_lEnableList, &fileList, false);
3010
 
3011
	int fileCount = 0;
3012
	// we use this list to match cat and dat files
147 cycrow 3013
	Utils::CStringList fakePatches;
1 cycrow 3014
	for ( CListNode<C_File> *node = fileList.Front(); node; node = node->next() )
3015
	{
3016
		C_File *f = node->Data();
147 cycrow 3017
		if (!f->isForGame(m_iGame))
3018
			continue;
1 cycrow 3019
		CBaseFile *package = NULL;
3020
		for ( CListNode<CBaseFile> *node = m_lEnableList.Front(); node; node = node->next() )
3021
		{
3022
			CBaseFile *p = node->Data();
3023
			if ( p->IsFileAdded(f) )
3024
			{
3025
				package = p;
3026
				break;
3027
			}
3028
		}
3029
 
3030
		if ( progress )
3031
		{
3032
			progress->UpdateProgress(fileCount++, maxFiles);
3033
			progress->UpdateFile(f);
3034
		}
3035
 
3036
		// only move fiels that are disabled
3037
		if ( !f->IsDisabled() )
3038
			continue;
3039
 
3040
		// make the directory if it dont exist
3041
		CDirIO Dir(m_sCurrentDir);
3042
 
3043
		// fake patches are in the root, no need for directory
3044
		if ( !f->IsFakePatch() )
3045
		{
121 cycrow 3046
			if ( !Dir.exists(f->getDirectory(package)) )
1 cycrow 3047
			{
160 cycrow 3048
				if ( !Dir.create(f->getDirectory(package)) )
1 cycrow 3049
				{
3050
					this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, f->GetDirectory(package), errors);
3051
					continue;
3052
				}
3053
				this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY, f->GetDirectory(package), errors);
3054
			}
3055
		}
3056
 
3057
		// check if theres an original file to backup
93 cycrow 3058
		_pOriginalFiles->doBackup(f, errors);
1 cycrow 3059
 
158 cycrow 3060
		Utils::String newFilename = f->getNameDirectory(package);
1 cycrow 3061
 
3062
		// fake patches need to be renamed
3063
		if ( f->IsFakePatch() )
3064
		{
3065
			// first check if the matching file has been done already
147 cycrow 3066
			if (fakePatches.contains(f->baseName()))
3067
				newFilename = fakePatches.findString(f->baseName()) + "." + f->fileExt();
1 cycrow 3068
			// we need to find the next available number instead
3069
			else
3070
			{
147 cycrow 3071
				Utils::String newPos = Utils::String::PadNumber(FindNextFakePatch(), 2);
3072
				newFilename = newPos + "." + f->fileExt();
1 cycrow 3073
				// and wee need to push this onto the string list so we can adjust the matchign pair
147 cycrow 3074
				fakePatches.pushBack(f->baseName(), newPos);
1 cycrow 3075
			}
3076
		}
3077
 
3078
		// lets actually move the file back now
3079
		// !!error checking!!
147 cycrow 3080
		CFileIO currentFile(f->filePointer());
1 cycrow 3081
		CFileIO newFile(m_sCurrentDir + "/" + newFilename);
52 cycrow 3082
		if ( !currentFile.exists() )
1 cycrow 3083
		{
3084
			// missing file ??
52 cycrow 3085
			if ( !newFile.exists() )
1 cycrow 3086
			{
3087
				this->AddLogEntry(SPKINSTALL_MISSINGFILE, newFilename, errors);
3088
				continue;
3089
			}
3090
		}
3091
		// remove existing file
3092
		// file exists, so lets try to move it
3093
		else
3094
		{
52 cycrow 3095
			if ( newFile.exists() )
3096
				newFile.remove();
1 cycrow 3097
 
102 cycrow 3098
			if ( !currentFile.Rename(newFile.fullFilename()) )
1 cycrow 3099
			{
3100
				this->AddLogEntry(SPKINSTALL_ENABLEFILE_FAIL, newFilename, errors);
3101
				continue;
3102
			}
3103
		}
3104
 
3105
		this->AddLogEntry(SPKINSTALL_ENABLEFILE, newFilename, errors);
3106
 
3107
		// adjust the internal name to match the new filename
158 cycrow 3108
		f->setFilename(m_sCurrentDir + "/" + newFilename);
1 cycrow 3109
		// no longer disabled, we need to remove the flag
3110
		f->SetDisabled(false);
3111
	}
3112
 
3113
	// recursive, auto enable all children
3114
	CBaseFile *oldMod = m_pEnabledMod;
3115
	CBaseFile *pMod = NULL;
3116
 
3117
	for ( CListNode<CBaseFile> *node = m_lEnableList.Front(); node; node = node->next() )
3118
	{
3119
		CBaseFile *p = node->Data();
3120
		p->SetEnabled(true);
3121
		if ( p->IsMod() && !pMod )
3122
			pMod = p;
3123
 
3124
		if ( enabledPackages )
3125
			enabledPackages->push_back(p);
105 cycrow 3126
 
3127
		_pOriginalFiles->installed(p);
1 cycrow 3128
	}
3129
 
105 cycrow 3130
 
1 cycrow 3131
	if ( pMod )
3132
		m_pEnabledMod = pMod;
3133
 
3134
	// disabled the mod
3135
	if ( oldMod && oldMod != m_pEnabledMod && !m_bForceModInstall )
3136
		this->DisablePackage(oldMod, errors, progress);
3137
 
3138
	// lets remove all the directories we might have left empty
3139
	CyStringList removeDirs;
3140
	removeDirs.PushBack(CyString("PluginManager/Disabled"));
3141
	RemoveUnusedDirectories(removeDirs, errors);
3142
 
3143
	m_lEnableList.clear();
3144
 
3145
	this->WriteData();
3146
 
3147
	return true;
3148
}
3149
 
3150
 
3151
bool CPackages::DisablePreparedPackages ( CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *disabledPackages )
3152
{
3153
	if ( progress )
3154
		progress->UpdateStatus(PROGRESS_DISABLEFILE);
3155
 
3156
	UpdateUsedFiles(&m_lDisableList, false);
3157
 
3158
	// checks if there are any original files to restore and if any fake patches were disabled to reshuffle
3159
	bool original = false, shuffle = false;
3160
 
3161
	// holds our list of directories that we might need to remove, only empty ones from this list will actually be removed
3162
	CyStringList removeDirs;
3163
 
3164
	// get all files, including children
3165
	CLinkList<C_File> fileList;
3166
	int maxFiles = this->GetAllPackageFiles(&m_lDisableList, &fileList, true);
3167
 
3168
	// interate through all the files in the package
3169
	int fileCount = 0;
3170
	for ( CListNode<C_File> *node = fileList.Front(); node; node = node->next() )
3171
	{
3172
		C_File *f = node->Data();
3173
		CBaseFile *checkPackage = NULL;
3174
		for ( CListNode<CBaseFile> *node = m_lDisableList.Front(); node; node = node->next() )
3175
		{
3176
			CBaseFile *p = node->Data();
3177
			if ( p->IsFileAdded(f) )
3178
			{
3179
				checkPackage = p;
3180
				break;
3181
			}
3182
		}
3183
 
3184
		// update the progress count for the current file
3185
		if ( progress )
3186
		{
3187
			progress->UpdateProgress(++fileCount, maxFiles);
3188
			progress->UpdateFile(f);
3189
		}
3190
 
3191
		// only delete files that are not used by any other enabled packages, counter from UpdateUsedFiles()
160 cycrow 3192
		if ( f->getUsed() || (f->IsShared() && !m_bDisableVanilla) )
1 cycrow 3193
			continue;
3194
 
3195
		// file is already disabled, no need to disable again
3196
		if ( f->IsDisabled() )
3197
			continue;
3198
 
3199
		// readmes, uninstall and extra files dont need to be disabled
3200
		// Extra files not in the "Extras" directory could be anywhere, so these should be disabled incase they are game changing files, ie in "types"
3201
		if ( f->GetFileType() == FILETYPE_README || f->GetFileType() == FILETYPE_UNINSTALL || (f->GetFileType() == FILETYPE_EXTRA && f->GetDir().Left(5).lower() == "Extra") )
3202
			continue;
3203
 
3204
		// check if there is a matching uninstall file, ie there the script file is also an uninstall script file for a previously uninstalled package that has yet to be removed
3205
		if ( f->GetFileType() == FILETYPE_SCRIPT )
3206
		{
3207
			bool found = false;
3208
			for ( CListNode<C_File> *uNode = m_lUninstallFiles.Front(); uNode; uNode = uNode->next() )
3209
			{
3210
				C_File *uFile = uNode->Data();
158 cycrow 3211
				if ( uFile->filename().Compare(f->filename()) )
1 cycrow 3212
				{
3213
					found = true;
3214
					break;
3215
				}
3216
			}
3217
 
3218
			if ( found )
3219
				continue;
3220
		}
3221
 
3222
		if ( f->GetFileType() == FILETYPE_MOD && !f->IsFakePatch() && f->CheckFileExt("cat") )
3223
		{
160 cycrow 3224
			if ( f->baseName().Compare(m_sSetMod) )
3225
				m_sSetMod = Utils::String::Null();
1 cycrow 3226
		}
3227
 
3228
		// file is not being used by any enabled package
3229
		// set disabled and move to disabled directory
3230
		CDirIO Dir(m_sCurrentDir);
121 cycrow 3231
		Utils::String newFilename = "PluginManager/Disabled/";
1 cycrow 3232
 
3233
		// fake patches have thier own special directory
3234
		if ( f->IsFakePatch() )
3235
			newFilename += "FakePatches";
3236
		// otherwise we put them in thier usual directory structure inside the disabled dir
3237
		else
121 cycrow 3238
			newFilename += f->getDirectory(NULL);
1 cycrow 3239
 
3240
		// make sure the directory exists so we can move the file
121 cycrow 3241
		if ( !Dir.exists(newFilename) )
1 cycrow 3242
		{
3243
			// we couldn't create the directory for some reason, this is not good
160 cycrow 3244
			if ( !Dir.create(newFilename) )
1 cycrow 3245
			{
3246
				this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, newFilename, errors);
3247
				continue;
3248
			}
3249
			this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY, newFilename, errors);
3250
		}
3251
 
3252
		// fake patches need a special directory and filename so they dont overright each other as thier filenames are always changes
3253
		// if a package with a fake patch is installed while another one is disabled, it will fill the gap left by the disabled one
3254
		// they will then end up with the same filename, if it gets disabled they would overright each other, so we change the filename to prevent that from happening
3255
		if ( f->IsFakePatch() )
3256
		{
3257
			// find package the fake patch belongs to
3258
			if ( checkPackage )
3259
			{
158 cycrow 3260
				newFilename = Utils::String(m_sCurrentDir) + "/PluginManager/Disabled/FakePatches/FakePatch_" + checkPackage->getNameValidFile() + "_" + checkPackage->author() + "_" + f->name();
1 cycrow 3261
				shuffle = true;
3262
			}
3263
		}
130 cycrow 3264
		else if ( f->isAutoTextFile() )
1 cycrow 3265
		{
3266
			if ( checkPackage )
3267
			{
158 cycrow 3268
				newFilename = Utils::String(m_sCurrentDir) + "/PluginManager/Disabled/TextFiles/Text_" + checkPackage->getNameValidFile() + "_" + checkPackage->author() + "_" + f->name();
1 cycrow 3269
				shuffle = true;
3270
			}
3271
		}
3272
		// otherwise we can just use the standard filename
3273
		else
158 cycrow 3274
			newFilename = Utils::String(m_sCurrentDir) + "/PluginManager/Disabled/" + f->GetNameDirectory(checkPackage).ToString();
1 cycrow 3275
 
3276
		// now to move the file by renameing it to its new location
3277
		// !!error checking!!
3278
		// check the file, if it doesn't exist, and exists as disabled, we should just adjust the setting instead of an error
3279
		CFileIO currentFile(f->GetFilePointer());
52 cycrow 3280
		if ( !currentFile.exists() )
1 cycrow 3281
		{
52 cycrow 3282
			if ( !CFileIO(newFilename).exists() )
1 cycrow 3283
			{
3284
				this->AddLogEntry(SPKINSTALL_MISSINGFILE, f->GetNameDirectory(checkPackage), errors);
3285
				continue;
3286
			}
3287
		}
3288
		// otherwise the file must exists, so lets move it
3289
		else if ( !currentFile.Rename(newFilename) )
3290
		{
3291
			this->AddLogEntry(SPKINSTALL_DISABLEFILE_FAIL, f->GetNameDirectory(checkPackage), errors);
3292
			continue;
3293
		}
3294
 
3295
		// must have been fine
3296
		this->AddLogEntry(SPKINSTALL_DISABLEFILE, f->GetNameDirectory(checkPackage), errors);
3297
 
93 cycrow 3298
		original = _pOriginalFiles->restoreFile(f, errors);
1 cycrow 3299
 
3300
		// extra file thats not in the extras directory
3301
		if ( f->GetFileType() == FILETYPE_EXTRA || f->GetFileType() == FILETYPE_MAP || f->GetFileType() == FILETYPE_SOUND )
3302
			removeDirs.PushBack(f->GetDirectory(checkPackage), NullString, true);
3303
 
3304
		// change the filename
3305
		f->SetFilename(newFilename);
3306
 
3307
		// finally mark the file as disabled so we know not to try to move it again
3308
		f->SetDisabled(true);
3309
	}
3310
 
3311
	// a fake patch has been disabled, we need to reshuffle the rest to fill in any gaps
3312
	if ( shuffle )
3313
	{
3314
		if ( progress )
3315
			progress->UpdateStatus(PROGRESS_SHUFFLEFAKE);
3316
		ShuffleFakePatches(errors);
3317
		ShuffleTextFiles(errors);
3318
	}
3319
 
3320
	// original files were restored, check to remove the original file directory if its now empty
3321
	if ( original )
3322
		removeDirs.PushBack(CyString("PluginManager/Original"));
3323
 
3324
	// remove any empty directories that we might have left
3325
	if ( !removeDirs.Empty() )
3326
		RemoveUnusedDirectories(removeDirs, errors);
3327
 
3328
	// finally mark the whole package as disabled
3329
	// recursive, we need to disable all children
3330
	for ( CBaseFile *child = m_lDisableList.First(); child; child = m_lDisableList.Next() )
3331
	{
3332
		if ( m_pEnabledMod == child )
3333
			m_pEnabledMod = NULL;
3334
		child->SetEnabled(false);
3335
 
3336
		if ( disabledPackages )
3337
			disabledPackages->push_back(child);
3338
	}
3339
 
3340
	// disabling has completed successfully, we hope
3341
	m_bDisableVanilla = false;
3342
	m_lDisableList.clear();
3343
 
3344
	this->WriteData();
3345
 
3346
	return true;
3347
}
3348
 
3349
/**
3350
 * Disables the selected package
3351
 *
3352
 * Disables all enabled files that are not being used by any other enabled package
3353
 * Any files that are being used by other enabled packages are skipped and left enabled
3354
 *
3355
 * Original Files are restored when file is disabled
3356
 *
3357
 * Fake patches are shuffled to fill in any gaps caused by disabling fake patches
3358
 *
3359
 * All files go into the Plugin/Disabled directory into thier respective directories.
3360
 *
3361
 * Any directories left empty when disabling files are then removed
3362
 *
3363
 * param: package	- Package file to be disabled
3364
 * param: errors	- A string list used to add the status as it progresses, used in debugging output
3365
 * param: progress	- The progress class, updates the progress of the current disabling.  Needs a divered class to report the progress somewhere
3366
 *
3367
 * return: boolean, true if there was no errors, otherwise false
3368
 */
3369
bool CPackages::DisablePackage ( CBaseFile *package, CyStringList *errors, CProgressInfo *progress )
3370
{
3371
	// if already disabled, just skip
3372
	if ( !package->IsEnabled() )
3373
		return true;
3374
 
3375
	m_lDisableList.clear();
3376
	if ( this->PrepareDisablePackage(package) )
3377
		return this->DisablePreparedPackages(errors, progress);
3378
 
3379
	return false;
3380
}
3381
 
3382
 
3383
/**
3384
 * Find a Package
3385
 *
3386
 * Finds a matching package so we can find if one is already installed
3387
 *
3388
 * Uses seperate functions for each package type, ie for SPK and XSP packages
3389
 */
160 cycrow 3390
CBaseFile* CPackages::FindPackage(CBaseFile* package)
1 cycrow 3391
{
3392
	// no point checking if we've been sent a null pointer
3393
	if ( !package )
3394
		return 0;
3395
 
3396
	// we are checking against a SPK package, so we match the name and author
3397
	if ( package->GetType() == TYPE_SPK )
50 cycrow 3398
		return FindSpkPackage(package->name(), package->author());
1 cycrow 3399
	else if ( package->GetType() == TYPE_XSP )
3400
		return FindXspPackage(((CXspFile *)package)->GetShipID());
3401
	else if ( package->GetType() == TYPE_ARCHIVE )
50 cycrow 3402
		return FindArchivePackage(package->name());
1 cycrow 3403
 
3404
	// nothing found obviously
3405
	return 0;
3406
}
3407
 
3408
CBaseFile *CPackages::FindFirstPackageWithFile(C_File *f)
3409
{
3410
	return FindNextPackageWithFile(NULL, f);
3411
}
3412
 
3413
CBaseFile *CPackages::FindNextPackageWithFile(CBaseFile *p, C_File *f)
3414
{
3415
	bool startCheck = (p) ? false : true;
3416
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
3417
	{
3418
		if ( startCheck )
3419
		{
3420
			if ( node->Data()->IsFileAdded(f) )
3421
				return node->Data();
3422
		}
3423
		else if ( p == node->Data() )
3424
			startCheck = true;
3425
	}
3426
 
3427
	return NULL;
3428
}
3429
 
3430
 
3431
/**
3432
 * Find a File
3433
 *
3434
 * Searches for a file matching the filetype and filename
3435
 * Optional dir is used for extras files
3436
 */
3437
C_File *CPackages::FindFile(int filetype, CyString filename, CyString dir)
3438
{
3439
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
3440
	{
3441
		C_File *f = node->Data();
3442
		if ( f->GetFileType() != filetype )
3443
			continue;
3444
 
158 cycrow 3445
		if ( !f->filename().Compare(filename.ToString()) )
1 cycrow 3446
			continue;
3447
 
158 cycrow 3448
		if ( !dir.Empty() && f->dir().Compare(dir.ToString()) )
1 cycrow 3449
			continue;
3450
 
3451
		return f;
3452
	}
3453
 
3454
	return NULL;
3455
}
3456
 
3457
CArchiveFile *CPackages::FindArchivePackage(CyString name)
3458
{
3459
	// interate through all packages
3460
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
3461
	{
3462
		CBaseFile *file = node->Data();
3463
 
3464
		// only look for archive packages
3465
		if ( file->GetType() != TYPE_ARCHIVE )
3466
			continue;
3467
 
3468
		// now compare the name and author, "Compare" is a non case senseative check, opposed to ==.
50 cycrow 3469
		if ( file->name().Compare(name.ToString()) )
1 cycrow 3470
			return (CArchiveFile *)file;
3471
	}
3472
 
3473
	// nothing found
3474
	return 0;
3475
}
3476
 
3477
/**
3478
 * Find a SPK Package
3479
 *
3480
 * This searching all installed packages for a SPK Package matching the name and author
3481
 */
3482
CBaseFile *CPackages::FindSpkPackage(CyString name, CyString author)
3483
{
133 cycrow 3484
	return findSpkPackage(name.ToString(), author.ToString());
3485
}
3486
CBaseFile *CPackages::findSpkPackage(const Utils::String &name, const Utils::String &author) const
3487
{
1 cycrow 3488
	// interate through all packages
3489
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
3490
	{
3491
		CBaseFile *file = node->Data();
3492
 
3493
		// only look for spk packages
3494
		if ( file->GetType() != TYPE_SPK )
3495
			continue;
3496
 
3497
		// now compare the name and author, "Compare" is a non case senseative check, opposed to ==.
133 cycrow 3498
		if ( file->name().Compare(name) && file->author().Compare(author) )
1 cycrow 3499
			return file;
3500
	}
3501
 
3502
	// nothing found
3503
	return 0;
3504
}
3505
 
160 cycrow 3506
CBaseFile* CPackages::findPackage(const Utils::String &name, const Utils::String &author) const
1 cycrow 3507
{
3508
	// interate through all packages
160 cycrow 3509
	for (CListNode<CBaseFile>* node = m_lPackages.Front(); node; node = node->next())
1 cycrow 3510
	{
160 cycrow 3511
		CBaseFile* file = node->Data();
1 cycrow 3512
 
3513
		// now compare the name and author, "Compare" is a non case senseative check, opposed to ==.
160 cycrow 3514
		if (file->name().Compare(name) && file->author().Compare(author))
1 cycrow 3515
			return file;
3516
	}
3517
 
3518
	// nothing found
3519
	return 0;
3520
}
160 cycrow 3521
CBaseFile* CPackages::FindPackage(CyString name, CyString author)
3522
{
3523
	return findPackage(name.ToString(), author.ToString());
3524
}
1 cycrow 3525
 
3526
/**
3527
 * Find a XSP Package
3528
 *
3529
 * This searching all installed packages for a XSP Package matching the object id
3530
 */
3531
CBaseFile *CPackages::FindXspPackage(CyString id)
3532
{
3533
	// interate through all packages
3534
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
3535
	{
3536
		CBaseFile *file = node->Data();
3537
 
3538
		// only look for spk packages
3539
		if ( file->GetType() != TYPE_XSP )
3540
			continue;
3541
 
3542
		// now compare the id, "Compare" is a non case senseative check, opposed to ==.
14 cycrow 3543
		if ( ((CXspFile *)file)->GetShipID().Compare(id.ToString()) )
1 cycrow 3544
			return file;
3545
	}
3546
 
3547
	// nothing found
3548
	return 0;
3549
}
3550
 
3551
/**
3552
 * Update the used files count
3553
 *
3554
 * counts how many packages are currently using the file
3555
 */
3556
void CPackages::UpdateUsedFiles(CLinkList<CBaseFile> *ignoreList, bool includedisabled)
3557
{
3558
	// clear amounts for all files
3559
	CListNode<C_File> *fnode = m_lFiles.Front();
3560
	while ( fnode )
3561
	{
160 cycrow 3562
		fnode->Data()->clearUsed();
1 cycrow 3563
		fnode = fnode->next();
3564
	}
3565
 
3566
	// update for all packages
3567
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node= node->next() )
3568
	{
3569
		CBaseFile *file = node->Data();
3570
		if ( (ignoreList) && (ignoreList->FindData(file)) )
3571
			continue;
3572
		if ( !includedisabled && !file->IsEnabled() )
3573
			continue;
3574
		// now mark all files
3575
		CListNode<C_File> *fnode = file->GetFileList()->Front();
3576
		while ( fnode )
3577
		{
160 cycrow 3578
			fnode->Data()->incUsed();
1 cycrow 3579
			fnode = fnode->next();
3580
		}
3581
	}
3582
}
3583
 
3584
/**
3585
 * Removes all empty directories that might have been created
3586
 */
160 cycrow 3587
void CPackages::RemoveUnusedDirectories(CyStringList& dirs, CyStringList* errors)
1 cycrow 3588
{
3589
	CDirIO Dir(m_sCurrentDir);
160 cycrow 3590
	for (SStringList* str = dirs.Head(); str; str = str->next)
1 cycrow 3591
	{
3592
		CyString dir = str->str;
3593
 
3594
		CyStringList removedDir;
160 cycrow 3595
		if (Dir.RemoveDir(dir, false, true, &removedDir) || !removedDir.Empty())
1 cycrow 3596
		{
160 cycrow 3597
			for (SStringList* node = removedDir.Head(); node; node = node->next)
1 cycrow 3598
			{
3599
				CyString displayName = node->str;
3600
				displayName = displayName.Remove(m_sCurrentDir);
3601
				this->AddLogEntry(SPKINSTALL_REMOVEDIR, displayName, errors);
3602
			}
3603
		}
3604
	}
3605
}
160 cycrow 3606
void CPackages::removeUnusedDirectories(const Utils::CStringList& dirs, Utils::CStringList* errors)
3607
{
3608
	CDirIO Dir(m_sCurrentDir);
3609
	for(auto itr = dirs.begin(); itr != dirs.end(); itr++)
3610
	{
3611
		Utils::String dir = (*itr)->str;
1 cycrow 3612
 
160 cycrow 3613
		Utils::CStringList removedDir;
3614
		if (Dir.removeDir(dir, false, true, &removedDir) || !removedDir.empty())
3615
		{
3616
			for(auto rItr = removedDir.begin(); rItr != removedDir.end(); rItr++)
3617
			{
3618
				Utils::String displayName = (*rItr)->str;
3619
				displayName = displayName.findRemove(m_sCurrentDir);
3620
				this->addLogEntry(SPKINSTALL_REMOVEDIR, displayName, errors);
3621
			}
3622
		}
3623
	}
3624
}
3625
 
1 cycrow 3626
/**
3627
 * Update signed status
3628
 *
3629
 * Updates the signed status of all packages
3630
 */
3631
void CPackages::UpdateSigned()
3632
{
3633
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
3634
	{
3635
		CBaseFile *p = node->Data();
3636
 
3637
		if ( p->GetType() != TYPE_SPK )
3638
			continue;
3639
 
3640
		((CSpkFile *)p)->UpdateSigned(false);
3641
	}
3642
}
3643
 
3644
/**
3645
 * Check validity of package file
3646
 *
3647
 * Checks if there is a newer version of the package installed
3648
 */
3649
int CPackages::CheckInstallPackage(CBaseFile *package, int check)
3650
{
3651
	if ( package->GetType() == TYPE_XSP && m_iGame == GAME_X2 )
3652
		return INSTALLCHECK_NOSHIP;
3653
 
3654
	// search for an old version
3655
	CBaseFile *oldPackage = FindPackage(package);
3656
 
3657
	// check versions are newer
3658
	if (oldPackage && (check & IC_OLDVERSION))
3659
	{
50 cycrow 3660
		if ( oldPackage->version().compareVersion(package->version()) == COMPARE_OLDER )
1 cycrow 3661
			return INSTALLCHECK_OLDVERSION;
3662
	}
3663
 
3664
	// now check for game version
3665
	if ((check & IC_WRONGGAME) || (check & IC_WRONGVERSION))
3666
	{
3667
		if ( package->AnyGameCompatability() )
3668
		{
3669
			if ( (check & IC_WRONGGAME) && (!package->CheckGameCompatability(m_iGame)) )
3670
				return INSTALLCHECK_WRONGGAME;
3671
			else if ( (check & IC_WRONGVERSION) && (!package->CheckGameVersionCompatability(m_iGame, m_sGameVersion, m_iGameVersion)) )
3672
				return INSTALLCHECK_WRONGVERSION;
3673
		}
3674
	}
3675
 
3676
	// check for modified
3677
	if (m_bVanilla && (check & IC_MODIFIED))
3678
	{
3679
		if ( !package->IsSigned() )
3680
			return INSTALLCHECK_MODIFIED;
3681
	}
3682
 
3683
	return INSTALLCHECK_OK;
3684
}
3685
 
3686
bool CPackages::CheckOtherPackage(CBaseFile *package)
3687
{
3688
	// check the need for another mod
3689
	if ( package->GetType() == TYPE_SPK )
3690
	{
3691
		CSpkFile *spk = (CSpkFile *)package;
3692
		if ( spk->IsAnotherMod() )
3693
		{
3694
			if ( !FindSpkPackage(spk->GetOtherName(), spk->GetOtherAuthor()) )
3695
			{
3696
				// check the install list
3697
				if ( m_lInstallList.empty() )
3698
					return false;
3699
 
3700
				bool found = false;
3701
				for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
3702
				{
50 cycrow 3703
					if ( spk->GetOtherName().Compare(node->Data()->name()) && spk->GetOtherAuthor().Compare(node->Data()->author()) )
1 cycrow 3704
					{
3705
						found = true;
3706
						break;
3707
					}
3708
				}
3709
 
3710
				if ( !found )
3711
					return false;
3712
			}
3713
		}
3714
	}
3715
 
3716
	return true;
3717
}
3718
 
3719
bool CPackages::CheckEnabledDependacy(CBaseFile *p)
3720
{
3721
	// check the for another mod
3722
	if ( p->GetType() == TYPE_SPK )
3723
	{
3724
		if ( ((CSpkFile *)p)->IsAnotherMod() )
3725
		{
3726
			CBaseFile *parent = this->FindSpkPackage(((CSpkFile *)p)->GetOtherName(), ((CSpkFile *)p)->GetOtherAuthor());
3727
			if ( parent )
3728
			{
3729
				if ( !parent->IsEnabled() )
3730
					return false;
3731
			}
3732
			else
3733
				return false;
3734
		}
3735
	}
3736
 
3737
	// check any dependacies
3738
	if ( p->AnyDependacies() )
3739
	{
3740
		for ( CListNode<SNeededLibrary> *dNode = p->GetNeededLibraries()->Front(); dNode; dNode = dNode->next() )
3741
		{
3742
			if ( dNode->Data()->sName.Compare("<package>") )
3743
				continue;
3744
			if ( !this->CheckInstalledDependacy(dNode->Data()->sName, dNode->Data()->sAuthor, dNode->Data()->sMinVersion, true, true) )
3745
				return false;
3746
		}
3747
	}
3748
 
3749
	return true;
3750
}
3751
 
3752
bool CPackages::CheckInstalledDependacy(CyString name, CyString author, CyString version, bool onlyEnabled, bool includePrepared)
3753
{
133 cycrow 3754
	bool ret = checkInstalledDependacy(name.ToString(), author.ToString(), version.ToString(), onlyEnabled, includePrepared);
3755
	m_lInstallList.RemoveEmpty();
3756
	return ret;
3757
}
3758
bool CPackages::checkInstalledDependacy(const Utils::String &name, const Utils::String &author, const Utils::String &version, bool onlyEnabled, bool includePrepared) const
3759
{
3760
	CBaseFile *p = this->findSpkPackage(name, author);
1 cycrow 3761
	if ( p )
3762
	{
3763
		// now check version
133 cycrow 3764
		if (version.compareVersion(p->version()) == COMPARE_OLDER)
1 cycrow 3765
			return false;
3766
 
3767
		if ( onlyEnabled && !p->IsEnabled() )
3768
			return false;
3769
 
3770
		return true;
3771
	}
3772
 
3773
	// now check the prepared list
3774
	if ( includePrepared )
3775
	{
3776
		for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
3777
		{
3778
			p = node->Data();
3779
			if ( !p )
3780
				continue;
3781
 
133 cycrow 3782
			if ( p->name().Compare(name) && p->author().Compare(author) )
1 cycrow 3783
			{
133 cycrow 3784
				if (version.compareVersion(p->version()) == COMPARE_OLDER)
1 cycrow 3785
					continue;
3786
 
3787
				if ( onlyEnabled && !p->IsEnabled() )
3788
					continue;
3789
 
3790
				return true;
3791
			}
3792
		}
3793
	}
3794
 
3795
	return false;
3796
}
3797
 
133 cycrow 3798
bool CPackages::findAllNeededDependacies(CBaseFile *p, const CLinkList<CBaseFile> &packages, CLinkList<CBaseFile> *foundPackages, bool onlyEnabled, bool includePrepared) const
1 cycrow 3799
{
133 cycrow 3800
	CLinkList<SNeededLibrary> *neededList = p->GetNeededLibraries();
3801
	if (neededList)
3802
	{
3803
		for (CListNode<SNeededLibrary> *node = neededList->Front(); node; node = node->next())
3804
		{
3805
			SNeededLibrary *nl = node->Data();
3806
			if (!checkInstalledDependacy((nl->sName.Compare("<package>")) ? p->name() : nl->sName, (nl->sAuthor.Compare("<author>")) ? p->author() : nl->sAuthor, nl->sMinVersion, (nl->sName.Compare("<package>")) ? false : onlyEnabled, (nl->sName.Compare("<package>")) ? false : includePrepared))
3807
			{
152 cycrow 3808
				bool found = false;
133 cycrow 3809
				for (auto itr = packages.Front(); itr; itr = itr->next())
3810
				{
152 cycrow 3811
					if (itr->Data()->name().Compare(nl->sName) && itr->Data()->author().Compare(nl->sAuthor) && nl->sMinVersion.compareVersion(itr->Data()->version()) >= 0)
133 cycrow 3812
					{
3813
						if (!findAllNeededDependacies(itr->Data(), packages, foundPackages, onlyEnabled, includePrepared))
3814
							return false;
3815
						if (foundPackages)
3816
						{
3817
							bool added = false;
3818
							for (auto itr2 = foundPackages->Front(); itr2; itr2 = itr2->next())
3819
							{
3820
								if (itr->Data() == itr2->Data() || (itr->Data()->name().Compare(itr2->Data()->name()) && itr->Data()->author().Compare(itr2->Data()->author())))
3821
								{
3822
									added = true;
3823
									break;
3824
								}
3825
							}
3826
							if(!added)
3827
								foundPackages->push_front(itr->Data());
3828
						}
3829
						found = true;
3830
						break;
3831
					}
3832
				}
3833
				if (!found)
3834
					return false;
3835
			}
3836
		}
3837
	}
3838
 
3839
	if (p->GetType() == TYPE_SPK)
3840
	{
3841
		CSpkFile *spk = (CSpkFile *)p;
3842
		if (spk->isAnotherMod())
3843
		{
3844
			bool found = true;
3845
			if (!this->findSpkPackage(spk->otherName(), spk->otherAuthor()))
3846
			{
3847
				if (includePrepared)
3848
				{
3849
					found = false;
3850
					for (CListNode<CBaseFile> *pNode = m_lInstallList.Front(); pNode; pNode = pNode->next())
3851
					{
3852
						CBaseFile *checkP = pNode->Data();
3853
						if (p->author().Compare(checkP->author()) && p->name().Compare(checkP->name()))
3854
						{
3855
							found = true;
3856
							break;
3857
						}
3858
					}
3859
				}
3860
				else
3861
					found = false;
3862
			}
3863
 
3864
			if (!found)
3865
			{
3866
				for (auto itr = packages.Front(); itr; itr = itr->next())
3867
				{
3868
					if (itr->Data()->name().Compare(spk->otherName()) && itr->Data()->author().Compare(spk->otherAuthor()))
3869
					{
3870
						if (!findAllNeededDependacies(itr->Data(), packages, foundPackages, onlyEnabled, includePrepared))
3871
							return false;
3872
						if(foundPackages)
3873
						{
3874
							bool added = false;
3875
							for (auto itr2 = foundPackages->Front(); itr2; itr2 = itr2->next())
3876
							{
3877
								if (itr->Data() == itr2->Data() || (itr->Data()->name().Compare(itr2->Data()->name()) && itr->Data()->author().Compare(itr2->Data()->author())))
3878
								{
3879
									added = true;
3880
									break;
3881
								}
3882
							}
3883
							if (!added)
3884
								foundPackages->push_front(itr->Data());
3885
						}
3886
						found = true;
3887
						break;
3888
					}
3889
				}
3890
 
3891
				if(!found)
3892
					return false;
3893
			}
3894
		}
3895
	}
3896
 
3897
	return true;
3898
 
3899
}
3900
int CPackages::GetMissingDependacies(CBaseFile *p, Utils::CStringList *list, bool onlyEnabled, bool includePrepared)
3901
{
1 cycrow 3902
	int count = 0;
3903
	CLinkList<SNeededLibrary> *neededList = p->GetNeededLibraries();
3904
	if ( neededList )
3905
	{
3906
		for ( CListNode<SNeededLibrary> *node = neededList->Front(); node; node = node->next() )
3907
		{
3908
			SNeededLibrary *nl = node->Data();
50 cycrow 3909
			if ( !CheckInstalledDependacy((nl->sName.Compare("<package>")) ? p->name() : nl->sName, (nl->sAuthor.Compare("<author>")) ? p->author() : nl->sAuthor, nl->sMinVersion, (nl->sName.Compare("<package>")) ? false : onlyEnabled, (nl->sName.Compare("<package>")) ? false : includePrepared) )
1 cycrow 3910
			{
3911
				if ( list )
133 cycrow 3912
					list->pushBack(((nl->sName.Compare("<package>")) ? p->name() : nl->sName) + "|" + nl->sMinVersion, (nl->sAuthor.Compare("<author>")) ? p->author() : nl->sAuthor);
1 cycrow 3913
				++count;
3914
			}
3915
		}
3916
	}
3917
 
3918
	if ( p->GetType() == TYPE_SPK )
3919
	{
3920
		CSpkFile *spk = (CSpkFile *)p;
3921
		if ( spk->IsAnotherMod() )
3922
		{
3923
			bool found = true;
3924
			if ( !this->FindSpkPackage(spk->GetOtherName(), spk->GetOtherAuthor()) )
3925
			{
3926
				if ( includePrepared )
3927
				{
3928
					found = false;
3929
					for ( CListNode<CBaseFile> *pNode = m_lInstallList.Front(); pNode; pNode = pNode->next() )
3930
					{
3931
						CBaseFile *checkP = pNode->Data();
50 cycrow 3932
						if ( p->author().Compare(checkP->author()) && p->name().Compare(checkP->name()) )
1 cycrow 3933
						{
3934
							found = true;
3935
							break;
3936
						}
3937
					}
3938
				}
3939
				else
3940
					found = false;
3941
			}
3942
 
3943
			if ( !found )
3944
			{
3945
				if ( list )
133 cycrow 3946
					list->pushBack(spk->GetOtherName(), spk->GetOtherAuthor());
1 cycrow 3947
				++count;
3948
			}
3949
		}
3950
	}
3951
 
3952
	return count;
3953
}
3954
 
3955
int CPackages::CheckPreparedInstallRequired(CLinkList<CBaseFile> *list)
3956
{
3957
	// loop through all packages
3958
	int count = 0;
3959
	for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() )
3960
	{
3961
		CBaseFile *p = node->Data();
3962
 
3963
		// no requirements found, remove from list
3964
		bool missingDep = false;
3965
		if ( !this->CheckOtherPackage(p) )
3966
			missingDep = true;
3967
		else if ( this->GetMissingDependacies(p, NULL, false, true) )
3968
			missingDep = true;
3969
 
3970
		if ( missingDep )
3971
		{
3972
			if ( list )
3973
			{
3974
				node->ChangeData(NULL);
3975
				list->push_back(p);
3976
			}
3977
			else
3978
				node->DeleteData();
3979
			++count;
3980
		}
3981
	}
3982
 
3983
	m_lInstallList.RemoveEmpty();
3984
 
3985
	return count;
3986
}
3987
 
3988
 
3989
/**
3990
 * Remove uninstall file
3991
 *
3992
 * Removes a single uninstall file
3993
 */
3994
bool CPackages::RemoveUninstallFile(C_File *file, CyStringList *errors)
3995
{
3996
	CFileIO fio(file->GetFilePointer());
52 cycrow 3997
	if ( fio.exists() )
1 cycrow 3998
	{
52 cycrow 3999
		if ( fio.remove() ) {
1 cycrow 4000
			this->AddLogEntry(SPKINSTALL_UNINSTALL_REMOVE, file->GetNameDirectory(NULL), errors);
4001
			return true;
4002
		}
4003
		else if ( errors )
4004
			this->AddLogEntry(SPKINSTALL_UNINSTALL_REMOVE_FAIL, file->GetNameDirectory(NULL), errors);
4005
	}
4006
 
4007
	return false;
4008
}
4009
 
4010
/**
4011
 * Remove uninstall scripts
4012
 *
4013
 * Removes any unused unisntall scripts
4014
 * Finds if any scripts are in the current package
4015
 */
4016
int CPackages::RemoveUninstallScripts(CyStringList *errors, CProgressInfo *progress)
4017
{
4018
	if ( m_lUninstallFiles.empty() )
4019
		return 0;
4020
 
4021
	UpdateUsedFiles();
4022
	int files = 0;
4023
 
4024
	for ( CListNode<C_File> *node = m_lUninstallFiles.Back(); node; node = node->prev() )
4025
	{
4026
		if ( progress )
4027
			progress->UpdateProgress(files, m_lUninstallFiles.size());
4028
		files++;
4029
 
4030
		C_File *file = node->Data();
4031
 
4032
		// first check if there is a matching file
4033
		bool found = false;
4034
		for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
4035
		{
4036
			C_File *checkFile = fNode->Data();
4037
			if ( checkFile->GetFileType() != FILETYPE_SCRIPT )
4038
				continue;
4039
 
158 cycrow 4040
			if ( checkFile->filename().Compare(file->filename()) )
1 cycrow 4041
			{
4042
				found = true;
4043
				break;
4044
			}
4045
		}
4046
 
4047
		// not found a matching file, we can safetly remove it
4048
		if ( !found )
4049
		{
4050
			if ( RemoveUninstallFile(file) )
4051
				node->DeleteData();
4052
		}
4053
	}
4054
 
4055
	m_lUninstallFiles.RemoveEmpty();
4056
 
4057
	return files;
4058
}
4059
 
4060
 
4061
/**
4062
 * Remove unused shared file
4063
 *
4064
 * Removes a single file
4065
 */
4066
bool CPackages::RemoveSharedFile(C_File *file, CyStringList *errors)
4067
{
4068
	CFileIO fio(file->GetFilePointer());
52 cycrow 4069
	if ( fio.exists() )
1 cycrow 4070
	{
52 cycrow 4071
		if ( fio.remove() ) {
1 cycrow 4072
			this->AddLogEntry(SPKINSTALL_SHARED, file->GetNameDirectory(NULL), errors);
4073
			delete file;
4074
			return true;
4075
		}
4076
		else if ( errors )
4077
			this->AddLogEntry(SPKINSTALL_SHARED_FAIL, file->GetNameDirectory(NULL), errors);
4078
	}
4079
 
4080
	return false;
4081
}
4082
 
4083
/**
4084
 * Remove Unused Shared Files
4085
 *
4086
 * Files that have been marked as shared will not be removed or disabled when the last package is removed
4087
 * This function will remove any that are no longer connected with packages
4088
 *
4089
 * Marked shared fiels are mainly used for library scripts that arn't always added to packages
4090
 */
4091
int CPackages::RemoveUnusedSharedFiles(CyStringList *errors, CProgressInfo *progress)
4092
{
4093
	UpdateUsedFiles();
4094
	int files = 0;
4095
	int done = 0;
4096
 
4097
	for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() )
4098
	{
4099
		if ( progress )
4100
			progress->UpdateProgress(files, m_lFiles.size());
4101
		files++;
4102
 
4103
		C_File *file = node->Data();
4104
 
4105
		// only do marked shared files
4106
		if ( !file->IsShared() )
4107
			continue;
4108
 
4109
		// only do ones that are no longer needed
160 cycrow 4110
		if ( file->getUsed() )
1 cycrow 4111
			continue;
4112
 
4113
		if ( RemoveSharedFile(file, errors) )
4114
			++done;
4115
		node->ChangeData(NULL);
4116
	}
4117
 
4118
	m_lFiles.RemoveEmpty();
4119
 
4120
	return done;
4121
}
4122
 
4123
/**
4124
 * Any Unused Shared
4125
 *
4126
 * Checks if theres any unused shared files available
4127
 *
4128
 * Any file thats marked as shared, and is no longer connected to any installed package
4129
 */
4130
bool CPackages::AnyUnusedShared()
4131
{
4132
	UpdateUsedFiles();
4133
 
4134
	for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() )
4135
	{
4136
		C_File *file = node->Data();
4137
 
4138
		// only do marked shared files
4139
		if ( !file->IsShared() )
4140
			continue;
4141
 
4142
		// only do ones that are no longer needed
160 cycrow 4143
		if ( file->getUsed() )
1 cycrow 4144
			continue;
4145
 
4146
		return true;
4147
	}
4148
 
4149
	return false;
4150
 
4151
}
4152
 
4153
void CPackages::ShuffleTextFiles(CyStringList *errors)
4154
{
4155
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
4156
	{
4157
		C_File *f = node->Data();
4158
		// only do files that are enabled
4159
		if ( f->IsDisabled() )
4160
			continue;
4161
 
4162
		if ( f->GetFileType() != FILETYPE_TEXT )
4163
			continue;
4164
 
4165
		// check if the file is an auto text file
130 cycrow 4166
		if ( !f->isAutoTextFile() )
1 cycrow 4167
			continue;
4168
 
4169
		// we need to rename it
130 cycrow 4170
		int current = findNextTextFile();
1 cycrow 4171
		if ( current < f->GetTextFileID() )
4172
		{
130 cycrow 4173
			CFileIO moveFile(f->filePointer());
1 cycrow 4174
 
130 cycrow 4175
			Utils::String newName = SPK::FormatTextName(current, m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT)) + "." + moveFile.extension();
1 cycrow 4176
			if ( moveFile.Rename(m_sCurrentDir + "/t/" + newName) )
4177
			{
130 cycrow 4178
				this->AddLogEntry(SPKINSTALL_AUTOTEXT, f->name() + "~" + newName, errors);
1 cycrow 4179
				f->SetName(newName);
4180
			}
4181
			else
130 cycrow 4182
				this->AddLogEntry(SPKINSTALL_AUTOTEXT_FAIL, f->name() + "~" + newName, errors);
1 cycrow 4183
		}
4184
	}
4185
}
4186
 
4187
/**
4188
 * Shuffle Fake Patches
4189
 *
4190
 * Rename the fake patches so they are always in sequence to be loaded into the game
4191
 *
4192
 * IE, when one is removed, the rest need to be shuffled down so theres no gaps
4193
 */
4194
void CPackages::ShuffleFakePatches(CyStringList *errors)
4195
{
4196
	int check = FindNextFakePatch();
4197
 
4198
	// lets make sure our order is correct
4199
	// find Lowest Fake Patch Installed
4200
	CLinkList<C_File> doneList;
4201
	int lowest = FindLowestFakePatchInstalled();
4202
	if ( check < lowest ) lowest = check; // gap at the beginning, lets use that
4203
 
160 cycrow 4204
	// find all packages that need to go before or after other packages
4205
	std::set<CBaseFile*> packagesBefore;
4206
	std::map<CBaseFile*, std::set<CBaseFile*>> packagesAfter;
4207
	for (CListNode<CBaseFile>* pNode = m_lPackages.Front(); pNode; pNode = pNode->next())
4208
	{
4209
		CBaseFile* p = pNode->Data();
4210
		// search for any fake patches in package
4211
		if (!p->IsEnabled()) continue;
4212
		if (!p->AnyFileType(FILETYPE_MOD)) continue;
4213
 
4214
		if (p->AnyDependacies())
4215
		{
4216
			for (SNeededLibrary* nl = p->GetNeededLibraries()->First(); nl; nl = p->GetNeededLibraries()->Next())
4217
			{
4218
				auto package = FindPackage(nl->sName, nl->sAuthor);
4219
				if (package)
4220
				{
4221
					packagesBefore.insert(package);
4222
					packagesAfter[p].insert(package);
4223
				}
4224
			}
4225
		}
4226
		CSpkFile* spk = dynamic_cast<CSpkFile*>(p);
4227
		if (spk)
4228
		{
4229
			if (spk->IsAnotherMod())
4230
			{
4231
				auto package = FindPackage(spk->otherName(), spk->otherAuthor());
4232
				if (package)
4233
				{
4234
					packagesBefore.insert(package);
4235
					packagesAfter[p].insert(package);
4236
				}
4237
			}
4238
		}
4239
 
4240
		if (!p->getFakePatchBeforeOrder().empty())
4241
		{
4242
			packagesBefore.insert(p);
4243
			auto& list = p->getFakePatchBeforeOrder();
4244
			for (auto itr = list.begin(); itr != list.end(); itr++)
4245
			{
4246
				auto package = FindPackage((*itr)->str, (*itr)->data);
4247
				if (package)				
4248
					packagesAfter[package].insert(p);
4249
			}
4250
		}
4251
		if (!p->getFakePatchAfterOrder().empty())
4252
		{
4253
			auto& list = p->getFakePatchAfterOrder();
4254
			for (auto itr = list.begin(); itr != list.end(); itr++)
4255
			{
4256
				auto package = FindPackage((*itr)->str, (*itr)->data);
4257
				if (package)
4258
				{
4259
					packagesBefore.insert(package);
4260
					packagesAfter[p].insert(package);
4261
				}
4262
			}
4263
		}
4264
	}
4265
 
4266
	auto addOrderedList = [](const std::vector<CBaseFile*>& addList, const Utils::CStringList& orderList, std::vector<CBaseFile*>& addTo, const CPackages *packages)
4267
	{
4268
		// add all the items in the ordered list first
4269
		for (auto itr = orderList.begin(); itr != orderList.end(); itr++)
4270
		{
4271
			auto p = packages->findPackage((*itr)->str, (*itr)->data);
4272
			if (p)
4273
			{
4274
				auto findItr = std::find(addList.begin(), addList.end(), p);
4275
				if (findItr != addList.end())
4276
				{
4277
					auto checkItr = std::find(addTo.begin(), addTo.end(), p);
4278
					if(checkItr == addTo.end())
4279
						addTo.push_back(p);
4280
				}
4281
			}
4282
		}
4283
 
4284
		// now add all the others
4285
		for (auto itr = addList.begin(); itr != addList.end(); itr++)
4286
		{
4287
			auto checkItr = std::find(addTo.begin(), addTo.end(), *itr);
4288
			if (checkItr == addTo.end())
4289
				addTo.push_back(*itr);
4290
		}
4291
	};
4292
 
4293
	auto removeList = [](const std::vector<CBaseFile*>& removeList, std::set<CBaseFile*>& list)
4294
	{
4295
		for (auto itr = removeList.begin(); itr != removeList.end(); itr++)
4296
		{
4297
			auto findItr = std::find(list.begin(), list.end(), *itr);
4298
			if (findItr != list.end())
4299
				list.erase(findItr);
4300
		}
4301
	};
4302
 
4303
	std::vector<CBaseFile*> order;
4304
	while (!packagesBefore.empty())
4305
	{
4306
		std::vector<CBaseFile*> packagesOrder;
4307
 
4308
		// all packages that go before, but not after should go first
4309
		for (auto itr = packagesBefore.begin(); itr != packagesBefore.end(); itr++)
4310
		{
4311
			CBaseFile* p = *itr;
4312
			auto findItr = packagesAfter.find(p);
4313
			if (findItr == packagesAfter.end())
4314
				packagesOrder.push_back(p);
4315
			else
4316
			{
4317
				// check if any packages that we go after have been added
4318
				bool notAdded = false;
4319
				for (auto checkItr = findItr->second.begin(); checkItr != findItr->second.end(); checkItr++)
4320
				{
4321
					auto findItr2 = std::find(order.begin(), order.end(), *checkItr);
4322
					if (findItr2 == order.end())
4323
					{
4324
						notAdded = true;
4325
						break;
4326
					}
4327
				}
4328
 
4329
				if (!notAdded)
4330
					packagesOrder.push_back(p);
4331
			}
4332
		}
4333
 
4334
 
4335
		// no valid packages left ? lets just add the rest
4336
		if (packagesOrder.empty())
4337
		{
4338
			for (auto itr = packagesBefore.begin(); itr != packagesBefore.end(); itr++)
4339
				packagesOrder.push_back(*itr);
4340
		}
4341
 
4342
		addOrderedList(packagesOrder, m_lFakePatchOrder, order, this);
4343
		removeList(packagesOrder, packagesBefore);
4344
	}
4345
 
4346
	// now add the remaining list ordered list
4347
	for (auto itr = m_lFakePatchOrder.begin(); itr != m_lFakePatchOrder.end(); itr++)
4348
	{
4349
		auto p = findPackage((*itr)->str, (*itr)->data);
4350
		if (p)
4351
		{
4352
			auto findItr = std::find(order.begin(), order.end(), p);
4353
			if (findItr == order.end())
4354
				order.push_back(p);
4355
		}
4356
	}
4357
 
4358
	/*
1 cycrow 4359
	// lets define the order
4360
 
4361
	// add any other packages that need to be ordered
4362
	// we need to work out the correct order
4363
	CLinkList<CBaseFile> packages;
4364
	for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )
4365
	{
4366
		CBaseFile *p = pNode->Data();
4367
		// search for any fake patches in package
4368
		if ( !p->IsEnabled() ) continue;
4369
		if ( !p->AnyFileType(FILETYPE_MOD) ) continue;
4370
 
160 cycrow 4371
		int existingPos = fakePatchOrder.findStringAndData(p->name(), p->author());
1 cycrow 4372
 
160 cycrow 4373
		if (p->AnyDependacies())
1 cycrow 4374
		{
160 cycrow 4375
			for (SNeededLibrary* nl = p->GetNeededLibraries()->First(); nl; nl = p->GetNeededLibraries()->Next())
1 cycrow 4376
			{
160 cycrow 4377
				int findPos = fakePatchOrder.findStringAndData(nl->sName, nl->sAuthor);
4378
				if (existingPos == -1)
4379
					fakePatchOrder.pushBack(nl->sName, nl->sAuthor);
4380
				else if (findPos == -1)
4381
					fakePatchOrder.insertAt(existingPos, nl->sName, nl->sAuthor);
4382
				else if (findPos > existingPos)
4383
				{
4384
					fakePatchOrder.removeAt(findPos);
4385
					fakePatchOrder.insertAt(existingPos, nl->sName, nl->sAuthor);
4386
				}
1 cycrow 4387
			}
4388
		}
4389
 
160 cycrow 4390
		CSpkFile* spk = dynamic_cast<CSpkFile*>(p);
4391
		if (spk)
4392
		{
4393
			if (spk->IsAnotherMod())
4394
			{
4395
				int findPos = fakePatchOrder.findStringAndData(spk->otherName(), spk->otherAuthor());
4396
				if (existingPos == -1)
4397
					fakePatchOrder.pushBack(spk->otherName(), spk->otherAuthor());
4398
				else if (findPos == -1)
4399
					fakePatchOrder.insertAt(existingPos, spk->otherName(), spk->otherAuthor());
4400
				else if (findPos > existingPos)
4401
				{
4402
					fakePatchOrder.removeAt(findPos);
4403
					fakePatchOrder.insertAt(existingPos, spk->otherName(), spk->otherAuthor());
4404
				}				
4405
			}
4406
		}
1 cycrow 4407
 
160 cycrow 4408
		// must have an order define
4409
		if (!p->anyFakePatchOrder())
4410
			continue;
4411
 
4412
		if (fakePatchOrder.findStringAndData(p->name(), p->author()) != -1)
4413
			continue;
4414
 
1 cycrow 4415
		bool anyFound = false;
4416
		for ( C_File *file = p->GetFirstFile(FILETYPE_MOD); file; file = p->GetNextFile(file) )
4417
		{
4418
			if ( !file->IsFakePatch() ) continue;
4419
			if ( !file->CheckFileExt("cat") ) continue;
4420
			if ( doneList.FindData(file) ) 	continue;
4421
			anyFound = true;
4422
			break;
4423
		}
4424
 
4425
		// we have some fake patches that need to be shuffled
4426
		if ( anyFound )
4427
			packages.push_back(p);
4428
	}
4429
 
4430
	// lets adjust the order (only if theres more than 1
4431
	if ( packages.size() > 1 )
4432
	{
4433
		CLinkList<CBaseFile> sortedPackages;
4434
 
4435
		// first add all the packages that dont need to be installed after
4436
		for ( CListNode<CBaseFile> *pNode = packages.Front(); pNode; pNode = pNode->next() )
4437
		{
4438
			CBaseFile *p = pNode->Data();
4439
			// we have a before and not after
160 cycrow 4440
			if ( !p->getFakePatchBeforeOrder().empty() && p->getFakePatchAfterOrder().empty() )
1 cycrow 4441
			{
4442
				// if we have to install before, check if any on the list
4443
				int earliestPos = -1;
4444
				bool notAdded = true;
160 cycrow 4445
				auto& list = p->getFakePatchBeforeOrder();
4446
				for(auto itr = list.begin(); itr != list.end(); itr++)
1 cycrow 4447
				{
4448
					int pos = 0;
4449
					for ( CListNode<CBaseFile> *sNode = sortedPackages.Front(); sNode; sNode = sNode->next() )
4450
					{
160 cycrow 4451
						if ((*itr)->str.Compare(sNode->Data()->name()) && (*itr)->data.Compare(sNode->Data()->author()) )
1 cycrow 4452
						{
4453
							if ( earliestPos == -1 || pos < earliestPos )
4454
								earliestPos = pos;
4455
							break;
4456
						}
4457
						++pos;
4458
					}					
4459
				}
4460
 
4461
				if ( earliestPos > -1 )
4462
					sortedPackages.insert(earliestPos, p);
4463
				// otherwise just add it at the back
4464
				else
4465
					sortedPackages.push_back(p);
4466
 
4467
				// remove from the list
4468
				pNode->ChangeData(NULL);
4469
			}
4470
		}
4471
 
4472
		// now do the packages that have both before and after
4473
		packages.RemoveEmpty();
4474
		for ( CListNode<CBaseFile> *pNode = packages.Front(); pNode; pNode = pNode->next() )
4475
		{
4476
			CBaseFile *p = pNode->Data();
160 cycrow 4477
			if ( !p->getFakePatchBeforeOrder().empty() && !p->getFakePatchAfterOrder().empty() )
1 cycrow 4478
			{
4479
			}
4480
		}
4481
 
4482
		// add them onto the list
4483
		for ( CListNode<CBaseFile> *pNode = sortedPackages.Front(); pNode; pNode = pNode->next() )
160 cycrow 4484
			fakePatchOrder.pushBack(pNode->Data()->name(), pNode->Data()->author());
1 cycrow 4485
	}
4486
 
4487
	// now add to do list
4488
	for ( CListNode<CBaseFile> *pNode = packages.Front(); pNode; pNode = pNode->next() )
160 cycrow 4489
		fakePatchOrder.pushBack(pNode->Data()->name(), pNode->Data()->author());
4490
		*/
4491
	for(auto itr = order.begin(); itr != order.end(); itr++)
1 cycrow 4492
	{
160 cycrow 4493
		CBaseFile *package = *itr;
1 cycrow 4494
		if ( package )
4495
		{
4496
			// might have more than 1 fake patch for the file, so we'll need the lowest
4497
			while ( true )
4498
			{
4499
				C_File *lowestFile = NULL;
4500
				for ( C_File *file = package->GetFirstFile(FILETYPE_MOD); file; file = package->GetNextFile(file) )
4501
				{
4502
					if ( !file->IsFakePatch() ) continue;
4503
					if ( !file->CheckFileExt("cat") ) continue; // only do the cat file, we can shuffle the dat file to match later
4504
					if ( doneList.FindData(file) ) continue; // already done?
4505
 
4506
					if ( !lowestFile )
4507
						lowestFile = file;
4508
					else
4509
					{
4510
						if ( file->GetBaseName().ToInt() < lowestFile->GetBaseName().ToInt() )
4511
							lowestFile = file;
4512
					}
4513
				}
4514
 
4515
				if ( !lowestFile ) // no more files ?
4516
					break;
4517
 
4518
				// check its filename, it might already be in the correct place
158 cycrow 4519
				if ( lowestFile->baseName().toInt() != lowest )
1 cycrow 4520
				{
4521
					// if the file already exists, we need to move it elsewhere
158 cycrow 4522
					Utils::String nextName = Utils::String::PadNumber(lowest, 2);
4523
					if ( CFileIO::Exists(m_sCurrentDir + "/" + nextName + ".cat") )
1 cycrow 4524
					{
4525
						// find the file in our internal file list
4526
						C_File *moveFile = FindFile(FILETYPE_MOD, nextName + ".cat");
4527
						if ( !moveFile ) // must not have it in our list ? lets move to the next
4528
						{
4529
							lowest++;
4530
							continue;
4531
						}
4532
 
4533
						// now we can move the the cat/dat file elsewhere, lets shuffle it to the highest free number
4534
						ShufflePatchTo(moveFile, FindLastFakePatch(), errors);
4535
					}
4536
 
4537
					// space should be free, now lets shuffle it
4538
					ShufflePatchTo(lowestFile, lowest, errors);
4539
				}
4540
 
4541
				doneList.push_back(lowestFile); // we've done this file now
4542
				lowest++; // move up the lowest ready for the next patch
4543
			}
4544
		}
4545
	}
4546
 
4547
	// now lets shuffle the rest
4548
	// now find any packages with greater fake patchs and fill the gaps
4549
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
4550
	{
4551
		C_File *f = node->Data();
4552
		// already done?
4553
		if ( doneList.FindData(f) ) 
4554
			continue;
4555
 
4556
		// only do files that are enabled
4557
		if ( f->IsDisabled() )
4558
			continue;
4559
 
4560
		// check if the file is a fake patch
4561
		if ( !f->IsFakePatch() )
4562
			continue;
4563
 
4564
		// we only want cat and dat files, all fake patchs should be, but incase theres an error in the package somewhere we can check
4565
		if ( !f->CheckFileExt("cat") )
4566
			continue;
4567
 
4568
		// now lets check if its greater than our gap
4569
		int check = FindNextFakePatch();
158 cycrow 4570
		int patchNum = f->filename().token(".", 1).toInt();
1 cycrow 4571
		if ( patchNum <= check )
4572
			continue;
4573
 
4574
		ShufflePatchTo(f, check, errors);
4575
	}
4576
}
4577
 
4578
void CPackages::ShufflePatchTo(C_File *file, int to, CyStringList *errors)
4579
{
4580
	// it is, we need to shift this to fill the gap
158 cycrow 4581
	Utils::String newName = Utils::String::PadNumber(to, 2) + "." + file->fileExt();
1 cycrow 4582
 
4583
	// now rename the file
158 cycrow 4584
	CFileIO moveFile(file->filePointer());
1 cycrow 4585
	if ( moveFile.Rename(m_sCurrentDir + "/" + newName) )
4586
	{
4587
		// display moveing
158 cycrow 4588
		this->AddLogEntry(SPKINSTALL_FAKEPATCH, file->name() + "~" + newName, errors);
1 cycrow 4589
 
4590
		// now find the matching pairing if it exists
4591
		for ( CListNode<C_File> *node2 = m_lFiles.Front(); node2; node2 = node2->next() )
4592
		{
4593
			C_File *f2 = node2->Data();
4594
 
4595
			if ( f2->IsDisabled() || !f2->IsFakePatch() || f2->CheckFileExt(file->GetFileExt()) )
4596
				continue;
4597
 
4598
			// needs to be the same file
4599
			if ( f2->GetBaseName() != file->GetBaseName() )
4600
				continue;
4601
 
158 cycrow 4602
			Utils::String newName2 = Utils::String::PadNumber(to, 2) + "." + f2->fileExt();
4603
			CFileIO moveFile(f2->filePointer());
1 cycrow 4604
			if ( moveFile.Rename(m_sCurrentDir + "/" + newName2) )
4605
			{
158 cycrow 4606
				this->AddLogEntry(SPKINSTALL_FAKEPATCH, f2->name() + "~" + newName2, errors);
4607
				f2->setName(newName2);
1 cycrow 4608
			}
4609
			else
158 cycrow 4610
				this->AddLogEntry(SPKINSTALL_FAKEPATCH_FAIL, f2->name() + "~" + newName2, errors);
1 cycrow 4611
		}
4612
 
4613
		// finally make sure the internal name matches the new one
158 cycrow 4614
		file->setName(newName);
1 cycrow 4615
	}
4616
	else
158 cycrow 4617
		this->AddLogEntry(SPKINSTALL_FAKEPATCH_FAIL, file->name() + "~" + newName, errors);
1 cycrow 4618
}
4619
 
4620
int CPackages::FindLowestFakePatchInstalled()
4621
{
4622
	int lowest = 99;
4623
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
4624
	{
4625
		CBaseFile *p = node->Data();
4626
		if ( !p->IsEnabled() ) continue;
4627
		if ( !p->AnyFileType(FILETYPE_MOD) ) continue;
4628
 
4629
		// now get all fake patches
4630
		for ( C_File *file = p->GetFirstFile(FILETYPE_MOD); file; file = p->GetNextFile(file) )
4631
		{
4632
			if ( !file->IsFakePatch() ) continue;
4633
			if ( file->CheckFileExt("dat") ) continue;
4634
			int check = file->GetBaseName().ToInt();
4635
			if ( check < lowest )
4636
				lowest = check;
4637
		}
4638
	}
4639
 
4640
	return lowest;
4641
}
4642
 
4643
int CPackages::FindLastFakePatch(int start, CyString dir)
4644
{
4645
	CDirIO Dir((dir.Empty()) ? m_sCurrentDir : dir);
4646
 
4647
	int check = start;
4648
	while ( check > 0 )
4649
	{
121 cycrow 4650
		Utils::String checkStr = Utils::String::PadNumber(check, 2);
1 cycrow 4651
 
4652
		// check if a cat file exists
121 cycrow 4653
		if ( !Dir.exists(checkStr + ".cat") )
1 cycrow 4654
		{
4655
			// it doen't, check if theres a dat file (incase of package error)
121 cycrow 4656
			if ( !Dir.exists(checkStr + ".dat") )
1 cycrow 4657
				break;
4658
		}
4659
		--check;
4660
	}
4661
 
4662
	return check;
4663
}
4664
 
4665
/**
4666
 * Find next fake patch
4667
 *
4668
 * Searching for the next gap in patches, starting with 01.cat to 99.cat
4669
 */
4670
int CPackages::FindNextFakePatch(int start, CyString dir)
4671
{
4672
	CDirIO Dir((dir.Empty()) ? m_sCurrentDir : dir);
4673
 
4674
	int check = start;
4675
	while ( check < 99 )
4676
	{
4677
		++check;
121 cycrow 4678
		Utils::String checkStr = Utils::String::PadNumber(check, 2);
1 cycrow 4679
 
4680
		// check if a cat file exists
121 cycrow 4681
		if ( !Dir.exists(checkStr + ".cat") )
1 cycrow 4682
		{
4683
			// it doen't, check if theres a dat file (incase of package error)
121 cycrow 4684
			if ( !Dir.exists(checkStr + ".dat") )
1 cycrow 4685
				break;
4686
		}
4687
	}
4688
 
4689
	return check;
4690
}
4691
 
4692
/**
4693
 * Find next text file
4694
 *
130 cycrow 4695
 * Searching for the next gap in automatic text files, start with 0004-LXXX or XX0004
1 cycrow 4696
 */
130 cycrow 4697
unsigned int CPackages::findNextTextFile(unsigned int start) const
1 cycrow 4698
{
130 cycrow 4699
	return findNextTextFile(Utils::String::Null(), start);
4700
}
4701
unsigned int CPackages::findNextTextFile(const Utils::String &dir, unsigned int start) const
4702
{
1 cycrow 4703
	int check = start;
4704
	if ( check < 2 ) check = 2;
4705
	while ( check < 9999 )
4706
	{
4707
		++check;
130 cycrow 4708
		Utils::String newFilename = SPK::FormatTextName(check, m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT));
1 cycrow 4709
 
43 cycrow 4710
		// check the vfs
4711
		if ( m_pGameVFS.isFileAvailable("t/" + newFilename + ".pck") ) continue;
4712
		if ( m_pGameVFS.isFileAvailable("t/" + newFilename + ".xml") ) continue;
4713
 
4714
		break;
1 cycrow 4715
	}
4716
 
4717
	return check;
4718
}
4719
 
4720
int CPackages::FindLastTextFile(int start, CyString dir)
4721
{
4722
	CDirIO Dir((dir.Empty()) ? m_sCurrentDir : dir);
4723
	Dir.cd("t");
4724
 
4725
	int check = start;
4726
	while ( check < 9999 )
4727
	{
4728
		++check;
130 cycrow 4729
		Utils::String newFilename = SPK::FormatTextName(check, m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT));
1 cycrow 4730
 
4731
		// check if a packed file exists
125 cycrow 4732
		if ( !Dir.exists(newFilename + ".pck") )
1 cycrow 4733
		{
4734
			// it doen't, check if theres an unpacked file
125 cycrow 4735
			if ( !Dir.exists(newFilename + ".xml") )
1 cycrow 4736
				break;
4737
		}
4738
	}
4739
 
4740
	return check;
4741
}
4742
 
4743
/**
4744
 * Read game language
4745
 *
4746
 * Reads the lang.dat file from the game directory for the language id
4747
 */
4748
void CPackages::ReadGameLanguage(bool force)
4749
{
4750
	// check if lauguage is already set
4751
	if ( !force && m_iLanguage )
4752
		return;
4753
 
4754
	CDirIO Dir(m_sCurrentDir);
4755
 
4756
	// check for lang.dat file
121 cycrow 4757
	if ( Dir.exists("lang.dat") )
1 cycrow 4758
	{
160 cycrow 4759
		CFileIO File(Dir.file("lang.dat"));
1 cycrow 4760
 
4761
		size_t size;
4762
		char *data = File.ReadToData(&size);
4763
 
4764
		if ( data )
4765
		{
160 cycrow 4766
			Utils::String str(data);
4767
			m_iLanguage = str.token("\n", 1).token(" ", 1).toInt();
1 cycrow 4768
		}
4769
	}
4770
}
4771
 
4772
/**
4773
 * Create Language Text File
4774
 *
4775
 * Creates text files for all packages into the correct language
4776
 */
160 cycrow 4777
void CPackages::CreateLanguageTextFiles(Utils::CStringList *errors)
1 cycrow 4778
{
4779
	// no need to create them if theres no language to use
4780
	if ( !m_iLanguage )
4781
		return;
4782
 
4783
	// find all text files
160 cycrow 4784
	Utils::CStringList ids;
1 cycrow 4785
 
4786
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
4787
	{
4788
		C_File *f = node->Data();
4789
		// only do text fiels
4790
		if ( f->GetFileType() != FILETYPE_TEXT )
4791
			continue;
4792
 
160 cycrow 4793
		Utils::String id, lang;
1 cycrow 4794
		if ( m_iGameFlags & EXEFLAG_TCTEXT )
4795
		{
160 cycrow 4796
			id = f->baseName().token("-", 1);
4797
			lang = f->baseName().token("-", 2);
4798
			if ( lang.empty() )
1 cycrow 4799
				lang = "NULL";
4800
			else
160 cycrow 4801
				lang = lang.erase(0, 1);  // remove the "L"
1 cycrow 4802
		}
4803
		else
4804
		{
160 cycrow 4805
			lang = Utils::String::PadNumber(f->baseName().left((int)f->baseName().length() - 4), 3);
4806
			id = f->baseName().mid(((int)f->baseName().length() - 4) + 1, 4);
1 cycrow 4807
		}
4808
 
4809
 
4810
		// not added, add a new one
160 cycrow 4811
		if (!ids.contains(id))
4812
			ids.pushBack(id, lang);
1 cycrow 4813
		else
4814
		{
160 cycrow 4815
			Utils::String data = ids.findString(id);
4816
			if (data.empty())
4817
				data = lang;
1 cycrow 4818
			else
4819
			{
160 cycrow 4820
				data += ":";
4821
				data += lang;
1 cycrow 4822
			}
160 cycrow 4823
			ids.changeData(id, data);
1 cycrow 4824
		}
4825
	}
4826
 
4827
	// we should now have a list of all text files, we need to remove those that have a matching language
160 cycrow 4828
	for(auto itr = ids.begin(); itr != ids.end(); itr++)
1 cycrow 4829
	{
4830
		int size = 0;
160 cycrow 4831
		Utils::String *data = (*itr)->data.tokenise(":", &size);
1 cycrow 4832
 
4833
		// huh ? we shouldn't have this
4834
		if ( !size )
4835
			continue;
4836
 
4837
		// lets search for a matching id
4838
		int useId = 0;
4839
		bool found = false;
4840
		for ( int i = 0; i < size; i++ )
4841
		{
4842
			if ( data[i] == "NULL" )
4843
				useId = -1;
4844
			else
4845
			{
160 cycrow 4846
				int num = data[i].toInt();
1 cycrow 4847
				if ( num == m_iLanguage )
4848
				{
4849
					found = true;
4850
					useId = m_iLanguage;
4851
					break;
4852
				}
4853
				// prioities the text file to use, no language first, then 44, then 49, otherwise, we pick the first available
4854
				else if ( num == 44 && useId != -1)
4855
					useId = 44;
4856
				// if we have a german language, and its not yet found english or null
4857
				else if ( num == 49 && useId != 44 && useId != -1 )
4858
					useId = 49;
4859
				// if we have not found a valid language yet, we will use this one
4860
				else if ( !useId )
4861
					useId = num;
4862
			}
4863
		}
4864
 
160 cycrow 4865
		if (found)
4866
		{
4867
			CLEANSPLIT(data, size);
1 cycrow 4868
			continue;
160 cycrow 4869
		}
1 cycrow 4870
 
4871
		if ( !useId )
160 cycrow 4872
			useId = data[0].toInt();
1 cycrow 4873
		if ( !useId )
4874
			useId = -1;
4875
 
4876
		CLEANSPLIT(data, size);
160 cycrow 4877
		RenameTextFile((*itr)->str, useId, errors);
1 cycrow 4878
	}
4879
}
4880
 
4881
/**
4882
 * Rename a text file
4883
 *
160 cycrow 4884
 * Creates a new text file for the selected langage by copying an existing one
1 cycrow 4885
 */
160 cycrow 4886
bool CPackages::RenameTextFile(const Utils::String &textid, int languageid, Utils::CStringList *errors)
1 cycrow 4887
{
4888
	// lets check if the file already exists
160 cycrow 4889
	Utils::String newFilename = SPK::FormatTextName(textid.toInt(), m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT));
1 cycrow 4890
	C_File *addFile = FindFile(FILETYPE_TEXT, newFilename + ".xml");
4891
	if ( !addFile )
4892
		addFile = FindFile(FILETYPE_TEXT, newFilename + ".pck");
4893
 
4894
	// we have found the file, lets just add it to our scripts
4895
	if ( addFile )
4896
	{
4897
		AddTextFileToScripts(addFile, textid);
4898
		return true;
4899
	}
4900
 
4901
	// first we need to find our text file
130 cycrow 4902
	Utils::String filename;
1 cycrow 4903
	if ( languageid != -1 )
160 cycrow 4904
		filename = SPK::FormatTextName(textid.toInt(), languageid, (m_iGameFlags & EXEFLAG_TCTEXT));
1 cycrow 4905
	else
160 cycrow 4906
		filename = textid;
1 cycrow 4907
 
4908
	C_File *textFile = FindFile(FILETYPE_TEXT, filename + ".xml");
4909
	if ( !textFile )
4910
	{
4911
		textFile = FindFile(FILETYPE_TEXT, filename + ".pck");
4912
		if ( !textFile )
4913
			return false;
4914
	}
4915
 
4916
	// now lets create out new text file
160 cycrow 4917
	CFileIO readFile(textFile->filePointer());
4918
	std::vector<Utils::String> *lines = readFile.readLines();
1 cycrow 4919
 
4920
	// find the language id in the lines
160 cycrow 4921
	std::vector<Utils::String> frontLines;
4922
	for(std::vector<Utils::String>::iterator it = lines->begin(); it != lines->end(); ++it)
1 cycrow 4923
	{
160 cycrow 4924
		Utils::String line = *it;
4925
		int pos = line.findPos("<language id");
1 cycrow 4926
		if ( pos != -1)
4927
		{
160 cycrow 4928
			Utils::String newLine = "<language id=\"";
4929
			newLine += Utils::String::Number(m_iLanguage);
1 cycrow 4930
			newLine += "\">";
160 cycrow 4931
			newLine += line.tokens(">", 2);
1 cycrow 4932
 
4933
			frontLines.insert(frontLines.begin(), newLine);
4934
 
4935
			lines->erase(lines->begin(), ++it);
4936
			break;
4937
		}
4938
		frontLines.insert(frontLines.begin(), line);
4939
	}
4940
 
160 cycrow 4941
	for(std::vector<Utils::String>::iterator it = frontLines.begin(); it != frontLines.end(); ++it)
1 cycrow 4942
		lines->insert(lines->begin(), *it);
4943
 
130 cycrow 4944
	addFile = new C_File(newFilename + ".xml");
160 cycrow 4945
	addFile->setFileType(FILETYPE_TEXT);
1 cycrow 4946
 
158 cycrow 4947
	CFileIO writeFile(m_sCurrentDir + "/" + addFile->getNameDirectory(NULL));
160 cycrow 4948
	if ( writeFile.writeFile(lines) )
1 cycrow 4949
	{
160 cycrow 4950
		this->addLogEntry(SPKINSTALL_WRITEFILE, addFile->getNameDirectory(NULL), errors);
1 cycrow 4951
 
158 cycrow 4952
		addFile->SetFilename(m_sCurrentDir + "/" + addFile->getNameDirectory(NULL));
1 cycrow 4953
		// now we have the file wrriten, we need to add it to all scripts that need it
4954
		// first we add it to the global list
4955
		m_lFiles.push_back(addFile);
4956
 
4957
		// now add it to the scripts
4958
		AddTextFileToScripts(addFile, textid);
4959
	}
4960
	else
4961
	{
160 cycrow 4962
		this->addLogEntry(SPKINSTALL_WRITEFILE_FAIL, addFile->getNameDirectory(NULL), errors);
1 cycrow 4963
		if ( lines )
4964
			delete lines;
4965
		return false;
4966
	}
4967
 
4968
	if ( lines )
4969
		delete lines;
4970
 
4971
 
4972
	return true;
4973
}
4974
 
4975
/**
4976
 * Add file to scripts
4977
 *
4978
 * Adds a file to all scripts that need it
4979
 */
4980
void CPackages::AddTextFileToScripts(C_File *file, CyString textid)
4981
{
4982
	// now we need to find all scripts that have a matching file and add this to the list
4983
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
4984
	{
4985
		CBaseFile *package = node->Data();
4986
 
4987
		// first make sure it doesn't already exist
4988
		if ( package->GetFileList()->FindData(file) )
4989
			continue;
4990
 
4991
		bool found = false;
4992
		for ( CListNode<C_File> *fNode = package->GetFileList()->Front(); fNode; fNode = fNode->next() )
4993
		{
4994
			C_File *tFile = fNode->Data();
4995
			if ( tFile->GetFileType() != FILETYPE_TEXT )
4996
				continue;
4997
 
4998
			CyString id = tFile->GetBaseName().GetToken("-", 1, 1);
4999
			if ( id == textid )
5000
			{
5001
				found = true;
5002
				break;
5003
			}
5004
		}
5005
 
5006
		if ( found )
5007
			package->GetFileList()->push_back(file);
5008
	}
5009
}
5010
 
5011
bool CPackages::RemoveFile(C_File *file, CyStringList *errors)
5012
{
5013
	if ( !file )
5014
		return true;
5015
 
158 cycrow 5016
	Utils::String remFileStr = file->filePointer();
5017
	remFileStr.findReplace(m_sCurrentDir, "");
1 cycrow 5018
 
158 cycrow 5019
	if ( file->filePointer().contains("::")) {
1 cycrow 5020
		CFileIO CatFile(file->GetFilePointer().GetToken("::", 1, 1));
52 cycrow 5021
		if ( CatFile.exists() ) {
1 cycrow 5022
			CCatFile cat;
125 cycrow 5023
			if ( cat.open(CatFile.fullFilename(), this->getAddonDir(), CATREAD_DAT, false) == CATERR_NONE ) {
1 cycrow 5024
				CyString fileName = file->GetFilePointer().GetToken("::", 2, 2);
5025
				if ( cat.FindData(fileName) ) {
124 cycrow 5026
					if ( cat.removeFile(fileName.ToString()) ) {
1 cycrow 5027
						this->AddLogEntry(SPKINSTALL_DELETEFILE, remFileStr, errors);
5028
					}
5029
					else {
5030
						this->AddLogEntry(SPKINSTALL_DELETEFILE_FAIL, remFileStr, errors);
5031
						return false;
5032
					}
5033
				}
5034
			}
5035
		}
5036
	}
5037
	else {
158 cycrow 5038
		CFileIO f(file->filePointer());
52 cycrow 5039
		if ( f.exists() )
1 cycrow 5040
		{
52 cycrow 5041
			if ( f.remove() ) this->AddLogEntry(SPKINSTALL_DELETEFILE, remFileStr, errors);
1 cycrow 5042
			else if ( errors )
5043
			{
5044
				this->AddLogEntry(SPKINSTALL_DELETEFILE_FAIL, remFileStr, errors);
5045
				return false;
5046
			}
5047
			else
5048
				return false;
5049
		}
5050
	}
5051
 
5052
	return true;
5053
}
5054
 
5055
int CPackages::RemoveAllPackages(CyStringList *errors, CProgressInfo *progress)
5056
{
5057
	int files = 0;
5058
 
5059
	// remove all files
93 cycrow 5060
	int max = m_lFiles.size() + _pOriginalFiles->count() + m_lUninstallFiles.size();
1 cycrow 5061
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
5062
	{
5063
		// update the progress
5064
		if ( progress )
5065
			progress->UpdateProgress(files, max);
5066
		++files;
5067
 
5068
		RemoveFile(node->Data());
5069
		delete node->Data();
5070
	}
5071
	m_lFiles.clear();
5072
 
5073
	// restore any original files that are backed up
93 cycrow 5074
	//TODO: find a better way to do the progress
5075
	files = _pOriginalFiles->restoreAll(progress, files, max);
1 cycrow 5076
 
5077
	// remove any uninstall files that remain
5078
	for ( CListNode<C_File> *uNode = m_lUninstallFiles.Front(); uNode; uNode = uNode->next() )
5079
	{
5080
		// update the progress
5081
		if ( progress )
5082
			progress->UpdateProgress(files, max);
5083
		++files;
5084
 
5085
		RemoveFile(uNode->Data());
5086
		delete uNode->Data();
5087
	}
5088
	m_lUninstallFiles.clear();
5089
 
5090
	// delete all packages
5091
	for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )
5092
	{
5093
		// clear file list as we have removed them already
5094
		pNode->Data()->GetFileList()->clear();
5095
		// delete the memory for the package
5096
		delete pNode->Data();
5097
	}
5098
	m_lPackages.clear();
5099
 
5100
	return files;
5101
}
5102
 
5103
/**
5104
 * Get Install Before Text
5105
 *
5106
 * Returns the install before text for the package in the correct language
5107
 */
5108
CyString CPackages::GetInstallBeforeText(CBaseFile *package)
5109
{
46 cycrow 5110
	return package->installText(m_iLanguage, true);
1 cycrow 5111
}
5112
CyString CPackages::GetInstallAfterText(CBaseFile *package)
5113
{
46 cycrow 5114
	return package->installText(m_iLanguage, false);
1 cycrow 5115
}
5116
CyString CPackages::GetUninstallBeforeText(CBaseFile *package)
5117
{
46 cycrow 5118
	return package->uninstallText(m_iLanguage, true);
1 cycrow 5119
}
5120
CyString CPackages::GetUninstallAfterText(CBaseFile *package)
5121
{
46 cycrow 5122
	return package->uninstallText(m_iLanguage, false);
1 cycrow 5123
}
5124
 
5125
int CPackages::GetChildPackages(CBaseFile *package, CLinkList<CBaseFile> *children, bool recursive)
5126
{
5127
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5128
	{
5129
		CBaseFile *p = node->Data();
5130
		if ( p->GetParent() == package )
5131
		{
5132
			children->push_back(p);
5133
 
5134
			if ( recursive )
5135
				this->GetChildPackages(p, children, recursive);
5136
		}
5137
	}
5138
 
5139
	return children->size();
5140
}
5141
 
5142
void CPackages::AssignPackageNumbers()
5143
{
5144
	int num = 0;
5145
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5146
		node->Data()->SetNum(num++);
5147
}
5148
 
127 cycrow 5149
Utils::String CPackages::findDataDir(const Utils::String &dir, const Utils::String &file)
1 cycrow 5150
{
127 cycrow 5151
	CDirIO Dir(dir);
125 cycrow 5152
 
1 cycrow 5153
	// data files could be in 4 places depending on what program is used, check for all of these
127 cycrow 5154
	if (Dir.exists(file))
125 cycrow 5155
		return Dir.file(file);
127 cycrow 5156
	else if (Dir.exists("Data/" + file))
125 cycrow 5157
		return Dir.file("Data/" + file);
127 cycrow 5158
	else if (Dir.exists("../" + file))
125 cycrow 5159
		return Dir.file("../" + file);
127 cycrow 5160
	else if (Dir.exists("../Data/" + file))
125 cycrow 5161
		return Dir.file("../Data/" + file);
1 cycrow 5162
 
127 cycrow 5163
	return Utils::String::Null();
1 cycrow 5164
}
5165
 
127 cycrow 5166
void CPackages::startup(const Utils::String &dir, const Utils::String &tempDir, const Utils::String &myDoc)
1 cycrow 5167
{
127 cycrow 5168
	this->setTempDirectory(tempDir);
5169
	this->setMyDocuments(myDoc);
1 cycrow 5170
 
5171
	// need to read the game exe versions
5172
	m_gameExe.Reset();
5173
 
127 cycrow 5174
	Utils::String exeFile = this->findDataDir(dir, "exe");
1 cycrow 5175
 
5176
	// if file exists, read it, otherwise, just add
127 cycrow 5177
	if (!exeFile.empty() && CFileIO::Exists(exeFile))
5178
		m_gameExe.ReadFile(exeFile);
1 cycrow 5179
	else
5180
	{
56 cycrow 5181
		m_gameExe.ParseExe("x2.exe|0:5:NOSAVESUBDIR:HKCU/Software/EgoSoftware/X2/ModName:X2 The Threat:!GAMEDIR!:2:1604608!2150400:1.4 Artifical Life:1974272:1.5 Uplink");
5182
		m_gameExe.ParseExe("x3.exe|30:5:0:HKCU/Software/Egosoft/X3/ModName:X3 Reunion:Egosoft/X3:2:2347008:2.0 Bala Gi:2367488!2375680:2.5 Uplink");
5183
		m_gameExe.ParseExe("x3tc.exe|35:5:NO_XOR|TC_TEXT|MYDOCLOG:HKCU/Software/Egosoft/X3TC/ModName:X3 Terran Conflict:Egosoft/X3TC:3:1933464!1933520:2.0 Aldrin Expansion:-1:2.5 A New Home (Superbox):-1:3.0 Balance of Power");
76 cycrow 5184
		m_gameExe.ParseExe("x3ap.exe|38:2:NO_XOR|TC_TEXT|MYDOCLOG|ADDON:HKCU/Software/Egosoft/X3AP/ModName:X3 Albion Prelude:Egosoft/X3AP:addon!x3tc.exe:3:-1:2.0 The War Continues:-1:2.5 Operation Loose Ends:-1:3.0 Shady Business");
134 cycrow 5185
		m_gameExe.ParseExe("x3fl.exe|39:3:NO_XOR|TC_TEXT|MYDOCLOG|ADDON:HKCU/Software/Egosoft/X3FL/ModName:X3 Farnham's Legacy:Egosoft/X3FL:addon2!x3tc.exe:0");
1 cycrow 5186
	}
5187
}
127 cycrow 5188
void CPackages::startup(const Utils::String &dir, const Utils::String &tempDir, const Utils::String &myDoc, const Utils::String &mod)
5189
{
5190
	startup(dir, tempDir, myDoc);
5191
	m_sSetMod = mod;
5192
}
158 cycrow 5193
/*
127 cycrow 5194
void CPackages::Startup(CyString dir, CyString tempDir, CyString myDoc, CyString mod)
5195
{
5196
	startup(dir.ToString(), tempDir.ToString(), myDoc.ToString(), mod.ToString());
158 cycrow 5197
}*/
1 cycrow 5198
 
121 cycrow 5199
int CPackages::GetGameLanguage() const
1 cycrow 5200
{
158 cycrow 5201
	return this->GetGameLanguage(m_sCurrentDir);
121 cycrow 5202
}
5203
int CPackages::GetGameLanguage(const Utils::String &sDir) const
5204
{
5205
	Utils::String dir = sDir;
5206
	if (dir.empty())
158 cycrow 5207
		dir = m_sCurrentDir;
121 cycrow 5208
	else
5209
		dir = this->getProperDir(dir);
1 cycrow 5210
 
5211
	CDirIO Dir(dir);
5212
 
5213
	// check for lang.dat file
121 cycrow 5214
	if ( Dir.exists("lang.dat") )
1 cycrow 5215
	{
121 cycrow 5216
		CFileIO File(Dir.file("lang.dat"));
1 cycrow 5217
 
5218
		size_t size;
5219
		char *data = File.ReadToData(&size);
5220
 
5221
		if ( data )
5222
		{
121 cycrow 5223
			Utils::String str(data);
5224
			return str.token("\n", 1).token(" ", 1).toLong();
1 cycrow 5225
		}
5226
	}
5227
 
5228
	return 0;
5229
}
121 cycrow 5230
Utils::String CPackages::GetGameRunExe(const Utils::String &dir)
1 cycrow 5231
{
121 cycrow 5232
	return m_gameExe.GetGameRunExe(dir);
1 cycrow 5233
}
121 cycrow 5234
Utils::String CPackages::GetGameRunExe()
5235
{
158 cycrow 5236
	return m_gameExe.GetGameRunExe(m_sCurrentDir);
121 cycrow 5237
}
1 cycrow 5238
 
5239
CyString CPackages::GetGameNameFromType(int game)
5240
{
5241
	return m_gameExe.GetGameNameFromType(game - 1);
5242
}
121 cycrow 5243
Utils::String CPackages::getGameName() const
5244
{
158 cycrow 5245
	return getGameName(m_sCurrentDir);
121 cycrow 5246
}
5247
 
5248
Utils::String CPackages::getGameName(const Utils::String &dir) const
5249
{
158 cycrow 5250
	return m_gameExe.GetGameName(dir.empty() ? m_sCurrentDir : dir);
121 cycrow 5251
}
5252
 
1 cycrow 5253
CyString CPackages::GetGameName(CyString dir)
5254
{
158 cycrow 5255
	return m_gameExe.GetGameName((dir.Empty()) ? m_sCurrentDir : dir.ToString());
1 cycrow 5256
}
5257
CyString CPackages::GetProperDir(CyString dir)
5258
{
158 cycrow 5259
	return m_gameExe.GetProperDir((dir.Empty()) ? m_sCurrentDir : dir.ToString());
1 cycrow 5260
}
5261
CyString CPackages::GetAddonDir(CyString dir)
5262
{
158 cycrow 5263
	return m_gameExe.GetAddonDir((dir.Empty()) ? m_sCurrentDir : dir.ToString());
1 cycrow 5264
}
121 cycrow 5265
Utils::String CPackages::getProperDir() const
1 cycrow 5266
{
158 cycrow 5267
	return getProperDir(m_sCurrentDir);
1 cycrow 5268
}
121 cycrow 5269
Utils::String CPackages::getProperDir(const Utils::String &dir) const
5270
{
158 cycrow 5271
	return m_gameExe.GetProperDir((dir.empty()) ? m_sCurrentDir : dir);
121 cycrow 5272
}
5273
Utils::String CPackages::getAddonDir() const
5274
{
158 cycrow 5275
	return getAddonDir(m_sCurrentDir);
121 cycrow 5276
}
5277
Utils::String CPackages::getAddonDir(const Utils::String &dir) const
5278
{
158 cycrow 5279
	return m_gameExe.GetAddonDir((dir.empty()) ? m_sCurrentDir : dir);
121 cycrow 5280
}
5281
int CPackages::GetGameAddons(Utils::CStringList &exes, const Utils::String &dir)
5282
{
158 cycrow 5283
	return m_gameExe.GetGameAddons((dir.empty()) ? m_sCurrentDir : dir, exes);
121 cycrow 5284
}
5285
int CPackages::GetGameAddons(Utils::CStringList &exes)
5286
{
158 cycrow 5287
	return m_gameExe.GetGameAddons(m_sCurrentDir, exes);
121 cycrow 5288
}
1 cycrow 5289
 
152 cycrow 5290
Utils::String CPackages::getGameTypesString(CBaseFile *package, bool includeVersion)
1 cycrow 5291
{
5292
	if ( !package->AnyGameCompatability() )
152 cycrow 5293
		return "";
1 cycrow 5294
 
98 cycrow 5295
	Utils::String sGames;
1 cycrow 5296
	for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {
98 cycrow 5297
		if ( !sGames.empty() )
1 cycrow 5298
			sGames += ", ";
5299
		sGames += m_gameExe.GetGameNameFromType(gNode->Data()->iGame - 1);
5300
		if ( includeVersion ) {
98 cycrow 5301
			Utils::String version = m_gameExe.GetGameVersionFromType(gNode->Data()->iGame - 1, gNode->Data()->iVersion - 1, gNode->Data()->sVersion);
5302
			if ( !version.empty() ) {
5303
				sGames += " (";
5304
				sGames += version;
5305
				sGames += ")";
5306
			}
1 cycrow 5307
		}
5308
	}
5309
	return sGames;
5310
}
5311
 
5312
CyString CPackages::GetGameVersionString(CBaseFile *package)
5313
{
5314
	for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {
5315
		if ( gNode->Data()->iGame == m_iGame ) {
5316
			return m_gameExe.GetGameVersionFromType(m_iGame - 1, gNode->Data()->iVersion - 1, gNode->Data()->sVersion);
5317
		}
5318
	}
5319
 
5320
	return NullString;
5321
}
5322
 
5323
CyString CPackages::GetGameVersionFromType(int game, int version, CyString sVersion)
5324
{
56 cycrow 5325
	return m_gameExe.GetGameVersionFromType(game - 1, version - 1, sVersion.ToString());
1 cycrow 5326
}
5327
 
5328
int CPackages::CountBuiltInPackages(bool onlyEnabled)
5329
{
5330
	int count = 0;
5331
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5332
	{
5333
		if ( !node->Data()->CheckGameCompatability(m_iGame) )
5334
			continue;
5335
		if ( onlyEnabled && !node->Data()->IsEnabled() )
5336
			continue;
50 cycrow 5337
		if ( node->Data()->author().Compare("PluginManager") )
1 cycrow 5338
			++count;
5339
	}
5340
 
5341
	return count;
5342
}
5343
 
5344
int CPackages::CountPackages(int type, bool onlyEnabled)
5345
{
5346
	int count = 0;
5347
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5348
	{
5349
		CBaseFile *p = node->Data();
5350
 
5351
		if ( (type != TYPE_BASE) && (p->GetType() != type) )
5352
			continue;
5353
 
5354
		if ( (onlyEnabled) && (!p->IsEnabled()) )
5355
			continue;
5356
 
5357
		++count;
5358
	}
5359
 
5360
	return count;
5361
}
5362
 
5363
int CPackages::ExtractGameFile(CyString aFilename, CyString aTo, CyString dir, CyString addon)
5364
{
5365
	// first check the enabled mod
5366
	if ( dir.Empty() )
5367
		dir = m_sCurrentDir;
5368
 
5369
	CyString addonDir = addon;
5370
	if ( addonDir.Empty() ) addonDir = this->GetAddonDir(dir);
5371
 
5372
	if ( m_pEnabledMod && m_pEnabledMod->AnyFileType(FILETYPE_MOD) )
5373
	{
5374
		for ( C_File *file = m_pEnabledMod->GetFirstFile(FILETYPE_MOD); file; file = m_pEnabledMod->GetNextFile(file) )
5375
		{
5376
			if ( !file->CheckFileExt("cat") )
5377
				continue;
5378
 
5379
			CCatFile catFile;
125 cycrow 5380
			if ( catFile.open(file->filePointer(), addonDir.ToString(), CATREAD_CATDECRYPT, false) == CATERR_NONE )
1 cycrow 5381
			{
5382
				if ( catFile.ExtractFile(aFilename, aTo) )
5383
					return 1;
124 cycrow 5384
				if ( catFile.error() == CATERR_INVALIDDEST || catFile.error() == CATERR_CANTCREATEDIR )
1 cycrow 5385
				{
5386
					if ( catFile.ExtractFile(aFilename) )
5387
						return -1;
5388
				}
5389
 
5390
			}
5391
		}
5392
	}
160 cycrow 5393
	else if ( !m_sSetMod.empty() )
1 cycrow 5394
	{
160 cycrow 5395
		if ( CFileIO::Exists(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat"))
1 cycrow 5396
		{
5397
			CCatFile catFile;
160 cycrow 5398
			if (catFile.open(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat", addonDir.ToString(), CATREAD_CATDECRYPT, false) == CATERR_NONE)
1 cycrow 5399
			{
5400
				if ( catFile.ExtractFile(aFilename, aTo) )
5401
					return 1;
124 cycrow 5402
				if ( catFile.error() == CATERR_INVALIDDEST || catFile.error() == CATERR_CANTCREATEDIR )
1 cycrow 5403
				{
5404
					if ( catFile.ExtractFile(aFilename) )
5405
						return -1;
5406
				}
5407
			}
5408
		}
5409
	}
5410
 
5411
	// find the highest cat number
5412
	int catNumber = 1;
52 cycrow 5413
	while ( CFileIO(dir + "/" + CyString::Number(catNumber).PadNumber(2) + ".cat").ExistsOld() && catNumber < 99 )
1 cycrow 5414
		++catNumber;
5415
 
5416
	// get the last one, not the next free one
5417
	--catNumber;
5418
 
5419
	// work backwards until we find the file
5420
	for ( ; catNumber; catNumber-- )
5421
	{
5422
		CCatFile catFile;
125 cycrow 5423
		if (catFile.open((dir + "/" + CyString::Number(catNumber).PadNumber(2) + ".cat").ToString(), addonDir.ToString(), CATREAD_CATDECRYPT, false) == CATERR_NONE )
1 cycrow 5424
		{
5425
			// check for the file
5426
			if ( catFile.ExtractFile(aFilename, aTo) )
5427
				return 1;
124 cycrow 5428
			if ( catFile.error() == CATERR_INVALIDDEST || catFile.error() == CATERR_CANTCREATEDIR )
1 cycrow 5429
			{
5430
				if ( catFile.ExtractFile(aFilename) )
5431
					return -1;
5432
			}
5433
		}
5434
	}
5435
 
5436
	return 0;
5437
}
5438
 
5439
void CPackages::CreateWareFiles()
5440
{
5441
	// do each ware
5442
	int wareTextID = WARETEXTSTART;
5443
	for ( int i = 0; i < WAREBUFFERS; i++ )
5444
	{
5445
		// its empty, no need to create ware files
5446
		if ( !m_lGameWares[i].size() )
5447
			continue;
5448
 
5449
		// lets extract the ware file
5450
		char wareType = CPackages::ConvertWareTypeBack(i);
118 cycrow 5451
		Utils::String wareFile = "TWare";
1 cycrow 5452
		wareFile += (char)UPPER(wareType);
5453
 
5454
		CyString openFile;
5455
 
5456
		int e;
118 cycrow 5457
		if ( i == WARES_TECH && CFileIO::Exists(m_sTempDir + "/TWareT.txt") )
1 cycrow 5458
			openFile = m_sTempDir + "/TWareT.txt";
5459
		else {
118 cycrow 5460
			e = ExtractGameFile("types/" + wareFile + ".pck", m_sTempDir + "/" + wareFile + ".txt");
1 cycrow 5461
			if ( e == 1 )
5462
				openFile = m_sTempDir + "/" + wareFile + ".txt";
5463
			else if ( e == -2 )
5464
				openFile = wareFile + ".txt";
5465
		}
5466
 
5467
		if ( !openFile.Empty() )
5468
		{
5469
			// read the file into memory
160 cycrow 5470
			Utils::CStringList wareLines;
5471
			size_t oldSize = -1;
1 cycrow 5472
			int version = -1;
5473
 
5474
			// read first number
5475
			CFileIO readFile(m_sTempDir + "/" + wareFile + ".txt");
160 cycrow 5476
			Utils::CStringList *lines = readFile.readLinesStr();
1 cycrow 5477
			if ( lines )
5478
			{
160 cycrow 5479
				for(auto itr = lines->begin(); itr != lines->end(); itr++)
1 cycrow 5480
				{
160 cycrow 5481
					Utils::String line((*itr)->str);
5482
					line.removeFirstSpace();
5483
					line.removeChar(9);
5484
					line.removeChar('\r');
5485
					if ( line.empty() )
1 cycrow 5486
						continue;
5487
					if ( line[0] == '/' )
5488
						continue;
5489
 
5490
					if ( oldSize == -1 )
5491
					{
160 cycrow 5492
						version = line.token(";", 1).toInt();
5493
						oldSize = line.token(";", 2).toInt();
1 cycrow 5494
					}
5495
					else
5496
					{
160 cycrow 5497
						line.removeEndSpace();
5498
						if ( line.back() != ';')
1 cycrow 5499
							line += ";";
160 cycrow 5500
						wareLines.pushBack(line);
5501
						if ( wareLines.size() >= oldSize )
1 cycrow 5502
							break;
5503
					}
5504
				}
5505
 
5506
				delete lines;
5507
 
5508
				// apply the buffer
5509
				if ( m_iWareBuffer[i] <= 0 )
160 cycrow 5510
					m_iWareBuffer[i] = wareLines.size() + 10;
1 cycrow 5511
				// last resort, readjust the buffer
160 cycrow 5512
				else if ( wareLines.size() > static_cast<size_t>(m_iWareBuffer[i]) )
5513
					m_iWareBuffer[i] = wareLines.size();
1 cycrow 5514
 
5515
				// add the buffers
160 cycrow 5516
				while ( wareLines.size() < static_cast<size_t>(m_iWareBuffer[i]) )
5517
					wareLines.pushBack("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_FILLER;");
1 cycrow 5518
 
5519
				// add the ware lines
5520
				bool create = false;
5521
				for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() )
5522
				{
5523
					SGameWare *w = node->Data();
5524
 
5525
					if ( w->iType == WARETYPE_NONE )
5526
						continue;
5527
					else if ( w->iType == WARETYPE_DISABLED )
5528
					{
5529
						create = true;
160 cycrow 5530
						wareLines.pushBack("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;" + w->sWareName + "_DISABLED;");
1 cycrow 5531
					}
5532
					else if ( w->iType == WARETYPE_DELETED || !w->pWare )
5533
					{
5534
						create = true;
160 cycrow 5535
						wareLines.pushBack("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_DELETED;");
1 cycrow 5536
					}
5537
					else if ( w->iType == WARETYPE_ADDED )
5538
					{
5539
						create = true;
5540
						w->pWare->iDescID = wareTextID;
5541
						w->iText = wareTextID;
5542
						wareTextID += 10;
160 cycrow 5543
						w->iPos = wareLines.size();
88 cycrow 5544
						long price = this->customWareOveridePrice(w->pWare->sID);
5545
						int notority = w->pWare->iNotority;
5546
						if ( !this->customWareOverideNoto(w->pWare->sID, &notority) ) notority = w->pWare->iNotority;
5547
						if ( !price ) price = w->pWare->iPrice;
5548
 
160 cycrow 5549
						wareLines.pushBack(Utils::String("28;0;0;0;0;") + (long)wareLines.size() + ";" + (long)(w->iText + 3) + ";" + (long)w->pWare->iVolumn + ";" + price + ";1;1;" + (long)w->pWare->iSize + ";" + price + ";" + (long)notority + ";0;0;" + w->sWareName.upper() + ";");
1 cycrow 5550
					}
5551
				}
5552
 
5553
				if ( create )
5554
				{
160 cycrow 5555
					wareLines.pushFront(Utils::String::Number(version) + ";" + Utils::String::Number(wareLines.size()) + ";", Utils::String::Null());
5556
					Utils::String strV;
1 cycrow 5557
					strV.FromFloat(GetLibraryVersion(), 2);
160 cycrow 5558
					wareLines.pushFront("// Created by SPKInstaller Libraries V" + strV, Utils::String::Null());
5559
					if ( readFile.writeFile(&wareLines) )
1 cycrow 5560
						this->PackFile(&readFile, CyString("types\\") + wareFile + ".pck");
5561
				}
5562
			}
52 cycrow 5563
			readFile.remove();
1 cycrow 5564
		}
5565
	}
5566
}
5567
 
160 cycrow 5568
Utils::String CPackages::empWaresForGame(size_t *maxsize)
1 cycrow 5569
{
88 cycrow 5570
	if ( maxsize ) (*maxsize) = 0;
1 cycrow 5571
 
5572
	if ( m_iGame == GAME_X3TC )
5573
	{
88 cycrow 5574
		if ( maxsize ) (*maxsize) = EMP_X3TC;
5575
		return GetX3TCEmp();
1 cycrow 5576
	}
126 cycrow 5577
	else if (m_iGame == GAME_X3AP)
1 cycrow 5578
	{
126 cycrow 5579
		if (maxsize) (*maxsize) = EMP_X3AP;
88 cycrow 5580
		return GetX3TCEmp();
1 cycrow 5581
	}
126 cycrow 5582
	else if (m_iGame == GAME_X3FL)
5583
	{
5584
		if (maxsize) (*maxsize) = EMP_X3FL;
5585
		return GetX3TCEmp();
5586
	}
1 cycrow 5587
	else if ( m_iGame == GAME_X3 )
5588
	{
88 cycrow 5589
		if ( maxsize ) (*maxsize) = EMP_X3;
5590
		return GetX3Emp();
1 cycrow 5591
	}
5592
 
88 cycrow 5593
	return Utils::String::Null();
5594
}
5595
 
5596
void CPackages::_addWareOverride(enum WareTypes type, int pos, const Utils::String &id, int value, bool noto)
5597
{
5598
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
5599
		SWarePriceOverride *wp = node->Data();
5600
		if ( wp->type == type ) {
5601
			if ( wp->type == Ware_Custom && !wp->id.Compare(id) ) continue;
5602
			else if ( wp->type != Ware_Custom && wp->pos != pos ) continue;
5603
			if ( noto ) {
5604
				wp->notority  = value;
89 cycrow 5605
				wp->bNotority = true;
88 cycrow 5606
			}
5607
			else wp->relval = value;
5608
			return;
5609
		}
5610
	}
5611
 
5612
	SWarePriceOverride *ware = new SWarePriceOverride;
5613
	ware->bNotority = noto;
5614
	ware->notority = (noto) ? value : 0;
5615
	ware->relval = (noto) ? 0 : value;
5616
	ware->type = type;
5617
	ware->pos = pos;
5618
	ware->id = id;
5619
 
5620
	m_lWarePrices.push_back(ware);
5621
}
5622
 
5623
void CPackages::addEMPPriceOverride(int empId, int price)
5624
{
5625
	_addWareOverride(Ware_EMP, empId, Utils::String::Null(), price, false);
5626
}
5627
 
5628
void CPackages::addEMPNotoOverride(int empId, int noto)
5629
{
5630
	_addWareOverride(Ware_EMP, empId, Utils::String::Null(), noto, true);
5631
}
5632
 
5633
void CPackages::addBuiltInWarePriceOverride(int empId, int price)
5634
{
5635
	_addWareOverride(Ware_BuiltIn, empId, Utils::String::Null(), price, false);
5636
}
5637
 
5638
void CPackages::addBuiltInWareNotoOverride(int empId, int noto)
5639
{
5640
	_addWareOverride(Ware_BuiltIn, empId, Utils::String::Null(), noto, false);
5641
}
5642
 
5643
void CPackages::addCustomWarePriceOverride(const Utils::String &id, int price)
5644
{
5645
	_addWareOverride(Ware_Custom, 0, id, price, false);
5646
}
5647
 
5648
void CPackages::addCustomWareNotoOverride(const Utils::String &id, int noto)
5649
{
5650
	_addWareOverride(Ware_Custom, 0, id, noto, true);
5651
}
5652
 
5653
 
5654
void CPackages::CreateEMPFile(CyString progDir)
5655
{
5656
	// do emp wares
160 cycrow 5657
	size_t maxsize = 0;
88 cycrow 5658
	Utils::String empWares = empWaresForGame(&maxsize);
5659
 
1 cycrow 5660
	if ( maxsize )
5661
	{
5662
		int e = ExtractGameFile("types/TWareT.pck", m_sTempDir + "/TWareT.txt");
5663
		if ( e )
5664
		{
5665
			// read the file into memory
160 cycrow 5666
			Utils::CStringList wareLines;
5667
			size_t oldSize = -1;
1 cycrow 5668
			int version = -1;
5669
 
5670
			// read first number
5671
			CFileIO readFile((e == -1) ? "TWareT.txt" : m_sTempDir + "/TWareT.txt");
88 cycrow 5672
			std::vector<Utils::String> *lines = readFile.readLines();
1 cycrow 5673
			if ( lines )
5674
			{
5675
				for ( int i = 0; i < (int)lines->size(); i++ )
5676
				{
88 cycrow 5677
					Utils::String line(lines->at(i));
5678
					line.removeFirstSpace();
5679
					line.removeChar('\r');
5680
					line.removeChar(9);
1 cycrow 5681
					if ( line[0] == '/' )
5682
						continue;
5683
 
5684
					if ( oldSize == -1 )
5685
					{
88 cycrow 5686
						version = line.token(";", 1).toLong();
5687
						oldSize = line.token(";", 2).toLong();
1 cycrow 5688
					}
5689
					else
5690
					{
88 cycrow 5691
						line.removeEndSpace();
5692
						if ( line.right(1) != ";" )
1 cycrow 5693
							line += ";";
88 cycrow 5694
 
5695
						// check for any override values for built in wares
5696
						if ( (i >= 62 && i <= 81) || (i >= 88 && i <= 93) ) {
5697
							int pos = i - ((i >= 88) ? 88 : 62);
5698
							int price = this->builtInWareOveridePrice(pos);
5699
							if ( price ) {
5700
								line = line.replaceToken(";", 9, Utils::String::Number(price));
5701
								line = line.replaceToken(";", 13, Utils::String::Number(price));
5702
							}
5703
 
5704
							int noto = 0;
5705
							if ( this->builtInWareOverideNoto(pos, &noto) ) {
5706
								line = line.replaceToken(";", 14, Utils::String::Number(noto));
5707
							}
5708
						}
5709
 
5710
						// check for any override values for EMP
5711
						if ( i >= 116 ) {
5712
							int price = this->empOveridePrice(i - 116);
5713
							if ( price ) {
5714
								line = line.replaceToken(";", 9, Utils::String::Number(price));
5715
								line = line.replaceToken(";", 13, Utils::String::Number(price));
5716
							}
5717
 
5718
							int noto = 0;
5719
							if ( this->empOverideNoto(i - 116, &noto) ) {
5720
								line = line.replaceToken(";", 14, Utils::String::Number(noto));
5721
							}
5722
						}
5723
 
160 cycrow 5724
						wareLines.pushBack(line);
5725
						if ( wareLines.size() >= oldSize )
1 cycrow 5726
							break;
5727
					}
5728
				}
5729
 
5730
				delete lines;
5731
			}
5732
 
5733
			// now we too add/remove entries to match
5734
			// need filler entries
160 cycrow 5735
			while ( wareLines.size() < maxsize )
5736
				wareLines.pushBack("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_FILLER;");
1 cycrow 5737
 
5738
			int empEntries = 0;
88 cycrow 5739
			Utils::String *empStr = empWares.tokenise("\n", &empEntries);
1 cycrow 5740
 
5741
			if ( empEntries && empStr )
5742
			{
88 cycrow 5743
				// apply any price overrides
5744
				for(int i = 0; i < empEntries; i++) {
5745
					int price = this->empOveridePrice(i);
5746
					if ( price ) {
5747
						empStr[i] = empStr[i].replaceToken(";", 9, Utils::String::Number(price));
5748
						empStr[i] = empStr[i].replaceToken(";", 13, Utils::String::Number(price));
5749
					}
5750
 
5751
					int noto = 0;
5752
					if ( this->empOverideNoto(i, &noto) ) {
5753
						empStr[i] = empStr[i].replaceToken(";", 14, Utils::String::Number(noto));
5754
					}
5755
				}
1 cycrow 5756
				// remove any empty end entries
88 cycrow 5757
				while ( empStr[empEntries - 1].empty() )
1 cycrow 5758
					--empEntries;
5759
 
160 cycrow 5760
				Utils::CStringList addAfter;
5761
				if ( wareLines.size() > maxsize )
1 cycrow 5762
				{
5763
					// force emp, remove entries to allow them to be added
5764
					if ( m_bForceEMP )
5765
					{
5766
						// more after emp
160 cycrow 5767
						if ( wareLines.size() > (maxsize + empEntries) )
1 cycrow 5768
						{
160 cycrow 5769
							for (size_t i = (maxsize + empEntries); i < wareLines.size(); i++)
1 cycrow 5770
							{
160 cycrow 5771
								auto node = wareLines.get(i);
5772
								addAfter.pushBack(node->str);
1 cycrow 5773
							}
5774
						}
5775
 
5776
						// no remove them all
160 cycrow 5777
						while (wareLines.size() > maxsize)
5778
							wareLines.removeAt(wareLines.size() - 1);
1 cycrow 5779
					}
126 cycrow 5780
					else if ( m_iGame == GAME_X3TC || m_iGame == GAME_X3AP || m_iGame == GAME_X3FL) // check if old emp is included, and convert it
1 cycrow 5781
					{
160 cycrow 5782
						if ( wareLines.size() > 128 )
1 cycrow 5783
						{
160 cycrow 5784
							Utils::String test = wareLines.get(128)->str;
5785
							if ( test.tokens(";", -2).Compare("SS_WARE_SW_CUSTOM16_1;") )
1 cycrow 5786
							{
5787
								// if theres any at the end, remove the last emp entry
160 cycrow 5788
								if ( wareLines.size() > (maxsize + empEntries - 1) )
1 cycrow 5789
								{
160 cycrow 5790
									wareLines.removeAt(maxsize + empEntries - 2);
1 cycrow 5791
								}
160 cycrow 5792
								wareLines.insertAt(128, "0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;128;");
1 cycrow 5793
							}
5794
						}
5795
					}
5796
				}
5797
 
5798
				// too many entries, need to remove the first set of EMP wares
5799
				int i = 0;
160 cycrow 5800
				if ( wareLines.size() > maxsize )
5801
					i = wareLines.size() - maxsize;
1 cycrow 5802
 
5803
				for ( ; i < empEntries; i++ )
5804
				{
160 cycrow 5805
					Utils::String str = empStr[i];
5806
					str.removeEndSpace();
5807
					str.removeChar(9);
5808
					str.removeChar('\r');
5809
					if ( str.empty() )
1 cycrow 5810
						continue;
160 cycrow 5811
					if ( str.right(1) != ";")
1 cycrow 5812
						str += ";";
160 cycrow 5813
					wareLines.pushBack(str);
1 cycrow 5814
				}
5815
 
160 cycrow 5816
				for(auto afterItr = addAfter.begin(); afterItr != addAfter.end(); afterItr++)
5817
					wareLines.pushBack((*afterItr)->str);
1 cycrow 5818
 
5819
				// finally we write the whole file
160 cycrow 5820
				wareLines.pushFront(Utils::String::Number(version) + ";" + Utils::String::Number(wareLines.size()) + ";", Utils::String::Null());
5821
				wareLines.pushFront("// Created by SPKInstaller Libraries V" + Utils::String::FromFloat(GetLibraryVersion(), 2), Utils::String::Null());
5822
				if ( readFile.writeFile(&wareLines) )
1 cycrow 5823
					this->PackFile(&readFile, "types\\TWareT.pck");
5824
			}
5825
			CLEANSPLIT(empStr, empEntries);
5826
		}
5827
	}
5828
}
5829
 
84 cycrow 5830
Utils::String parseXmlText(const Utils::String &str)
17 cycrow 5831
{
84 cycrow 5832
	Utils::String newStr(str);
17 cycrow 5833
	CyStringList changes;
5834
 
5835
	// find all XML commands, &<command>;
84 cycrow 5836
	Utils::String sStr = str;
5837
	Utils::String::size_type pos = sStr.find_first_of("&", 0);
5838
	while ( pos != Utils::String::npos ) {
17 cycrow 5839
		// find the next space and next ;.  If ; comes first, assume its acommand
84 cycrow 5840
		Utils::String::size_type spacePos = sStr.find_first_of(" ", pos);
5841
		Utils::String::size_type colonPos = sStr.find_first_of(";", pos);
5842
		if ( colonPos != Utils::String::npos && colonPos < spacePos ) {
17 cycrow 5843
			// replace with <::command::> so they the & doesn't get replaced
84 cycrow 5844
			Utils::String repStr = sStr.substr(pos, (colonPos + 1) - pos);
5845
			Utils::String repWithStr = "<::" + sStr.substr(pos + 1, colonPos - pos - 1) + "::>";
5846
			newStr = newStr.findReplace(repStr, repWithStr);
5847
			changes.PushBack(CyString(repStr), CyString(repWithStr));
17 cycrow 5848
		}
5849
 
5850
		// find the next command
5851
		pos = sStr.find_first_of("&", pos + 1);
5852
	}
5853
 
5854
	// replace the & now
84 cycrow 5855
	newStr = newStr.findReplace("&", "&amp;");
17 cycrow 5856
 
5857
	// restore the commands
5858
	for ( SStringList *strNode = changes.Head(); strNode; strNode = strNode->next ) {
84 cycrow 5859
		newStr = newStr.findReplace(strNode->data.ToString(), strNode->str.ToString());
17 cycrow 5860
	}
5861
 
5862
	return newStr;
5863
}
5864
 
84 cycrow 5865
Utils::String CPackages::ConvertTextString(const Utils::String &sText)
1 cycrow 5866
{
17 cycrow 5867
	//process any &
84 cycrow 5868
	Utils::String text = parseXmlText(sText);
17 cycrow 5869
 
5870
	// change special cases
84 cycrow 5871
	text = text.findReplace("(", "\\(");
5872
	text = text.findReplace(")", "\\)");
5873
	text = text.findReplace("[", "{");
5874
	text = text.findReplace("]", "}");
5875
	text = text.findReplace(">", "&gt;");
5876
	text = text.findReplace("<", "&lt;");
1 cycrow 5877
	return text;
5878
}
5879
 
56 cycrow 5880
int CPackages::_gameTextNumber() const
5881
{
5882
	int gameNumber = (m_pCurrentGameExe) ? m_pCurrentGameExe->iTextNum : -1;
5883
	if ( gameNumber != -1 ) return gameNumber;
5884
 
5885
	switch(m_iGame) {
5886
		case GAME_X3: return 30;
5887
		case GAME_X3TC: return 35;
5888
		case GAME_X3AP: return 38;
126 cycrow 5889
		case GAME_X3FL: return 39;
56 cycrow 5890
		default: return 0;
5891
	}
5892
}
5893
 
87 cycrow 5894
void CPackages::createPluginManagerOpenText()
5895
{
5896
	int gameNumber = _gameTextNumber();
5897
 
5898
	int lang = m_iLanguage;
5899
	if ( !lang || lang < 0 )
5900
		lang = 44;
5901
 
5902
	CDirIO Dir(m_sCurrentDir);
121 cycrow 5903
	if ( !Dir.exists("t") )
160 cycrow 5904
		Dir.create("t");
87 cycrow 5905
 
158 cycrow 5906
	Utils::String filename = SPK::FormatTextName(PMTEXTFILE, lang, (m_iGameFlags & EXEFLAG_TCTEXT));
87 cycrow 5907
	CFileIO textFile(m_sCurrentDir + "/t/" + filename + ".xml");
5908
 
160 cycrow 5909
	std::vector<Utils::String> writeData;
87 cycrow 5910
 
160 cycrow 5911
	writeData.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
5912
	writeData.push_back("<language id=\"" + Utils::String::Number(lang) + "\">");
87 cycrow 5913
 
5914
	if ( !gameNumber )
160 cycrow 5915
		writeData.push_back("	<page id=\"" + Utils::String::Number(PMTEXTFILE) + "\" title=\"Plugin Manager Text File\" descr=\"Contains text used for the plugin manager, packages, settings, wares, ship, etc\">");
87 cycrow 5916
	else
160 cycrow 5917
		writeData.push_back("	<page id=\"" + (long)gameNumber + Utils::String::PadNumber(PMTEXTFILE, 4) + "\" title=\"Plugin Manager Text File\" descr=\"Contains text used for the plugin manager, packages, settings, wares, ship, etc\">");
87 cycrow 5918
 
160 cycrow 5919
	writeData.push_back("		<t id=\"99998\">[author]Plugin Manager[/author]It appears the plugin manager hasn't been closed properly.  Make sure its closed before running the game otherwise things may not work correctly</t>");
5920
	writeData.push_back("		<t id=\"99999\">2</t>");	
5921
	writeData.push_back("	</page>");
87 cycrow 5922
 
160 cycrow 5923
	writeData.push_back("</language>");
5924
	textFile.writeFileUTF(&writeData);
87 cycrow 5925
 
5926
	size_t fileSize;
102 cycrow 5927
	char *fileData = CFileIO(textFile.fullFilename()).ReadToData(&fileSize);
87 cycrow 5928
 
5929
	if ( fileData && fileSize)
5930
	{
5931
		size_t newFileSize;
5932
		unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
5933
		if ( pckData )
5934
		{
5935
			CFileIO pckFile(m_sCurrentDir + "/t/" + filename + ".pck");
5936
			pckFile.WriteData((char *)pckData, newFileSize);
102 cycrow 5937
			this->AddCreatedFile(pckFile.fullFilename());
87 cycrow 5938
		}
5939
	}
5940
	textFile.remove();
5941
}
5942
 
1 cycrow 5943
void CPackages::CreatePluginManagerText()
5944
{
56 cycrow 5945
	int gameNumber = _gameTextNumber();
1 cycrow 5946
 
5947
	int lang = m_iLanguage;
5948
	if ( !lang || lang < 0 )
5949
		lang = 44;
5950
 
5951
	CDirIO Dir(m_sCurrentDir);
121 cycrow 5952
	if ( !Dir.exists("t") )
160 cycrow 5953
		Dir.create("t");
1 cycrow 5954
 
5955
	m_iLastUpdated = (int)time(NULL);
5956
 
158 cycrow 5957
	Utils::String filename = SPK::FormatTextName(PMTEXTFILE, lang, (m_iGameFlags & EXEFLAG_TCTEXT));
1 cycrow 5958
	CFileIO textFile(m_sCurrentDir + "/t/" + filename + ".xml");
5959
 
160 cycrow 5960
	std::vector<Utils::String> writeData;
1 cycrow 5961
 
5962
	CLinkList<SGameWare> lWares;
5963
	CLinkList<SGameShip> lShips;
5964
	for ( int i = 0; i < WAREBUFFERS; i++ )
5965
	{
5966
		for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() )
5967
		{
5968
			SGameWare *w = node->Data();
5969
			if ( w->iType == WARETYPE_NONE )
5970
				continue;
5971
			lWares.push_back(w);
5972
		}
5973
	}
5974
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
5975
	{
5976
		if ( node->Data()->iType == WARETYPE_NONE )
5977
			continue;
5978
		lShips.push_back(node->Data());
5979
	}
5980
 
160 cycrow 5981
	writeData.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
5982
	writeData.push_back("<language id=\"" + Utils::String::Number(lang) + "\">");
1 cycrow 5983
 
5984
	if ( !gameNumber )
160 cycrow 5985
		writeData.push_back("	<page id=\"" + Utils::String::Number(PMTEXTFILE) + "\" title=\"Plugin Manager Text File\" descr=\"Contains text used for the plugin manager, packages, settings, wares, ship, etc\">");
1 cycrow 5986
	else
160 cycrow 5987
		writeData.push_back("	<page id=\"" + (long)gameNumber + Utils::String::PadNumber(PMTEXTFILE, 4) + "\" title=\"Plugin Manager Text File\" descr=\"Contains text used for the plugin manager, packages, settings, wares, ship, etc\">");
1 cycrow 5988
 
5989
	// write the heading
5990
	int start = 10000;
160 cycrow 5991
	writeData.push_back("		<t id=\"1\">" + Utils::String::Number(m_iLastUpdated) + "</t>");
5992
	writeData.push_back("		<t id=\"2\">" + Utils::String::Number(this->CountPackages(TYPE_SPK, true)) + "</t>");
5993
	writeData.push_back("		<t id=\"3\">" + Utils::String::Number(start) + "</t>");
5994
	writeData.push_back("		<t id=\"4\">" + Utils::String::Number(lWares.size()) + "</t>");
5995
	writeData.push_back("		<t id=\"6\">" + Utils::String::Number(lShips.size()) + "</t>");
1 cycrow 5996
 
5997
	// write some generic texts
160 cycrow 5998
	writeData.push_back("		<t id=\"110\">" + Utils::String::Number((long)m_iLanguage) + "</t>");
5999
	writeData.push_back("		<t id=\"109\">Plugin Manager: \\033GPoll Gui Data\\033X</t>");
6000
	writeData.push_back("		<t id=\"107\">Plugin Manager: \\033GExport Game Data\\033X </t>");
6001
	writeData.push_back("		<t id=\"100\">\\n</t>");
6002
	writeData.push_back("		<t id=\"101\">\\033B</t>");
6003
	writeData.push_back("		<t id=\"102\">\\033G</t>");
6004
	writeData.push_back("		<t id = \"103\">\\033B</t>");
6005
	writeData.push_back("		<t id=\"104\">\\033X</t>");
6006
	writeData.push_back("		<t id=\"105\">\\033Y</t>");
6007
	writeData.push_back("		<t id=\"106\">\\033C</t>");
6008
	writeData.push_back("		<t id=\"108\">\\033</t>");
87 cycrow 6009
 
160 cycrow 6010
	writeData.push_back("		<t id=\"99998\">[author]Plugin Manager[/author]It appears the plugin manager hasn't been closed properly.  Make sure its closed before running the game otherwise things may not work correctly</t>");
6011
	writeData.push_back("		<t id=\"99999\">1</t>");
1 cycrow 6012
	// now write each package
6013
	int settingStart = 100000;
6014
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
6015
	{
6016
		CBaseFile *p = node->Data();
6017
		if ( !p->IsEnabled() )
6018
			continue;
6019
 
6020
		if ( p->GetType() != TYPE_SPK )
6021
			continue;
6022
 
6023
		CSpkFile *spk = (CSpkFile *)p;
6024
 
6025
		// count text files
160 cycrow 6026
		Utils::String textEntries;
1 cycrow 6027
		int textCount = 0;
6028
		C_File *f = p->GetFirstFile(FILETYPE_TEXT);
6029
		while ( f )
6030
		{
160 cycrow 6031
			Utils::String sLang;
6032
			Utils::String id;
1 cycrow 6033
			if ( m_iGameFlags & EXEFLAG_TCTEXT )
6034
			{
160 cycrow 6035
				id = f->baseName().token("-", 1);
6036
				sLang = f->baseName().token("-", 2);
6037
				if ( sLang.empty() )
1 cycrow 6038
					sLang = "NULL";
6039
				else
160 cycrow 6040
					sLang = sLang.erase(0, 1);  // remove the "L"
1 cycrow 6041
			}
6042
			else
6043
			{
160 cycrow 6044
				sLang = f->baseName().left((int)f->baseName().length() - 4).padNumber(3);
6045
				id = f->baseName().mid(((int)f->baseName().length() - 4) + 1, 4);
1 cycrow 6046
			}
6047
 
6048
			if ( sLang != "NULL" )
6049
			{
160 cycrow 6050
				if ( sLang.toInt() == lang )
1 cycrow 6051
				{
6052
					++textCount;
160 cycrow 6053
					if ( !textEntries.empty() )
1 cycrow 6054
						textEntries += " ";
6055
					textEntries += id;
6056
				}
6057
			}
6058
			f = p->GetNextFile(f);
6059
		}
6060
 
160 cycrow 6061
		Utils::String sTextCount((long)textCount);
6062
		writeData.push_back("		<t id=\"" + Utils::String::Number((long)start) + "\">" + this->ConvertTextString(p->name()) + "</t>");
6063
		writeData.push_back("		<t id=\"" + Utils::String::Number((long)(start + 1)) + "\">" + this->ConvertTextString(p->author()) + "</t>");
6064
		writeData.push_back("		<t id=\"" + Utils::String::Number((long)(start + 2)) + "\">" + this->ConvertTextString(p->version()) + "</t>");
6065
		writeData.push_back("		<t id=\"" + Utils::String::Number((long)(start + 3)) + "\">" + this->ConvertTextString(p->GetLanguageName(lang).ToString()) + "</t>");
1 cycrow 6066
 
14 cycrow 6067
		CLinkList<SSettingType> *settings = spk->GetSettingsList();
1 cycrow 6068
		if ( settings && settings->size() )
6069
		{
160 cycrow 6070
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 4) + "\">" + (long)settings->size() + "</t>");
6071
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 5) + "\">" + (long)settingStart + "</t>");
1 cycrow 6072
 
14 cycrow 6073
			for ( CListNode<SSettingType> *sNode = settings->Front(); sNode; sNode = sNode->next() )
1 cycrow 6074
			{
14 cycrow 6075
				SSettingType *st = sNode->Data();
160 cycrow 6076
				writeData.push_back(Utils::String("		<t id=\"") + (long)(settingStart++) + "\">" + st->sKey + "</t>");
6077
				writeData.push_back(Utils::String("		<t id=\"") + (long)(settingStart++) + "\">" + spk->GetSetting(st) + "</t>");
1 cycrow 6078
			}
6079
		}
6080
		else
160 cycrow 6081
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 4) + "\">0</t>");
1 cycrow 6082
 
160 cycrow 6083
		writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 6) + "\">" + sTextCount + "</t>");
1 cycrow 6084
		if ( textCount )
160 cycrow 6085
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 7) + "\">" + textEntries + "</t>");
1 cycrow 6086
 
6087
		start += 10;
6088
	}
6089
 
6090
	// write ware names
6091
	if ( lWares.size() )
6092
	{
160 cycrow 6093
		writeData.push_back("		<t id=\"5\">" + Utils::String::Number(start) + "</t>");
1 cycrow 6094
		for ( CListNode<SGameWare> *node = lWares.Front(); node; node = node->next() )
6095
		{
6096
			SGameWare *w = node->Data();
6097
			if ( w->pWare && w->iType == WARETYPE_ADDED )
160 cycrow 6098
				writeData.push_back(Utils::String("		<t id=\"") + (long)start + "\">" + this->ConvertTextString(w->sWareName) + "</t>");
1 cycrow 6099
			else
160 cycrow 6100
				writeData.push_back(Utils::String("		<t id=\"") + (long)start + "\">-1</t>");
6101
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 1) + "\">" + Utils::String((char)w->cType) + "</t>");
6102
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 2) + "\">" + (long)w->iPos + "</t>");
1 cycrow 6103
			start += 10;
6104
		}
6105
	}
6106
 
6107
	if ( lShips.size() )
6108
	{
160 cycrow 6109
		writeData.push_back("		<t id=\"7\">" + Utils::String::Number(start) + "</t>");
1 cycrow 6110
		for ( CListNode<SGameShip> *node = lShips.Front(); node; node = node->next() )
6111
		{
6112
			SGameShip *gs = node->Data();
6113
			if ( gs->iType == WARETYPE_NONE )
6114
				continue;
6115
			if ( gs->pPackage && gs->iType == WARETYPE_ADDED )
160 cycrow 6116
				writeData.push_back(Utils::String("		<t id=\"") + (long)start + "\">" + gs->sShipID + "</t>");
1 cycrow 6117
			else
160 cycrow 6118
				writeData.push_back(Utils::String("		<t id=\"") + (long)start + "\">-1</t>");
6119
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 1) + "\">" + (long)gs->iPos + "</t>");
6120
			writeData.push_back(Utils::String("		<t id=\"") + (long)(start + 2) + "\">Ship</t>");
1 cycrow 6121
 
6122
			// write shipyard info
6123
			if ( gs->pPackage )
6124
			{
6125
				int doStart = start + 5;
6126
				for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
6127
				{
160 cycrow 6128
					writeData.push_back(Utils::String("		<t id=\"") + (long)(doStart) + "\">" + ((gs->pPackage->IsShipyard(i)) ? Utils::String::Number(1) : Utils::String::Number(0)) + "</t>");
1 cycrow 6129
					++doStart;
6130
				}
6131
			}
6132
 
6133
			start += 20;
6134
		}
6135
	}
6136
 
160 cycrow 6137
	writeData.push_back("	</page>");
1 cycrow 6138
 
160 cycrow 6139
	// do emp
6140
	if (m_iGame == GAME_X3TC || m_iGame == GAME_X3 || m_iGame == GAME_X3AP || m_iGame == GAME_X3FL)
6141
	{
6142
		writeData.push_back("  <page id=\"17\" title=\"Plugin Manager Objects\">");
6143
		writeData.push_back(GetEMPText());
6144
		writeData.push_back("  </page>");
6145
	}
6146
 
1 cycrow 6147
	// wares
126 cycrow 6148
	if ( m_iGame == GAME_X3AP || m_iGame == GAME_X3TC || m_iGame == GAME_X3FL || m_iGame == GAME_X3 || lWares.size() || lShips.size() )
1 cycrow 6149
	{
160 cycrow 6150
 
1 cycrow 6151
		if ( !gameNumber )
160 cycrow 6152
			writeData.push_back("  <page id=\"17\" title=\"Plugin Manager Objects\">");
1 cycrow 6153
		else
160 cycrow 6154
			writeData.push_back(Utils::String("  <page id=\"") + (long)gameNumber + "0017\" title=\"Plugin Manager Objects\">");
1 cycrow 6155
 
160 cycrow 6156
		writeData.push_back(Utils::String("		<t id=\"") + (long)(SHIPSTARTTEXT - 1) + "\">ZZ_BLANKSHIP</t>");
1 cycrow 6157
 
6158
		// object names
6159
		for ( CListNode<SGameWare> *node = lWares.Front(); node; node = node->next() )
6160
		{
6161
			SGameWare *w = node->Data();
6162
			if ( !w->pWare || w->iType != WARETYPE_ADDED )
6163
				continue;
6164
 
6165
			// find the correct text for the language
84 cycrow 6166
			Utils::String name = CSpkFile::GetWareText(w->pWare, m_iLanguage);
6167
			Utils::String desc = CSpkFile::GetWareDesc(w->pWare, m_iLanguage);
6168
			if ( !name.empty() )
160 cycrow 6169
				writeData.push_back(Utils::String("		<t id=\"") + (long)(w->iText + 3) + "\">" + this->ConvertTextString(name) + "</t>");
84 cycrow 6170
			if ( !desc.empty() )
160 cycrow 6171
				writeData.push_back(Utils::String("		<t id=\"") + (long)(w->iText + 4) + "\">" + this->ConvertTextString(desc) + "</t>");
1 cycrow 6172
		}
6173
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6174
		{
6175
			SGameShip *s = node->Data();
6176
			if ( !s->pPackage || s->iType != WARETYPE_ADDED )
6177
				continue;
6178
			if ( s->pPackage->GetOriginalDescription() )
6179
				continue;
6180
 
84 cycrow 6181
			Utils::String name = s->pPackage->GetTextName(m_iLanguage);
6182
			Utils::String desc = s->pPackage->GetTextDescription(m_iLanguage);
6183
			if ( !name.empty() )
160 cycrow 6184
				writeData.push_back(Utils::String("		<t id=\"") + (long)s->iText + "\">" + this->ConvertTextString(name) + "</t>");
84 cycrow 6185
			if ( !desc.empty() )
160 cycrow 6186
				writeData.push_back(Utils::String("		<t id=\"") + (long)(s->iText + 1) + "\">" + this->ConvertTextString(desc) + "</t>");
1 cycrow 6187
		}
160 cycrow 6188
		writeData.push_back("  </page>");
1 cycrow 6189
	}
160 cycrow 6190
	writeData.push_back("</language>");
6191
	textFile.writeFileUTF(&writeData);
1 cycrow 6192
 
6193
	size_t fileSize;
102 cycrow 6194
	char *fileData = CFileIO(textFile.fullFilename()).ReadToData(&fileSize);
1 cycrow 6195
 
6196
	if ( fileData && fileSize)
6197
	{
6198
		size_t newFileSize;
6199
		unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
6200
		if ( pckData )
6201
		{
6202
			CFileIO pckFile(m_sCurrentDir + "/t/" + filename + ".pck");
6203
			pckFile.WriteData((char *)pckData, newFileSize);
102 cycrow 6204
			this->AddCreatedFile(pckFile.fullFilename());
1 cycrow 6205
		}
6206
	}
52 cycrow 6207
	textFile.remove();
1 cycrow 6208
}
6209
 
121 cycrow 6210
bool CPackages::isCurrentDir(const Utils::String &dir) const
1 cycrow 6211
{
158 cycrow 6212
	Utils::String cur = m_sCurrentDir;
121 cycrow 6213
 
6214
	if ( dir.Compare(cur) )
1 cycrow 6215
		return true;
6216
 
121 cycrow 6217
	Utils::String checkDir = cur;
6218
	checkDir = checkDir.findReplace("/", "\\");
1 cycrow 6219
	if ( checkDir.Compare(dir) )
6220
		return true;
6221
 
121 cycrow 6222
	checkDir = checkDir.findReplace("\\", "/");
1 cycrow 6223
	if ( checkDir.Compare(dir) )
6224
		return true;
6225
 
6226
	return false;
6227
}
6228
 
126 cycrow 6229
void CPackages::backupSaves(bool vanilla)
1 cycrow 6230
{
126 cycrow 6231
	if (!_sSaveDir.empty())
6232
	{
6233
		// copy any saves into the vanilla directory
6234
		Utils::String dir = (vanilla) ? "Vanilla" : "Modified";
1 cycrow 6235
 
126 cycrow 6236
		// make sure the directory exists
6237
		CDirIO saveDir(this->saveDirectory());
6238
		CDirIO gameSaveDir(saveDir.dir(_sSaveDir));
1 cycrow 6239
 
126 cycrow 6240
		if (!gameSaveDir.exists())
160 cycrow 6241
			gameSaveDir.create();
126 cycrow 6242
		if (!gameSaveDir.exists(dir))
160 cycrow 6243
			gameSaveDir.create(dir);
126 cycrow 6244
		gameSaveDir.cd(dir);
6245
 
6246
		// backup the saves
6247
		Utils::CStringList files;
6248
		if(saveDir.dirList(files, Utils::String::Null(), "*.sav"))
1 cycrow 6249
		{
126 cycrow 6250
			for(auto itr = files.begin(); itr != files.end(); ++itr)
6251
			{
6252
				CFileIO File(saveDir.file((*itr)->str));
160 cycrow 6253
				if (!File.isFileExtension("sav"))
126 cycrow 6254
					continue;
6255
				// remove the file if already exists
6256
				if (gameSaveDir.exists((*itr)->str))
6257
					CFileIO::Remove(gameSaveDir.file((*itr)->str));
1 cycrow 6258
 
126 cycrow 6259
				// copy the file into the games save dir for backup
6260
				File.copy(gameSaveDir.file(File.filename()), true);
6261
			}
1 cycrow 6262
		}
6263
	}
6264
}
6265
 
126 cycrow 6266
void CPackages::restoreSaves(bool vanilla)
1 cycrow 6267
{
6268
	// get dir to restore from
126 cycrow 6269
	if (!_sSaveDir.empty())
6270
	{
6271
		Utils::String dir = (vanilla) ? "Vanilla" : "Modified";
6272
		CDirIO toDir(this->saveDirectory());
6273
		CDirIO restoreDir(toDir.dir(_sSaveDir));
6274
		restoreDir.cd(dir);
1 cycrow 6275
 
126 cycrow 6276
		if (restoreDir.exists())
6277
		{
6278
			//if we are in vanilla mode, we should remove the saves (so we only have vanilla saves
6279
			/*
6280
			if (vanilla) {
6281
				CyStringList *files = toDir.DirList();
6282
				if (files) {
6283
					for (SStringList *node = files->Head(); node; node = node->next)
6284
					{
6285
						CFileIO saveFile(toDir.File(node->str));
6286
						if (saveFile.extension().Compare("sav")) {
6287
							saveFile.remove();
6288
						}
6289
					}
6290
					delete files;
86 cycrow 6291
				}
6292
			}
126 cycrow 6293
			*/
86 cycrow 6294
 
126 cycrow 6295
			// now we copy of the backed up save games
6296
			Utils::CStringList files;
6297
			if(restoreDir.dirList(files, Utils::String::Null(), "*.sav"))
6298
			{
6299
				for(auto itr = files.begin(); itr != files.end(); itr++)
6300
				{
6301
					CFileIO File(restoreDir.file((*itr)->str));
6302
					// remove the file if already exists
6303
					if (toDir.exists((*itr)->str)) CFileIO::Remove(toDir.file((*itr)->str));
1 cycrow 6304
 
126 cycrow 6305
					// move file over
6306
					File.copy(toDir.file((*itr)->str), true);
6307
				}
6308
			}
1 cycrow 6309
		}
6310
	}
6311
}
6312
 
6313
bool CPackages::RemoveCurrentDirectory()
6314
{
6315
	if ( !m_bLoaded )
6316
		return false;
6317
 
6318
	// remove all package files
6319
	this->RemoveAllPackages();
6320
 
6321
	// remove all plugin manager files
6322
	this->RemoveCreatedFiles();
6323
 
6324
	this->Reset();
6325
	m_bLoaded = false;
6326
 
6327
	// clear the plugin manager directory
6328
	CDirIO Dir(m_sCurrentDir);
160 cycrow 6329
	Dir.removeDir("PluginManager", true, true, 0);
6330
	Dir.removeDir("dds", false, true, 0);
6331
	Dir.removeDir("objects", false, true, 0);
6332
	Dir.removeDir("types", false, true, 0);
6333
	Dir.removeDir("textures", false, true, 0);
1 cycrow 6334
 
6335
	// remove the plugin manager mod files
121 cycrow 6336
	if ( Dir.exists("mods/PluginManager.cat") )	CFileIO::Remove(Dir.file("mods/PluginManager.cat"));
6337
	if ( Dir.exists("mods/PluginManager.dat") )	CFileIO::Remove(Dir.file("mods/PluginManager.dat"));
1 cycrow 6338
 
6339
	return true;
6340
}
6341
 
6342
void CPackages::CreateDummies()
6343
{
6344
	// first check we have any ships
6345
	if ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )
6346
		return;
6347
 
6348
	CLinkList<SDummyEntry> dummyList;
6349
 
6350
	// now extract the existing dummies
6351
	int e = ExtractGameFile("types/Dummies.pck", m_sTempDir + "/Dummies.txt");
6352
	if ( e )
6353
	{
6354
		// read the dummies
6355
		CFileIO File;
118 cycrow 6356
		if ( File.open((e == -1) ? "Dummies.txt" : m_sTempDir + "/Dummies.txt") )
1 cycrow 6357
		{
160 cycrow 6358
			std::vector<Utils::String> *lines = File.readLines();
1 cycrow 6359
			if ( lines )
6360
			{
6361
				int insection = 0;
6362
				SDummyEntry *currentSection = NULL;
6363
				for ( int j = 0; j < (int)lines->size(); j++ )
6364
				{
160 cycrow 6365
					Utils::String line(lines->at(j));
6366
					line.removeChar(9);
6367
					line.removeChar('\r');
6368
					line.removeFirstSpace();
6369
					line.removeEndSpace();
6370
					if ( line.empty() )
1 cycrow 6371
						continue;
6372
					if ( line[0] == '/' )
6373
						continue;
6374
 
6375
					// read the section, first entry is section, second is size
160 cycrow 6376
					while ( !line.empty() )
1 cycrow 6377
					{
6378
						if ( !insection )
6379
						{
160 cycrow 6380
							CyString section = line.token(";", 1);
6381
							insection = line.token(";", 2).toInt();
1 cycrow 6382
 
6383
							// search for the sections
6384
							currentSection = NULL;
6385
							for ( CListNode<SDummyEntry> *node = dummyList.Front(); node; node = node->next() )
6386
							{
6387
								SDummyEntry *d = node->Data();
6388
								if ( d->sSection.Compare(section) )
6389
								{
6390
									currentSection = node->Data();
6391
									break;
6392
								}
6393
							}
6394
 
6395
							if ( !currentSection )
6396
							{
6397
								currentSection = new struct SDummyEntry;
6398
								currentSection->sSection = section;
6399
								dummyList.push_back(currentSection);
6400
							}
6401
 
6402
							// we have some more ?
160 cycrow 6403
							line = line.remTokens(";", 1, 2);
1 cycrow 6404
						}
6405
						else
6406
						{
6407
							--insection;
6408
							// check the last entry for number of states
6409
							if ( currentSection->sSection.Compare("SDTYPE_GUN") )
6410
							{
160 cycrow 6411
								int states = line.token(";", 3).toInt();
6412
								int parts = line.token(";", 4 + (states * 2)).toInt();
6413
								Utils::String data = line.tokens(";", 1, 4 + (states * 2) + (parts * 2)) + ";";
6414
								currentSection->lEntries.PushBack(CyString(data));
1 cycrow 6415
 
6416
								// remove done
160 cycrow 6417
								line = line.remTokens(";", 1, 4 + (states * 2) + (parts * 2));
1 cycrow 6418
							}
6419
							else
6420
							{
160 cycrow 6421
								int states = line.token(";", 3).toInt();
6422
								Utils::String data = line.tokens(";", 1, 3 + (states * 2)) + ";";
6423
								currentSection->lEntries.PushBack(CyString(data));
1 cycrow 6424
 
6425
								// remove done
160 cycrow 6426
								line = line.remTokens(";", 1, 3 + (states * 2));
1 cycrow 6427
							}
6428
						}
6429
					}
6430
				}
6431
 
6432
				delete lines;
6433
			}
6434
 
52 cycrow 6435
			File.remove();
1 cycrow 6436
		}
6437
 
6438
		// add the new entries for the ships
6439
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6440
		{
6441
			SGameShip *s = node->Data();
6442
			if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6443
				continue;
6444
 
6445
			// no dummies to add?
6446
			if ( !s->pPackage->AnyDummies() )
6447
				continue;
6448
 
6449
			// add each dummy to list
6450
			for ( CListNode<SDummy> *dNode = s->pPackage->GetDummies()->Front(); dNode; dNode = dNode->next() )
6451
			{
6452
				SDummy *dummy = dNode->Data();
6453
				SDummyEntry *found = NULL;
6454
				for ( CListNode<SDummyEntry> *eNode = dummyList.Front(); eNode; eNode = eNode->next() )
6455
				{
39 cycrow 6456
					if ( eNode->Data()->sSection.Compare(CyString(dummy->sSection)) )
1 cycrow 6457
					{
6458
						found = eNode->Data();
6459
						break;
6460
					}
6461
				}
6462
				if ( !found )
6463
				{
6464
					found = new SDummyEntry;
6465
					found->sSection = dummy->sSection;
6466
					dummyList.push_back(found);
6467
				}
6468
				// check if its already on the list
6469
				else
6470
				{
6471
					bool f = false;
6472
					for ( SStringList *strNode = found->lEntries.Head(); strNode; strNode = strNode->next )
6473
					{
39 cycrow 6474
						if ( strNode->str.GetToken(";", 1, 1).Compare(CyString(dummy->sData.token(";", 1))) )
1 cycrow 6475
						{
6476
							f = true;
6477
							break;
6478
						}
6479
					}
6480
 
6481
					if ( f )
6482
						continue;
6483
				}
6484
 
39 cycrow 6485
				found->lEntries.PushBack(CyString(dummy->sData));
1 cycrow 6486
			}
6487
		}
6488
 
6489
		// finally, write the file
160 cycrow 6490
		std::vector<Utils::String> lines;
6491
		lines.push_back("// Dummies file, created by SPK Libraries V" + Utils::String::FromFloat(GetLibraryVersion(), 2));
1 cycrow 6492
		for ( SDummyEntry *dummy = dummyList.First(); dummy; dummy = dummyList.Next() )
6493
		{
6494
			lines.push_back("");
160 cycrow 6495
			lines.push_back("// Section: " + dummy->sSection.ToString() + " Entries: " + Utils::String::Number((long)dummy->lEntries.Count()));
6496
			lines.push_back(dummy->sSection.ToString() + ";" + Utils::String::Number(dummy->lEntries.Count()) + ";");
1 cycrow 6497
			for ( SStringList *str = dummy->lEntries.Head(); str; str = str->next )
6498
			{
160 cycrow 6499
				Utils::String strLine = str->str.ToString();
6500
				strLine.removeChar(9);
6501
				strLine.removeChar('\r');
6502
				strLine.removeEndSpace();
6503
				strLine.removeFirstSpace();
6504
				strLine = strLine.findReplace("<::PiPe::>", "|");
6505
				if ( strLine.right(1) != ";" )
1 cycrow 6506
					strLine += ";";
6507
				lines.push_back(strLine);
6508
			}
6509
		}
6510
		lines.push_back("");
6511
 
6512
		// write the file to disk
6513
		CFileIO WriteFile(m_sTempDir + "/dummies.txt");
160 cycrow 6514
		if ( WriteFile.writeFile(&lines) )
1 cycrow 6515
		{
6516
			this->PackFile(&WriteFile, "types\\dummies.pck");
52 cycrow 6517
			WriteFile.remove();
1 cycrow 6518
		}
6519
	}
6520
}
6521
 
6522
void CPackages::CreateCutData()
6523
{
6524
	// first check we have any ships
6525
	if ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )
6526
		return;
6527
 
6528
	bool found = false;
6529
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6530
	{
6531
		SGameShip *s = node->Data();
6532
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6533
			continue;
6534
 
6535
		// no dummies to add?
6536
		if ( !s->pPackage->AnyCutData() )
6537
			continue;
6538
		found = true;
6539
		break;
6540
	}
6541
 
6542
	if ( !found )
6543
		return;
6544
 
6545
	CyStringList cutList;
6546
	int e = ExtractGameFile("types/CutData.pck", m_sTempDir + "/CutData.txt");
6547
	if ( e )
6548
	{
6549
		CFileIO File;
118 cycrow 6550
		if ( File.open((e == -1) ? "CutData.txt" : m_sTempDir + "/CutData.txt") )
1 cycrow 6551
		{
160 cycrow 6552
			std::vector<Utils::String> *lines = File.readLines();
1 cycrow 6553
			if ( lines )
6554
			{
6555
				int entries = -1;
6556
				for ( int j = 0; j < (int)lines->size(); j++ )
6557
				{
160 cycrow 6558
					Utils::String line(lines->at(j));
6559
					line.removeChar(9);
6560
					line.removeChar('\r');
6561
					line.removeChar(' ');
6562
					if ( line.empty() || line[0] == '/' )
1 cycrow 6563
						continue;
6564
					if ( entries == -1 )
160 cycrow 6565
						entries = line.token(";", 1).toInt();
1 cycrow 6566
					else
6567
					{
160 cycrow 6568
						if ( line.right(1) != ";" )
1 cycrow 6569
							line += ";";
160 cycrow 6570
						cutList.PushBack(CyString(line));
1 cycrow 6571
						if ( cutList.Count() == entries )
6572
							break;
6573
					}
6574
				}
6575
 
6576
				delete lines;
6577
			}
6578
 
52 cycrow 6579
			File.remove();
1 cycrow 6580
		}
6581
	}
6582
 
6583
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6584
	{
6585
		SGameShip *s = node->Data();
6586
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6587
			continue;
6588
 
6589
		// no dummies to add?
6590
		if ( !s->pPackage->AnyCutData() )
6591
			continue;
6592
 
6593
		// add each dummy to list
6594
		for ( SStringList *strNode = s->pPackage->GetCutData()->Head(); strNode; strNode = strNode->next )
6595
		{
6596
			CyString str = strNode->str;
6597
			str.RemoveChar(' ');
6598
			if ( str.Right(1) != ";" )
6599
				str += ";";
6600
			cutList.PushBack(str, true);
6601
		}
6602
	}
6603
 
6604
	cutList.PushFront(CyString::Number(cutList.Count()) + ";");
6605
	cutList.PushFront("/cut id;filename (leave blank to use id)");
6606
	cutList.PushFront(CyString("// Cut Data file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2));
6607
 
6608
	// write the file to disk
6609
	CFileIO WriteFile(m_sTempDir + "/CutData.txt");
6610
	if ( WriteFile.WriteFile(&cutList) )
6611
	{
6612
		this->PackFile(&WriteFile, "types\\CutData.pck");
52 cycrow 6613
		WriteFile.remove();
1 cycrow 6614
	}
6615
}
6616
 
6617
void CPackages::CreateAnimations()
6618
{
6619
	// first check we have any ships
6620
	if ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )
6621
		return;
6622
 
6623
	bool found = false;
6624
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6625
	{
6626
		SGameShip *s = node->Data();
6627
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6628
			continue;
6629
 
6630
		// no dummies to add?
6631
		if ( !s->pPackage->AnyAnimations() )
6632
			continue;
6633
		found = true;
6634
		break;
6635
	}
6636
 
6637
	if ( !found )
6638
		return;
6639
 
6640
	CyStringList aniList;
6641
	int e = ExtractGameFile("types/Animations.pck", m_sTempDir + "/Animations.txt");
6642
	if ( e )
6643
	{
6644
		CFileIO File;
118 cycrow 6645
		if ( File.open((e == -1) ? "Animations.txt" : m_sTempDir + "/Animations.txt") )
1 cycrow 6646
		{
160 cycrow 6647
			std::vector<Utils::String> *lines = File.readLines();
1 cycrow 6648
			if ( lines )
6649
			{
6650
				for ( int j = 0; j < (int)lines->size(); j++ )
6651
				{
160 cycrow 6652
					Utils::String line(lines->at(j));
6653
					aniList.PushBack(CyString(line));
1 cycrow 6654
				}
6655
 
6656
				delete lines;
6657
			}
6658
 
52 cycrow 6659
			File.remove();
1 cycrow 6660
		}
6661
	}
6662
 
6663
	CyStringList parsedAniList;
6664
	CXspFile::ReadAnimations(&aniList, &parsedAniList, 0);
6665
 
6666
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6667
	{
6668
		SGameShip *s = node->Data();
6669
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6670
			continue;
6671
 
6672
		// no dummies to add?
6673
		if ( !s->pPackage->AnyAnimations() )
6674
			continue;
6675
 
6676
		// add each dummy to list
6677
		for ( SStringList *strNode = s->pPackage->GetAnimations()->Head(); strNode; strNode = strNode->next )
6678
			parsedAniList.PushBack(strNode->str);
6679
	}
6680
 
6681
	// format the list with added spaces
6682
	CyStringList formatedAniList;
6683
	int lineCount = -1;
6684
	for ( SStringList *strNode = parsedAniList.Head(); strNode; strNode = strNode->next )
6685
	{
6686
		// format the comment to match the line number
6687
		lineCount++;
6688
		CyString oldComment = strNode->str.GetToken("//", 2);
6689
		CyString comment = CyString("//") + CyString::Number(lineCount);
6690
		if ( !oldComment.Empty() )
6691
		{
6692
			comment += " ";
6693
			oldComment.RemoveFirstSpace();
6694
			if ( oldComment.GetToken(" ", 1, 1).IsNumber() )
6695
				comment += oldComment.GetToken(" ", 2);
6696
			else
6697
				comment += oldComment;
6698
		}
6699
		CyString line = strNode->str.GetToken("//", 1, 1);
6700
 
6701
		// split into seperate lines
6702
		CyString first = line.GetToken(";", 1, 1);
6703
		if ( first.Compare("TAT_TAGSINGLESTEP") )
6704
		{
6705
			formatedAniList.PushBack(line.GetToken(";", 1, 5) + ";");
6706
			int max;
6707
			CyString *sLines = line.GetToken(";", 6).SplitToken(";", &max);
6708
			if ( max && sLines )
6709
			{
6710
				if ( sLines[max - 1].Empty() )
6711
					--max; // remove the last ";"
6712
 
6713
				for ( int i = 0; i < max; i++ )
6714
				{
6715
					CyString l = CyString("\t") + sLines[i] + ";";
6716
					if ( i == (max - 1) )
6717
						formatedAniList.PushBack(l + comment);
6718
					else
6719
						formatedAniList.PushBack(l);
6720
				}
6721
			}
6722
			CLEANSPLIT(sLines, max);
6723
		}
6724
		else if ( (first.Compare("TAT_TAGONESHOT") || first.Compare("TAT_TAGLOOP")) && (line.IsIn("TATF_COORDS")) )
6725
		{
6726
			formatedAniList.PushBack(line.GetToken(";", 1, 5) + ";");
6727
			int max;
6728
			CyString *sLines = line.GetToken(";", 6).SplitToken(";", &max);
6729
			if ( max && sLines )
6730
			{
6731
				if ( sLines[max - 1].Empty() )
6732
					--max; // remove the last ";"
6733
 
6734
				CyString prevLine;
6735
				for ( int i = 0; i < max; i++ )
6736
				{
6737
					CyString l = sLines[i] + ";";
6738
					if ( l.IsIn("TATF_COORDS") && !prevLine.Empty() )
6739
					{
6740
						formatedAniList.PushBack(CyString("\t") + prevLine);
6741
						prevLine = "";
6742
					}
6743
					prevLine += l;
6744
				}
6745
 
6746
				if ( !prevLine.Empty() )
6747
					formatedAniList.PushBack(CyString("\t") + prevLine + comment);
6748
 
6749
			}
6750
			CLEANSPLIT(sLines, max);
6751
		}
6752
		else
6753
			formatedAniList.PushBack(line + comment);
6754
	}
6755
 
6756
	formatedAniList.PushFront(CyString::Number(parsedAniList.Count()) + ";");
6757
	formatedAniList.PushFront(CyString("// Animations, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2));
6758
 
6759
	// write the file to disk
6760
	CFileIO WriteFile(m_sTempDir + "/Animations.txt");
6761
	if ( WriteFile.WriteFile(&formatedAniList) )
6762
	{
6763
		this->PackFile(&WriteFile, "types\\Animations.pck");
52 cycrow 6764
		WriteFile.remove();
1 cycrow 6765
	}
6766
}
6767
 
6768
void CPackages::CreateBodies()
6769
{
6770
	// first check we have any ships
6771
	if ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )
6772
		return;
6773
 
6774
	bool found = false;
6775
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6776
	{
6777
		SGameShip *s = node->Data();
6778
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6779
			continue;
6780
 
6781
		// no dummies to add?
6782
		if ( !s->pPackage->AnyBodies() )
6783
			continue;
6784
		found = true;
6785
		break;
6786
	}
6787
 
6788
	if ( !found )
6789
		return;
6790
 
6791
	// lets read our current bodies file
6792
	CLinkList<SBodies> bodiesList;
6793
	SBodies *currentSection = NULL;
6794
	int e = ExtractGameFile("types/Bodies.pck", m_sTempDir + "/Bodies.txt");
6795
	if ( e )
6796
	{
6797
		CFileIO File;
118 cycrow 6798
		if ( File.open((e == -1) ? "Bodies.txt" : m_sTempDir + "/Bodies.txt") )
1 cycrow 6799
		{
160 cycrow 6800
			std::vector<Utils::String> *lines = File.readLines();
1 cycrow 6801
			if ( lines )
6802
			{
6803
				int entries = 0;
6804
				for ( int j = 0; j < (int)lines->size(); j++ )
6805
				{
160 cycrow 6806
					Utils::String line(lines->at(j));
6807
					line.removeChar(' ');
6808
					line.removeChar(9);
6809
					if ( line.empty() || line[0] == '/' )
1 cycrow 6810
						continue;
6811
					if ( entries <= 0 )
6812
					{
160 cycrow 6813
						entries = line.token(";", 2).toInt();
1 cycrow 6814
						currentSection = new SBodies;
160 cycrow 6815
						currentSection->sSection = line.token(";", 1);
1 cycrow 6816
						bodiesList.push_back(currentSection);
6817
					}
6818
					else if ( currentSection )
6819
					{
6820
						int num;
160 cycrow 6821
						Utils::String *strs = line.tokenise(";", &num);
1 cycrow 6822
						if ( num && strs )
6823
						{
6824
							for ( int i = 0; i < num; i++ )
6825
							{
160 cycrow 6826
								if ( strs[i].empty() )
1 cycrow 6827
									continue;
160 cycrow 6828
								if(!currentSection->lEntries.contains(strs[i] + ";"))
6829
									currentSection->lEntries.pushBack(strs[i] + ";");
1 cycrow 6830
								--entries;
6831
							}
6832
						}
6833
						CLEANSPLIT(strs, num);
6834
					}
6835
				}
6836
 
6837
				delete lines;
6838
			}
52 cycrow 6839
			File.remove();
1 cycrow 6840
		}
6841
	}
6842
 
6843
	// lets now add any new entries
6844
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6845
	{
6846
		SGameShip *s = node->Data();
6847
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6848
			continue;
6849
 
6850
		// no dummies to add?
6851
		if ( !s->pPackage->AnyBodies() )
6852
			continue;
6853
 
6854
		// add each dummy to list
6855
		for ( SStringList *strNode = s->pPackage->GetBodies()->Head(); strNode; strNode = strNode->next )
6856
		{
6857
			CyString section = strNode->str.GetToken(";", 1, 1);
6858
			CyString body = strNode->str.GetToken(";", 2).Remove(' ');
6859
			if ( body.Right(1) != ";" )
6860
				body += ";";
6861
 
6862
			// find the section to add into
6863
			SBodies *foundSection = NULL;
6864
			for ( CListNode<SBodies> *checkBody = bodiesList.Front(); checkBody; checkBody = checkBody->next() )
6865
			{
160 cycrow 6866
				if ( checkBody->Data()->sSection.Compare(section.ToString()))
1 cycrow 6867
				{
6868
					foundSection = checkBody->Data();
6869
					break;
6870
				}
6871
			}
6872
 
6873
			if ( !foundSection )
6874
			{
6875
				foundSection = new SBodies;
160 cycrow 6876
				foundSection->sSection = section.ToString();
1 cycrow 6877
				bodiesList.push_back(foundSection);
6878
			}
160 cycrow 6879
			if(!foundSection->lEntries.contains(body.ToString()))
6880
				foundSection->lEntries.pushBack(body.ToString());
1 cycrow 6881
		}
6882
	}
6883
 
6884
	// now write the file
160 cycrow 6885
	std::vector<Utils::String> writeList;
1 cycrow 6886
	// the header first
160 cycrow 6887
	writeList.push_back("// Bodies file, created by SPK Libraries V" + Utils::String::FromFloat(GetLibraryVersion(), 2));
6888
	writeList.push_back("//body type;num bodies;");
6889
	writeList.push_back("//[body id/name]");
1 cycrow 6890
 
6891
	// now our sections
6892
	for ( SBodies *bSection = bodiesList.First(); bSection; bSection = bodiesList.Next() )
6893
	{
160 cycrow 6894
		writeList.push_back("");
6895
		writeList.push_back("// Section: " + bSection->sSection);
6896
		writeList.push_back(bSection->sSection + ";" + Utils::String::Number(bSection->lEntries.size()) + ";");
6897
		for(auto itr = bSection->lEntries.begin(); itr != bSection->lEntries.end(); itr++)
1 cycrow 6898
		{
160 cycrow 6899
			Utils::String str = (*itr)->str;
6900
			str.removeChar(9);
6901
			str.removeChar(' ');
6902
			if ( str.right(1) != ";" )
1 cycrow 6903
				str += ";";
160 cycrow 6904
			writeList.push_back(str);
1 cycrow 6905
		}
6906
	}
6907
 
6908
	// write the file to disk
6909
	CFileIO WriteFile(m_sTempDir + "/Bodies.txt");
160 cycrow 6910
	if ( WriteFile.writeFile(&writeList) )
1 cycrow 6911
	{
6912
		this->PackFile(&WriteFile, "types\\Bodies.pck");
52 cycrow 6913
		WriteFile.remove();
1 cycrow 6914
	}
6915
}
6916
 
6917
void CPackages::CreateCustomStarts()
6918
{
6919
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
6920
	{
6921
		// find all spk files (only ones that can be custom starts
6922
		if ( node->Data()->GetType() != TYPE_SPK )
6923
			continue;
6924
 
6925
		CSpkFile *p = (CSpkFile *)node->Data();
6926
 
6927
		// only use custom starts
6928
		if ( !p->IsCustomStart() )
6929
			continue;
6930
 
6931
		// get the name of the start to use
6932
		CyString name = p->GetCustomStartName();
6933
		if ( name.Empty() )
6934
			continue;
6935
 
6936
		// find if maps file exists
6937
		CyStringList createFiles;
6938
		createFiles.PushBack(name, "maps/x3_universe");
6939
		createFiles.PushBack(name, "types/Jobs");
6940
		createFiles.PushBack(name, "types/JobWings");
6941
 
6942
		for ( SStringList *str = createFiles.Head(); str; str = str->next )
6943
		{
102 cycrow 6944
			Utils::String dir = CFileIO(str->data).dir();
1 cycrow 6945
			int type = FILETYPE_EXTRA;
6946
			if ( dir.Compare("maps") )
6947
				type = FILETYPE_MAP;
6948
 
6949
			if ( !p->FindFile(str->str + ".xml", type) && !p->FindFile(str->str + ".pck", type) )
6950
			{
6951
				// create a maps files
118 cycrow 6952
				int e = this->ExtractGameFile(str->data + ".pck", m_sTempDir + "/" + str->data.ToString() + ".pck");
1 cycrow 6953
				if ( e )
6954
				{
118 cycrow 6955
					CFileIO File((e == -1) ? (str->data + ".pck") : (m_sTempDir + "/" + str->data.ToString() + ".pck"));
52 cycrow 6956
					if ( File.exists() )
1 cycrow 6957
					{
158 cycrow 6958
						File.Rename(m_sCurrentDir + "/" + dir + "/" + str->str.ToString() + ".pck");
102 cycrow 6959
						this->AddCreatedFile(dir + "/" + str->str.ToString() + ".pck");
1 cycrow 6960
					}
6961
				}
6962
			}
6963
		}
6964
	}
6965
}
6966
 
160 cycrow 6967
void CPackages::AddCreatedFile(CyString sFile)
1 cycrow 6968
{
160 cycrow 6969
	Utils::String file = sFile.ToString();
6970
	file = file.findRemove(m_sCurrentDir);
1 cycrow 6971
	while ( file[0] == '/' )
160 cycrow 6972
		file.erase(0, 1);
1 cycrow 6973
	while ( file[0] == '\\' )
160 cycrow 6974
		file.erase(0, 1);
1 cycrow 6975
 
160 cycrow 6976
	if(!m_lCreatedFiles.contains(file, true))
6977
		m_lCreatedFiles.pushBack(file);
1 cycrow 6978
}
6979
 
6980
void CPackages::CreateComponants()
6981
{
6982
	// first check we have any ships
6983
	if ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )
6984
		return;
6985
 
6986
	CLinkList<SComponantEntry> dummyList;
6987
 
6988
	// now extract the existing dummies
6989
	int e = ExtractGameFile("types/Components.pck", m_sTempDir + "/Components.txt");
6990
	if ( e )
6991
	{
6992
		// read the dummies
6993
		CFileIO File;
118 cycrow 6994
		if ( File.open((e == -1) ? "Components.txt" : m_sTempDir + "/Components.txt") )
1 cycrow 6995
		{
160 cycrow 6996
			std::vector<Utils::String> *lines = File.readLines();
1 cycrow 6997
			if ( lines )
6998
			{
6999
				int insection = 0;
7000
				int insubsection = 0;
7001
				SComponantEntry *currentSection = NULL;
7002
				SComponantEntry2 *currentSubSection = NULL;
7003
				for ( int j = 0; j < (int)lines->size(); j++ )
7004
				{
160 cycrow 7005
					Utils::String line(lines->at(j));
1 cycrow 7006
					if ( line[0] == '/' )
7007
						continue;
160 cycrow 7008
					line.removeChar('\r');
7009
					line = line.removeFirstSpace();
7010
					line = line.removeEndSpace();
7011
					if ( line.empty() )
1 cycrow 7012
						continue;
7013
 
7014
 
7015
					// read the section, first entry is section, second is size
160 cycrow 7016
					while ( !line.empty() )
1 cycrow 7017
					{
160 cycrow 7018
						line = line.removeFirstSpace();
7019
						if ( line.empty() )
1 cycrow 7020
							break;
7021
 
7022
						if ( !insection && !insubsection )
7023
						{
160 cycrow 7024
							Utils::String section = line.token(";", 1);
7025
							insection = line.token(";", 2).toInt();
1 cycrow 7026
 
7027
							// search for the sections
7028
							currentSection = NULL;
7029
							for ( CListNode<SComponantEntry> *node = dummyList.Front(); node; node = node->next() )
7030
							{
7031
								SComponantEntry *d = node->Data();
160 cycrow 7032
								if ( d->sSection.Compare(CyString(section)) )
1 cycrow 7033
								{
7034
									currentSection = node->Data();
7035
									break;
7036
								}
7037
							}
7038
 
7039
							if ( !currentSection )
7040
							{
7041
								currentSection = new SComponantEntry;
7042
								currentSection->sSection = section;
7043
								dummyList.push_back(currentSection);
7044
							}
7045
 
7046
							// we have some more ?
160 cycrow 7047
							line = line.remTokens(";", 1, 2);
1 cycrow 7048
						}
7049
						else if ( !insubsection )
7050
						{
7051
							--insection;
160 cycrow 7052
							Utils::String section = line.token(";", 1);
7053
							insubsection = line.token(";", 2).toInt();
1 cycrow 7054
 
7055
							currentSubSection = new SComponantEntry2;
7056
							currentSubSection->sSection = section;
7057
							currentSection->lEntries.push_back(currentSubSection);
7058
 
160 cycrow 7059
							line = line.remTokens(";", 1, 2);
1 cycrow 7060
						}
7061
						else
7062
						{
7063
							--insubsection;
160 cycrow 7064
							currentSubSection->lEntries.PushBack(CyString(line.remove(' ')), true);
1 cycrow 7065
							line = "";
7066
						}
7067
					}
7068
				}
7069
 
7070
				delete lines;
7071
			}
7072
 
52 cycrow 7073
			File.remove();
1 cycrow 7074
		}
7075
 
7076
		// add the new entries for the ships
7077
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7078
		{
7079
			SGameShip *s = node->Data();
7080
			if ( s->iType != WARETYPE_ADDED || !s->pPackage )
7081
				continue;
7082
 
7083
			// no dummies to add?
7084
			if ( !s->pPackage->AnyComponents() )
7085
				continue;
7086
 
7087
			// add each dummy to list
7088
			for ( CListNode<SComponent> *dNode = s->pPackage->GetComponents()->Front(); dNode; dNode = dNode->next() )
7089
			{
7090
				SComponent *dummy = dNode->Data();
7091
				SComponantEntry *found = NULL;
7092
				SComponantEntry2 *found2 = NULL;
7093
				for ( CListNode<SComponantEntry> *eNode = dummyList.Front(); eNode; eNode = eNode->next() )
7094
				{
39 cycrow 7095
					if ( eNode->Data()->sSection.Compare(CyString(dummy->sSection)) )
1 cycrow 7096
					{
7097
						found = eNode->Data();
7098
						break;
7099
					}
7100
				}
7101
				if ( !found )
7102
				{
7103
					found = new SComponantEntry;
7104
					found->sSection = dummy->sSection;
7105
					dummyList.push_back(found);
7106
					found2 = new SComponantEntry2;
7107
					found2->sSection = dummy->sSection2;
7108
					found->lEntries.push_back(found2);
7109
				}
7110
				// else check for the 2nd section
7111
				else
7112
				{
7113
					for ( CListNode<SComponantEntry2> *cNode = found->lEntries.Front(); cNode; cNode = cNode->next() )
7114
					{
39 cycrow 7115
						if ( cNode->Data()->sSection.Compare(CyString(dummy->sSection2)) )
1 cycrow 7116
						{
7117
							found2 = cNode->Data();
7118
							break;
7119
						}
7120
					}
7121
 
7122
					if ( !found2 )
7123
					{
7124
						found2 = new SComponantEntry2;
7125
						found2->sSection = dummy->sSection2;
7126
						found->lEntries.push_back(found2);
7127
					}
7128
					else
7129
					{
7130
						bool f = false;
7131
						for ( SStringList *strNode = found2->lEntries.Head(); strNode; strNode = strNode->next )
7132
						{
39 cycrow 7133
							if ( dummy->sData.remove(' ').Compare(strNode->str.ToString()) )
1 cycrow 7134
							{
7135
								f = true;
7136
								break;
7137
							}
7138
						}
7139
 
7140
						if ( f )
7141
							continue;
7142
					}
7143
				}
7144
 
39 cycrow 7145
				found2->lEntries.PushBack(CyString(dummy->sData.remove(' ')));
1 cycrow 7146
			}
7147
		}
7148
 
7149
		// finally, write the file
160 cycrow 7150
		std::vector<Utils::String> lines;
7151
		lines.push_back("// Components file, created by SPK Libraries V" + Utils::String::FromFloat(GetLibraryVersion(), 2));
1 cycrow 7152
		for ( SComponantEntry *dummy = dummyList.First(); dummy; dummy = dummyList.Next() )
7153
		{
7154
			lines.push_back("");
160 cycrow 7155
			lines.push_back("// Section: " + dummy->sSection.ToString() + " Entries: " + Utils::String::Number((long)dummy->lEntries.size()));
7156
			lines.push_back(dummy->sSection.ToString() + ";" + Utils::String::Number(dummy->lEntries.size()) + ";");
1 cycrow 7157
			for ( CListNode<SComponantEntry2> *comp = dummy->lEntries.Front(); comp; comp = comp->next() )
7158
			{
160 cycrow 7159
				lines.push_back(comp->Data()->sSection.ToString() + ";" + Utils::String::Number((long)comp->Data()->lEntries.Count()) + ";");
1 cycrow 7160
				for ( SStringList *str = comp->Data()->lEntries.Head(); str; str = str->next )
7161
				{
160 cycrow 7162
					Utils::String cStr = str->str.ToString();
7163
					cStr.removeEndSpace();
7164
					cStr.removeChar(9);
7165
					cStr.removeChar('\r');
7166
					if ( cStr.right(1) != ";" )
1 cycrow 7167
						cStr += ";";
7168
					lines.push_back(cStr);
7169
				}
7170
			}
7171
		}
7172
 
7173
		// write the file to disk
7174
		CFileIO WriteFile(m_sTempDir + "/Components.txt");
160 cycrow 7175
		if ( WriteFile.writeFile(&lines) )
1 cycrow 7176
		{
7177
			this->PackFile(&WriteFile, "types\\Components.pck");
52 cycrow 7178
			WriteFile.remove();
1 cycrow 7179
		}
7180
	}
7181
}
7182
 
89 cycrow 7183
bool CPackages::readWares(int iLang, CLinkList<SWareEntry> &list)
88 cycrow 7184
{
89 cycrow 7185
	if ( iLang == 0 ) iLang = m_iLanguage;
88 cycrow 7186
 
89 cycrow 7187
	Utils::String empWares = this->empWaresForGame();
7188
 
7189
	for(CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next()) {
91 cycrow 7190
		if ( !node->Data()->IsEnabled() ) continue;
89 cycrow 7191
		node->Data()->readWares(iLang, list, empWares);
88 cycrow 7192
	}
7193
 
89 cycrow 7194
	return true;
7195
}
88 cycrow 7196
 
89 cycrow 7197
bool CPackages::readCommands(int iLang, CLinkList<SCommandSlot> &list)
7198
{
7199
	if ( iLang == 0 ) iLang = m_iLanguage;
7200
 
7201
	for(CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next()) {
91 cycrow 7202
		if ( !node->Data()->IsEnabled() ) continue;
89 cycrow 7203
		node->Data()->readCommands(iLang, list);
88 cycrow 7204
	}
7205
 
89 cycrow 7206
	return true;
7207
}
88 cycrow 7208
 
89 cycrow 7209
bool CPackages::readWingCommands(int iLang, CLinkList<SCommandSlot> &list)
7210
{
7211
	if ( iLang == 0 ) iLang = m_iLanguage;
7212
 
7213
	for(CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next()) {
91 cycrow 7214
		if ( !node->Data()->IsEnabled() ) continue;
89 cycrow 7215
		node->Data()->readWingCommands(iLang, list);
7216
	}
7217
 
88 cycrow 7218
	return true;
7219
}
7220
 
7221
int CPackages::_warePriceOverride(enum WareTypes type, int pos, const Utils::String &id)
7222
{
7223
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
7224
		if ( node->Data()->type == type ) {
7225
			if ( node->Data()->type == Ware_Custom && id.Compare(node->Data()->id) ) return node->Data()->relval;
7226
			else if ( node->Data()->type != Ware_Custom && node->Data()->pos == pos ) return node->Data()->relval;
7227
		}
7228
	}
7229
	return 0;
7230
}
7231
 
7232
bool CPackages::_wareNotoOverride(enum WareTypes type, int pos, const Utils::String &id, int *noto)
7233
{
7234
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
7235
		if ( node->Data()->type == type && node->Data()->bNotority ) {
7236
			if ( node->Data()->type == Ware_Custom && !id.Compare(node->Data()->id) ) continue;
7237
			else if ( node->Data()->type != Ware_Custom && node->Data()->pos != pos ) continue;
7238
 
7239
			(*noto) = node->Data()->notority;
7240
			return true;
7241
		}
7242
	}
7243
	return false;
7244
}
7245
 
7246
void CPackages::_removeWareOverride(enum WareTypes type, int pos, const Utils::String &id)
7247
{
7248
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
7249
		if ( node->Data()->type == type ) {
7250
			if ( node->Data()->type == Ware_Custom && !id.Compare(node->Data()->id) ) continue;
7251
			else if ( node->Data()->type != Ware_Custom && node->Data()->pos != pos ) continue;
7252
			m_lWarePrices.remove(node);
7253
			break;
7254
		}
7255
	}
7256
}
7257
 
7258
int CPackages::empOveridePrice(int id)
7259
{
7260
	return _warePriceOverride(Ware_EMP, id, Utils::String::Null()); 
7261
}
7262
 
7263
bool CPackages::empOverideNoto(int id, int *noto)
7264
{
7265
	return _wareNotoOverride(Ware_EMP, id, Utils::String::Null(), noto);
7266
}
7267
 
7268
int CPackages::builtInWareOveridePrice(int id)
7269
{
7270
	return _warePriceOverride(Ware_BuiltIn, id, Utils::String::Null()); 
7271
}
7272
 
7273
bool CPackages::builtInWareOverideNoto(int id, int *noto)
7274
{
7275
	return _wareNotoOverride(Ware_BuiltIn, id, Utils::String::Null(), noto);
7276
}
7277
 
7278
int CPackages::customWareOveridePrice(const Utils::String &id)
7279
{
7280
	return _warePriceOverride(Ware_Custom, 0, id); 
7281
}
7282
 
7283
bool CPackages::customWareOverideNoto(const Utils::String &id, int *noto)
7284
{
7285
	return _wareNotoOverride(Ware_Custom, 0, id, noto);
7286
}
7287
 
7288
void CPackages::removeEmpOverride(int pos)
7289
{
7290
	_removeWareOverride(Ware_EMP, pos, Utils::String::Null());
7291
}
7292
 
7293
void CPackages::removeBuiltinWareOverride(int pos)
7294
{
7295
	_removeWareOverride(Ware_BuiltIn, pos, Utils::String::Null());
7296
}
7297
 
7298
void CPackages::removeCustomWareOverride(const Utils::String &id)
7299
{
7300
	_removeWareOverride(Ware_Custom, 0, id);
7301
}
7302
 
7303
 
1 cycrow 7304
bool CPackages::ReadGlobals(CyStringList &globals)
7305
{
7306
	int e = ExtractGameFile("types/Globals.pck", m_sTempDir);
7307
	if ( e )
7308
	{
118 cycrow 7309
		CFileIO File((e == -1) ? "Globals.txt" : m_sTempDir + "/Globals.txt");
52 cycrow 7310
		if ( File.exists() )
1 cycrow 7311
		{
7312
			CyStringList *lines = File.ReadLinesStr();
7313
			if ( lines )
7314
			{
7315
				int entries = -1;
7316
				for ( SStringList *str = lines->Head(); str; str = str->next )
7317
				{
7318
					str->str.RemoveChar('\r');
7319
					str->str.RemoveChar(9);
7320
					str->str.RemoveFirstSpace();
7321
 
7322
					if ( str->str.Empty() )
7323
						continue;
7324
					if ( str->str[0] == '/' )
7325
						continue;
7326
 
7327
					// remove comments
7328
					CyString l = str->str;
7329
					if ( l.IsIn("/") ) 
7330
						l = l.GetToken("/", 1, 1);
7331
 
7332
					if ( entries == -1 )
7333
						entries = l.GetToken(";", 1, 1).ToInt();
7334
					else
7335
						globals.PushBack(l.GetToken(";", 1, 1), l.GetToken(";", 2, 2));
7336
				}
7337
 
7338
				delete lines;
7339
 
7340
				return true;
7341
			}
7342
		}
7343
	}
7344
 
7345
	return false;
7346
}
7347
 
7348
void CPackages::CreateGlobals()
7349
{
160 cycrow 7350
	if ( m_lGlobals.empty() )
1 cycrow 7351
		return; // no global settings
7352
 
7353
	CyStringList globals;
7354
	if ( ReadGlobals(globals) )
7355
	{
7356
		// apply out settings
160 cycrow 7357
		for(auto itr = m_lGlobals.begin(); itr != m_lGlobals.end(); itr++)
1 cycrow 7358
		{
160 cycrow 7359
			SStringList *found = globals.FindString((*itr)->str);
1 cycrow 7360
			if ( found )
160 cycrow 7361
				found->data = (*itr)->data;
1 cycrow 7362
		}
7363
 
7364
		// now write it
7365
		CyStringList writeList;
7366
		for ( SStringList *str = globals.Head(); str; str = str->next )
7367
			writeList.PushBack(str->str + ";" + str->data + ";");
7368
 
7369
		// finally, write the file
7370
		writeList.PushFront(CyString::Number(writeList.Count()) + "; /globals amount", "");
7371
		writeList.PushFront(CyString("// Globals file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2), "");
7372
 
7373
		CFileIO WriteFile(m_sTempDir + "/Globals.txt");
7374
		if ( WriteFile.WriteFile(&writeList) )
7375
		{
7376
			this->PackFile(&WriteFile, "types/Globals.pck");
52 cycrow 7377
			WriteFile.remove();
1 cycrow 7378
		}
7379
	}
7380
}
7381
 
7382
void CPackages::CreateTShips()
7383
{
7384
	// no ships ?
7385
	if ( m_lGameShips.empty() )
7386
		return;
7387
 
7388
	// get the cockpit list to match with ships turrets
7389
	CyStringList Cockpits;
7390
	CyStringList *cockpitList = this->CreateCockpits();
7391
	if ( cockpitList )
7392
	{
7393
		for ( SStringList *str = cockpitList->Head(); str; str = str->next )
7394
		{
7395
			CyString id = str->str.GetToken(";", 19, 19);
7396
			Cockpits.PushBack(id);
7397
		}
7398
 
7399
		delete cockpitList;
7400
	}
7401
 
7402
	CLinkList<SGameShip> shipOverrides;
7403
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7404
	{
7405
		if ( node->Data()->iType != WARETYPE_ADDED || !node->Data()->pPackage )
7406
			continue;		
7407
		if ( !node->Data()->pPackage->IsExistingShip() )
7408
			continue;
7409
		shipOverrides.push_back(node->Data());
7410
	}
7411
 
7412
	// read the existing tships file
7413
	int e = ExtractGameFile("types/TShips.pck", m_sTempDir + "/TShips.txt");
7414
	if ( e )
7415
	{
7416
		int fileType = 51;
7417
		CyStringList tshipsList;
7418
 
7419
		// if we have no buffer, lets create one
7420
		CFileIO File;
118 cycrow 7421
		if ( File.open((e == -1) ? "TShips.txt" : m_sTempDir + "/TShips.txt") )
1 cycrow 7422
		{
7423
			int shiptext = SHIPSTARTTEXT;
7424
 
160 cycrow 7425
			std::vector<Utils::String> *lines = File.readLines();
1 cycrow 7426
			if ( lines )
7427
			{
7428
				int count = -1;
7429
				for ( int j = 0; j < (int)lines->size(); j++ )
7430
				{
160 cycrow 7431
					Utils::String line(lines->at(j));
1 cycrow 7432
					if ( line[0] == '/' )
7433
						continue;
160 cycrow 7434
					line.removeChar('\r');
7435
					line.removeChar(9);
7436
					line = line.removeFirstSpace();
7437
					line = line.removeEndSpace();
7438
					if ( line.empty() )
1 cycrow 7439
						continue;
7440
 
7441
					if ( count == -1 )
7442
					{
160 cycrow 7443
						fileType = line.token(";", 1).toInt();
7444
						count = line.token(";", 2).toInt();
1 cycrow 7445
					}
7446
					else
7447
					{
160 cycrow 7448
						if ( line.right(1) != ";" )
1 cycrow 7449
							line += ";";
7450
 
7451
						// check for any ship overrides
7452
						bool added = false;
7453
						if ( !shipOverrides.empty() )
7454
						{
7455
							CShipData shipData;
7456
							if ( shipData.ReadShipData(line) )
7457
							{
7458
								for ( CListNode<SGameShip> *node = shipOverrides.Front(); node; node = node->next() )
7459
								{
7460
									SGameShip *s = node->Data();
14 cycrow 7461
									if ( !s->pPackage->GetShipID().Compare(shipData.sID.ToString()) )
1 cycrow 7462
										continue;
7463
									s->iText = shiptext;
7464
									if ( !s->pPackage->GetOriginalDescription() )
7465
										shiptext += 2;
7466
									s->iPos = tshipsList.Count();
7467
									added = true;
39 cycrow 7468
									tshipsList.PushBack(CyString(s->pPackage->FormatShipData(&Cockpits, &s->iText, m_iGame)));
1 cycrow 7469
									shipOverrides.remove(node);
7470
									break;
7471
								}
7472
							}
7473
						}
7474
 
7475
						if ( !added )
160 cycrow 7476
							tshipsList.PushBack(CyString(line));
1 cycrow 7477
						--count;
7478
						if ( count < 0 )
7479
							break;
7480
					}
7481
				}
7482
 
7483
				delete lines;
7484
 
7485
			}
7486
 
52 cycrow 7487
			File.remove();
1 cycrow 7488
 
7489
			// assign the ship buffer
7490
			if ( !m_iShipBuffer )
7491
				m_iShipBuffer = tshipsList.Count() + 15;
7492
			// there seems to be too many additional entries, we have no choise but to change the buffer
7493
			else if ( m_iShipBuffer <= tshipsList.Count() )
7494
				m_iShipBuffer = tshipsList.Count() + 15;
7495
 
7496
			CyString bufferStart;
7497
			if ( m_iGame == GAME_X3 )
7498
				bufferStart = "0;0;0;0;0;2;499999;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0.049988;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;1;0;0;0;0;0;0;2092;1;1;-1;0;0;1;1;0;1;1;1;0;0;0;;-1;0;0;0;0;0;0;0;0;0;";
7499
			else
7500
				bufferStart = "0;0;0;0;0;SG_SH_M5;499999;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0.049988;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;1;0;0;0;0;0;0;OBJ_BEACON;1;1;-1;0;0;1;1;0;1;1;1;0;0;0;;-1;0;0;0;0;0;0;0;0;0;";
7501
			// add the buffers now
7502
			for ( int i = tshipsList.Count(); i < m_iShipBuffer; i++ )
7503
				tshipsList.PushBack(bufferStart + "SHIP_BUFFER;");
7504
 
7505
			// now lets add our tships line
7506
			for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7507
			{
7508
				SGameShip *s = node->Data();
7509
				if ( s->pPackage && s->pPackage->IsExistingShip() )
7510
					continue;
7511
				s->iPos = tshipsList.Count();
7512
				if ( s->iType == WARETYPE_ADDED && s->pPackage )
7513
				{
7514
					s->iText = shiptext;
7515
					if ( !s->pPackage->GetOriginalDescription() )
7516
						shiptext += 2;
7517
 
39 cycrow 7518
					tshipsList.PushBack(CyString(s->pPackage->FormatShipData(&Cockpits, &s->iText, m_iGame)));
1 cycrow 7519
				}
7520
				else if ( s->iType == WARETYPE_DELETED )
7521
					tshipsList.PushBack(bufferStart + "SHIP_DELETED;");
7522
				else if ( s->iType == WARETYPE_DISABLED )
7523
					tshipsList.PushBack(bufferStart + "SHIP_DISABLED;");
7524
				else
7525
					tshipsList.PushBack(bufferStart + "SHIP_SPACER;");
7526
			}
7527
 
7528
			// finally, write the file
7529
			tshipsList.PushFront(CyString::Number(fileType) + ";" + CyString::Number(tshipsList.Count()) + ";", "");
7530
			tshipsList.PushFront(CyString("// TShips file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2), "");
7531
 
7532
			CFileIO WriteFile(m_sTempDir + "/TShips.txt");
7533
			if ( WriteFile.WriteFile(&tshipsList) )
7534
			{
7535
				this->PackFile(&WriteFile, "types/TShips.pck");
52 cycrow 7536
				WriteFile.remove();
1 cycrow 7537
			}
7538
		}
7539
	}
7540
 
7541
}
7542
 
7543
bool CPackages::PackFile(CyString filename)
7544
{
7545
	// compress the file
7546
	CFileIO File(filename);
7547
	size_t fileSize;
7548
	char *fileData = File.ReadToData(&fileSize);
7549
 
7550
	if ( fileData && fileSize)
7551
	{
7552
		size_t newFileSize;
7553
		unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
7554
		if ( pckData )
7555
		{
160 cycrow 7556
			Utils::String ext = "pck";
7557
			if ( File.isFileExtension("bob") )
1 cycrow 7558
				ext = "pbb";
160 cycrow 7559
			else if ( File.isFileExtension("bod") )
1 cycrow 7560
				ext = "pbd";
160 cycrow 7561
			CFileIO pckFile(File.changeFileExtension(ext));
121 cycrow 7562
			if ( !CDirIO(pckFile.dir()).exists() )
160 cycrow 7563
				CDirIO(pckFile.dir()).create();
1 cycrow 7564
			pckFile.WriteData((char *)pckData, newFileSize);
7565
			return true;
7566
		}
7567
	}
7568
 
7569
	return false;
7570
}
7571
 
158 cycrow 7572
bool CPackages::UnPackFile(const Utils::String &filename, bool checkxml)
1 cycrow 7573
{
7574
	// compress the file
7575
	CFileIO File(filename);
7576
	size_t fileSize;
7577
	char *fileData = File.ReadToData(&fileSize);
7578
 
7579
	if ( fileData && fileSize)
7580
	{
7581
		size_t newFileSize;
96 cycrow 7582
		unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize, false);
7583
		if ( !pckData )
7584
			pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
7585
 
1 cycrow 7586
		if ( pckData )
7587
		{
160 cycrow 7588
			Utils::String ext = "txt";
7589
			if ( File.isFileExtension("pbb") )
1 cycrow 7590
				ext = "bob";
160 cycrow 7591
			else if ( File.isFileExtension("pbd") )
1 cycrow 7592
				ext = "bod";
160 cycrow 7593
			CFileIO pckFile(File.changeFileExtension(ext));
121 cycrow 7594
			if ( !CDirIO(pckFile.dir()).exists() )
160 cycrow 7595
				CDirIO(pckFile.dir()).create();
1 cycrow 7596
			pckFile.WriteData((char *)pckData, newFileSize);
7597
 
7598
			// check for xml and rename
7599
			if ( checkxml )
7600
			{
7601
				int readmaxlines = 20;
7602
				bool isxml = false;
7603
				do {
52 cycrow 7604
					CyString line = pckFile.readEndOfLine();
1 cycrow 7605
					if ( line.IsIn("<language id=") )
7606
					{
7607
						isxml = true;
7608
						break;
7609
					}
7610
					else if ( line.IsIn("<page id=") )
7611
					{
7612
						isxml = true;
7613
						break;
7614
					}
7615
					else if ( line.IsIn("<?xml") || line.IsIn("<script>") )
7616
					{
7617
						isxml = true;
7618
						break;
7619
					}
7620
					--readmaxlines;
7621
					if ( readmaxlines <= 0 )
7622
						break;
52 cycrow 7623
				} while (pckFile.isOpened());
1 cycrow 7624
 
52 cycrow 7625
				if ( pckFile.isOpened() )
82 cycrow 7626
					pckFile.close();
1 cycrow 7627
 
7628
				if ( isxml )
158 cycrow 7629
					pckFile.Rename(pckFile.changeFileExtension("xml"));
1 cycrow 7630
			}
7631
 
7632
			return true;
7633
		}
7634
	}
7635
 
7636
	return false;
7637
}
7638
 
158 cycrow 7639
bool CPackages::PackFile(CFileIO *File, CyString sFilename)
1 cycrow 7640
{
158 cycrow 7641
	Utils::String filename = sFilename.FindReplace("\\", "/").ToString();
1 cycrow 7642
	if ( m_iGame == GAME_X3 )
7643
	{
7644
		CCatFile catFile;
158 cycrow 7645
		int error = catFile.open(m_sCurrentDir + "/mods/PluginManager.cat", this->getAddonDir(), CATREAD_CATDECRYPT, true);
1 cycrow 7646
		if ( error == CATERR_NONE || error == CATERR_CREATED )
7647
		{
7648
			// it it wrote ok, remove the old ones
158 cycrow 7649
			if ( !catFile.AppendFile(File->fullFilename(), filename, true, true) )
1 cycrow 7650
				return false;
7651
			return true;
7652
		}
7653
	}
7654
	else
7655
	{
7656
		// compress the file
7657
		size_t fileSize;
102 cycrow 7658
		char *fileData = CFileIO(File->fullFilename()).ReadToData(&fileSize);
1 cycrow 7659
 
7660
		if ( fileData && fileSize)
7661
		{
7662
			size_t newFileSize;
7663
			unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
7664
			if ( pckData )
7665
			{
7666
//				if ( !this->GetAddonDir().Empty() && CCatFile::IsAddonDir(filename) )
7667
//					filename = this->GetAddonDir() + "/" + filename;
7668
				CFileIO pckFile(m_sCurrentDir + "/" + filename);
121 cycrow 7669
				if ( !CDirIO(pckFile.dir()).exists() )
160 cycrow 7670
					CDirIO(pckFile.dir()).create();
1 cycrow 7671
				pckFile.WriteData((char *)pckData, newFileSize);
102 cycrow 7672
				this->AddCreatedFile(pckFile.fullFilename());
1 cycrow 7673
				return true;
7674
			}
7675
		}
7676
	}
7677
 
7678
	return false;
7679
}
7680
 
7681
CyStringList *CPackages::CreateCockpits()
7682
{
7683
	// first check we have any ships
7684
	if ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )
7685
		return NULL;
7686
 
7687
	CyStringList *cockpitList = new CyStringList;
7688
 
7689
	// now extract the existing cockpits
7690
	int fileType = 51;
7691
	int e = ExtractGameFile("types/TCockpits.pck", m_sTempDir + "/TCockpits.txt");
7692
	if ( e )
7693
	{
7694
		// read the dummies
7695
		CFileIO File;
118 cycrow 7696
		if ( File.open((e == -1) ? "TCockpits.txt" : m_sTempDir + "/TCockpits.txt") )
1 cycrow 7697
		{
7698
			CyStringList *lines = File.ReadLinesStr();
7699
			if ( lines )
7700
			{
7701
				int count = -1;
7702
				for ( SStringList *str = lines->Head(); str; str = str->next )
7703
				{
7704
					CyString line(str->str);
7705
					line.RemoveChar('\r');
7706
					line.RemoveChar(9);
7707
					line = line.RemoveFirstSpace();
7708
					line = line.RemoveEndSpace();
7709
					if ( line.Empty() )
7710
						continue;
7711
					if ( line[0] == '/' )
7712
						continue;
7713
 
7714
					if ( count == -1 )
7715
					{
7716
						fileType = line.GetToken(";", 1, 1).ToInt();
7717
						count = line.GetToken(";", 2, 2).ToInt();
7718
					}
7719
					else
7720
					{
7721
						while ( !line.Empty() )
7722
						{
7723
							CyString data = line.GetToken(";", 1, 19);
7724
							cockpitList->PushBack(data + ";");
7725
							line = line.DelToken(";", 1, 19);
7726
 
7727
							--count;
7728
							if ( count < 1 )
7729
								break;
7730
						}
7731
					}
7732
				}
7733
 
7734
				delete lines;
7735
			}
7736
 
52 cycrow 7737
			File.remove();
1 cycrow 7738
		}
7739
 
7740
		// now add the new ones
7741
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7742
		{
7743
			SGameShip *s = node->Data();
7744
			if ( s->iType != WARETYPE_ADDED || !s->pPackage )
7745
				continue;
7746
 
7747
			if ( !s->pPackage->AnyCockpits() )
7748
				continue;
7749
 
7750
			for ( CListNode<SCockpit> *cn = s->pPackage->GetCockpits()->Front(); cn; cn = cn->next() )
7751
			{
7752
				bool foundEntry = false;
7753
				CyString cockpitStr = cn->Data()->sCockpit;
7754
				// search for matching game entry
7755
				for ( CListNode<SWeaponMask> *wm = cn->Data()->lWeaponMask.Front(); wm; wm = wm->next() )
7756
				{
7757
					if ( wm->Data()->iGame == (m_iGame - 1) )
7758
					{
7759
						if ( wm->Data()->iMask != -1 )
7760
							cockpitStr = cockpitStr.RepToken(";", 9, CyString::Number(wm->Data()->iMask));
7761
						foundEntry = true;
7762
						break;
7763
					}
7764
				}
39 cycrow 7765
 
7766
				bool found = false;
1 cycrow 7767
				for ( SStringList *str = cockpitList->Head(); str; str = str->next )
7768
				{
39 cycrow 7769
					if ( str->str.GetToken(";", 19, 19).Compare(CyString(cn->Data()->sCockpit.token(";", 19))) )
1 cycrow 7770
					{
7771
						// only replace existing entry if we have sepeperate weapon masks set
7772
						if ( foundEntry )
7773
							str->str = cockpitStr;
7774
						found = true;
7775
						break;
7776
					}
7777
				}
7778
 
7779
				if ( !found )
7780
					cockpitList->PushBack(cockpitStr);
7781
			}
7782
		}
7783
 
7784
		// finally, write the file
7785
		cockpitList->PushFront(CyString::Number(fileType) + ";" + CyString::Number(cockpitList->Count()) + ";", "");
7786
		cockpitList->PushFront(CyString("// TCockpits file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2), "");
7787
 
7788
		CFileIO WriteFile(m_sTempDir + "/TCockpits.txt");
7789
		if ( WriteFile.WriteFile(cockpitList) )
7790
		{
7791
			this->PackFile(&WriteFile, "types\\TCockpits.pck");
52 cycrow 7792
			WriteFile.remove();
1 cycrow 7793
		}
7794
 
7795
		// remove those entrys
7796
		cockpitList->PopFront();
7797
		cockpitList->PopFront();
7798
	}
7799
 
7800
	return cockpitList;
7801
}
7802
 
7803
CBaseFile *CPackages::FindScriptByAuthor(CyString author, CBaseFile *prev)
7804
{
7805
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
7806
	{
7807
		CBaseFile *p = node->Data();
7808
		if ( prev )
7809
		{
7810
			if ( p == prev )
7811
				prev = NULL;
7812
			continue;
7813
		}
50 cycrow 7814
		if ( p->author().Compare(author.ToString()) )
1 cycrow 7815
			return p;
7816
	}
7817
 
7818
	return NULL;
7819
}
7820
 
129 cycrow 7821
bool CPackages::extractAll(CBaseFile *baseFile, const Utils::String &dir, int game, bool includedir, CProgressInfo *progress) const
7822
{
7823
	if (!baseFile)
7824
		return false;
7825
 
7826
	Utils::CStringList gameAddons;
7827
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
7828
	{
7829
		SGameExe *exe = m_gameExe.GetGame(i);
7830
		if (!exe->sAddon.empty())
7831
			gameAddons.pushBack(Utils::String::Number(i + 1), exe->sAddon);
7832
	}
7833
 
7834
	return baseFile->extractAll(dir, game, gameAddons, includedir, progress);
7835
}
7836
 
127 cycrow 7837
bool CPackages::generatePackagerScript(CBaseFile *baseFile, bool wildcard, Utils::CStringList *list, int game, bool datafile) const
7838
{	
7839
	if (!baseFile)
7840
		return false;
7841
 
7842
	Utils::CStringList gameAddons;
7843
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
7844
	{
7845
		SGameExe *exe = m_gameExe.GetGame(i);
7846
		if (!exe->sAddon.empty())
7847
			gameAddons.pushBack(Utils::String::Number(i + 1), exe->sAddon);
7848
	}
7849
 
7850
	return baseFile->GeneratePackagerScript(wildcard, list, game, gameAddons, datafile);
7851
}
7852
 
134 cycrow 7853
CBaseFile *CPackages::LoadPackagerScript(const Utils::String &filename, int compression, Utils::String (*askFunc)(const Utils::String &), Utils::CStringList *malformedLines, Utils::CStringList *unknownCommands, Utils::CStringList *variables, CProgressInfo *progress)
1 cycrow 7854
{
7855
	// check the file exists
131 cycrow 7856
	if ( !CFileIO::Exists(filename) )
1 cycrow 7857
		return NULL;
7858
 
7859
	// read all the lines
7860
	CFileIO File(filename);
98 cycrow 7861
	if ( !File.startRead() ) 
1 cycrow 7862
		return NULL;
7863
 
98 cycrow 7864
	Utils::CStringList fileData;
7865
 
7866
	int iLine = 0;
7867
 
1 cycrow 7868
	CBaseFile *package = NULL;
7869
 
98 cycrow 7870
	while(!File.atEnd()) {
7871
		// read the next line in the file
7872
		Utils::String line = File.readEndOfLine();
1 cycrow 7873
 
98 cycrow 7874
		// filter out any characters we dont really want
7875
		line.removeChar("\t\r");
7876
		line.removeFirstSpace();
1 cycrow 7877
 
98 cycrow 7878
		if ( line.empty() ) continue;
1 cycrow 7879
 
98 cycrow 7880
		// check for any comments (so we can ignore them)
7881
		if ( line.left(2).Compare("//") || line[0] == '#' ) continue;
1 cycrow 7882
 
98 cycrow 7883
		++iLine;
7884
 
1 cycrow 7885
		// all commands start with a keyword followed by a colon, if one doesn't exist, it cant be a valid line
131 cycrow 7886
		if ( !line.contains(':') )
1 cycrow 7887
		{
7888
			// there are some exeptions, and these are one word entrys only
98 cycrow 7889
			line.removeEndSpace();
131 cycrow 7890
			if ( line.contains(" ") )
1 cycrow 7891
			{
7892
				if ( malformedLines )
131 cycrow 7893
					malformedLines->pushBack(line, Utils::String::Number(iLine));
1 cycrow 7894
				continue;
7895
			}
7896
		}
7897
 
7898
		// check for the type line
98 cycrow 7899
		if ( !package && line.token(":", 1).Compare("FileType") )
1 cycrow 7900
		{
98 cycrow 7901
			Utils::String sFileType = line.tokens(":", 2).removeFirstSpace();
1 cycrow 7902
			if ( sFileType.Compare("Ship") )
7903
				package = new CXspFile();
7904
			else if ( sFileType.Compare("Script") )
7905
				package = new CSpkFile();
7906
			else if ( sFileType.Compare("Base") )
7907
				package = new CBaseFile();
98 cycrow 7908
			continue;
1 cycrow 7909
		}
7910
 
98 cycrow 7911
		fileData.pushBack(line, Utils::String::Number(iLine));
1 cycrow 7912
	}
7913
 
7914
	// assume its a script if no type is set (all old versions are scripts)
7915
	if ( !package )
7916
		package = new CSpkFile();
7917
 
7918
	if ( compression != -1 )
7919
		package->SetDataCompression(compression);
7920
 
7921
	CyString ftpaddr;
7922
	CyString ftpuser;
7923
	CyString ftppass;
7924
	CyString ftpdir;
98 cycrow 7925
	Utils::String sMainGame;
7926
	Utils::CStringList otherGames;
127 cycrow 7927
	Utils::CStringList gameAddons;
7928
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
7929
	{
7930
		SGameExe *exe = m_gameExe.GetGame(i);
7931
		if (!exe->sAddon.empty())
7932
			gameAddons.pushBack(Utils::String::Number(i + 1), exe->sAddon);
7933
	}
98 cycrow 7934
 
1 cycrow 7935
	// now lets read the rest of the day
131 cycrow 7936
	Utils::CStringList listVaribles;
7937
	for (Utils::SStringList *line = fileData.first(); line; line = fileData.next())
1 cycrow 7938
	{
98 cycrow 7939
		Utils::String cmd = line->str.token(":", 1);
7940
		Utils::String rest = line->str.tokens(":", 2).removeFirstSpace();
1 cycrow 7941
 
131 cycrow 7942
		if (cmd.Compare("Varible") || cmd.Compare("Variable"))
7943
		{
7944
			Utils::String s1 = rest.token(" ", 1);
7945
			Utils::String s2 = rest.tokens(" ", 2);
7946
			if(!listVaribles.changeData(s1, s2))
7947
				listVaribles.pushBack(s1, s2);
7948
		}
1 cycrow 7949
		else
7950
		{
7951
			// replace variables
98 cycrow 7952
			if ( rest.isin("$") )
1 cycrow 7953
			{
131 cycrow 7954
				for (Utils::SStringList *strVar = listVaribles.first(); strVar; strVar = listVaribles.next())
1 cycrow 7955
				{
131 cycrow 7956
					if ( rest.contains(strVar->str) )
7957
						rest = rest.findReplace(strVar->str, strVar->data);
1 cycrow 7958
				}
7959
 
7960
				if ( variables )
7961
				{
131 cycrow 7962
					for (Utils::SStringList *strVar = variables->first(); strVar; strVar = variables->next())
1 cycrow 7963
					{
131 cycrow 7964
						if ( rest.contains(strVar->str) )
7965
							rest = rest.findReplace(strVar->str, strVar->data);
1 cycrow 7966
					}
7967
				}
7968
			}
7969
 
7970
			//check for the built in varibles
127 cycrow 7971
			if ( rest.contains("$ASK") )
1 cycrow 7972
			{
98 cycrow 7973
				Utils::String replace = "$ASK";
7974
				Utils::String result;
1 cycrow 7975
 
7976
				if ( askFunc )
127 cycrow 7977
					result = askFunc(cmd);
1 cycrow 7978
 
127 cycrow 7979
				if ( rest.contains("$ASK(") )
1 cycrow 7980
				{
98 cycrow 7981
					replace = rest.tokens("$ASK(", 2).token(")", 1);
7982
					if ( result.empty() )
1 cycrow 7983
						result = replace;
98 cycrow 7984
					replace = "$ASK(" + replace + ")";
1 cycrow 7985
				}
7986
 
98 cycrow 7987
				if ( !result.empty() )
7988
					rest = rest.findReplace(replace, result);
1 cycrow 7989
			}
7990
			// todays date
98 cycrow 7991
			if ( rest.isin("$DATE") )
1 cycrow 7992
			{
7993
				time_t now;
7994
				time(&now);
7995
				struct tm *timeinfo = localtime(&now);
98 cycrow 7996
				Utils::String result = Utils::String::Number(timeinfo->tm_mday) + "." + Utils::String::Number(timeinfo->tm_mon + 1) + "." + Utils::String::Number(timeinfo->tm_year + 1900);
7997
				if ( !result.empty() )
7998
					rest = rest.findReplace("$DATE", result);
1 cycrow 7999
			}
8000
			// mydocuments
98 cycrow 8001
			if ( rest.isin("$MYDOCUMENTS") )
1 cycrow 8002
			{
127 cycrow 8003
				if ( !m_sMyDoc.empty() )
8004
					rest = rest.findReplace("$MYDOCUMENTS", m_sMyDoc);
1 cycrow 8005
			}
8006
 
8007
			// current path
98 cycrow 8008
			if ( rest.isin("$PATH") )
1 cycrow 8009
			{
102 cycrow 8010
				Utils::String currentDir = CFileIO(filename).dir();
98 cycrow 8011
				if ( !currentDir.empty() )
8012
					rest = rest.findReplace("$PATH", currentDir);
1 cycrow 8013
			}
8014
 
8015
			// now parse the rest of the values
98 cycrow 8016
			if ( cmd.Compare("FtpUpload") )
8017
				ftpaddr = rest.token(" ", 1) + ":" + rest.token(" ", 2);
8018
			else if ( cmd.Compare("FtpUser") )
1 cycrow 8019
				ftpuser = rest;
98 cycrow 8020
			else if ( cmd.Compare("FtpPass") )
1 cycrow 8021
				ftppass = rest;
98 cycrow 8022
			else if ( cmd.Compare("FtpDir") )
1 cycrow 8023
				ftpdir = rest;
98 cycrow 8024
			else if ( cmd.Compare("MultiGames") ) {
8025
				sMainGame = rest.token(" ", 1);
8026
				otherGames.tokenise(rest.tokens(" ", 2), " ");
8027
			}
134 cycrow 8028
			else if ( !package->LoadPackageData(cmd, rest, sMainGame, otherGames, gameAddons, progress) )
1 cycrow 8029
			{
8030
				if ( unknownCommands )
131 cycrow 8031
					unknownCommands->pushBack(cmd, rest);
1 cycrow 8032
			}
8033
		}
8034
	}
8035
 
50 cycrow 8036
	if ( package->filename().empty() )
134 cycrow 8037
		package->LoadPackageData("AutoSave", "$AUTOSAVE", sMainGame, otherGames, gameAddons, progress);
1 cycrow 8038
 
131 cycrow 8039
	if (package->autoExtraction())
8040
	{
8041
		for (auto itr = package->autoExtraction()->begin(); itr != package->autoExtraction()->end(); itr++)
8042
		{
8043
			unsigned int game = itr->first;
8044
			for (auto node = package->fileList()->Front(); node; node = node->next())
8045
			{
8046
				C_File *f = node->Data();
8047
				if (f->game() && f->game() != GAME_ALLNEW && !(f->game() & (1 << game)))
8048
					continue;
8049
				package->extractFile(f, itr->second, game, gameAddons);
8050
			}
8051
		}
8052
	}
8053
 
8054
	if (package->autoExporter())
8055
	{
8056
		for (auto itr = package->autoExporter()->begin(); itr != package->autoExporter()->end(); itr++)
8057
			package->saveToArchive(itr->second, itr->first, &m_gameExe);
8058
	}
8059
 
1 cycrow 8060
	if ( !ftpaddr.Empty() )
8061
	{
8062
		if ( !ftpuser.Empty() )
8063
		{
8064
			if ( !ftppass.Empty() )
8065
				ftpaddr = ftpuser + ":" + ftppass + "@" + ftpaddr;
8066
			else
8067
				ftpaddr = ftpuser + "@" + ftpaddr;
8068
		}
8069
 
8070
		if ( !ftpdir.Empty() )
8071
			ftpaddr += ftpdir;
8072
 
8073
		package->SetFtpAddr(ftpaddr);
8074
	}
8075
 
8076
	return package;
8077
}
8078
 
121 cycrow 8079
CyString CPackages::GetLanguageName() const
1 cycrow 8080
{
8081
	return CPackages::ConvertLanguage(m_iLanguage);
8082
}
8083
 
133 cycrow 8084
int CPackages::findAllPackages(CLinkList<CBaseFile> &packages, const Utils::String &dir)
8085
{
8086
	int count = 0;
8087
	if (!dir.empty())
8088
	{
8089
		count += findPackageDirectories(packages, dir + "/Addons");
8090
		count += findPackageDirectories(packages, dir + "/Downloads");
8091
	}
8092
 
8093
	count += findPackageDirectories(packages, "./Addons");
8094
	count += findPackageDirectories(packages, "./Downloads");
8095
 
8096
	if (_pCurrentDir)
8097
	{
8098
		count += findPackageDirectories(packages, _pCurrentDir->dir + "/Addons");
8099
		count += findPackageDirectories(packages, _pCurrentDir->dir + "/Downloads");
8100
		count += findPackageDirectories(packages, _pCurrentDir->dir + "/ExtraContent");
8101
	}
8102
 
8103
	return count;
8104
}
8105
int CPackages::findPackageDirectories(CLinkList<CBaseFile> &packages, const Utils::String &dir)
8106
{
8107
	CDirIO Dir(dir);
8108
	int count = 0;
8109
	Utils::CStringList files;
8110
	if (Dir.dirList(files))
8111
	{
8112
		for (auto itr = files.begin(); itr != files.end(); itr++)
8113
		{
8114
			Utils::String d = Dir.file((*itr)->str);
8115
			if (CDirIO(d).isDir())
8116
				count += findPackageDirectories(packages, d);
8117
		}
8118
	}
8119
 
8120
	count += findPackageFiles(packages, dir);
8121
	return count;
8122
}
8123
int CPackages::findPackageFiles(CLinkList<CBaseFile> &packages, const Utils::String &dir)
8124
{
8125
	CDirIO Dir(dir);
8126
	int count = 0;
8127
	for (int type = 0; type < 2; type++)
8128
	{
8129
		Utils::CStringList files;
8130
		if (type == 0)
8131
			Dir.dirList(files, Utils::String::Null(), "*.spk");
8132
		else if(type == 1)
8133
			Dir.dirList(files, Utils::String::Null(), "*.xsp");
8134
		else
8135
			break;
8136
 
8137
		for(auto itr = files.begin(); itr != files.end(); itr++)
8138
		{
8139
			Utils::String f = Dir.file((*itr)->str);
8140
			int error = 0;
8141
			CBaseFile *p = this->OpenPackage(f, &error, 0, SPKREAD_NODATA, READFLAG_NOUNCOMPRESS);
8142
			if (!p)
8143
				continue;
8144
			if (p->IsMod() || this->FindSpkPackage(p->name(), p->author()))
8145
			{
8146
				delete p;
8147
				continue;
8148
			}
8149
 
8150
			// check its for the correct game
8151
			if (!p->CheckGameCompatability(this->GetGame()))
8152
			{
8153
				delete p;
8154
				continue;
8155
			}
8156
 
8157
			// check if its already on the list
8158
			bool found = false;
8159
			for (CBaseFile *checkp = packages.First(); checkp; checkp = packages.Next())
8160
			{
8161
				if (p->name().Compare(checkp->name()) && p->author().Compare(checkp->author()))
8162
				{
8163
					found = true;
8164
					break;
8165
				}
8166
			}
8167
 
8168
			if (found)
8169
			{
8170
				delete p;
8171
				continue;
8172
			}
8173
 
8174
			if (p->GetIcon())
8175
			{
8176
				bool addedIcon = false;
8177
				p->ReadIconFileToMemory();
158 cycrow 8178
				p->GetIcon()->setFilename(this->tempDirectory().findReplace("\\", "/") + "/" + p->author() + "_" + p->name() + "." + p->iconExt());
8179
				p->GetIcon()->setFullDir(this->tempDirectory());
133 cycrow 8180
				if (p->GetIcon()->UncompressData())
8181
				{
8182
					if (p->GetIcon()->writeFilePointer())
8183
						addedIcon = true;
8184
				}
8185
 
8186
				if (!addedIcon)
8187
					p->SetIcon(NULL, "");
8188
			}
8189
 
8190
			// get an advert to display
8191
			if (p->GetFirstFile(FILETYPE_ADVERT))
8192
			{
8193
				bool done = false;
8194
				C_File *f = p->GetFirstFile(FILETYPE_ADVERT);
8195
				if (p->ReadFileToMemory(f))
8196
				{
8197
					f->SetFullDir(this->tempDirectory());
8198
					if (f->UncompressData())
8199
					{
8200
						if (f->writeFilePointer())
8201
							done = true;
8202
					}
8203
				}
8204
 
8205
				if (!done)
8206
					f->DeleteData();
8207
			}
8208
 
8209
			packages.push_back(p);
8210
			++count;
8211
		}
8212
	}
8213
 
8214
	return count;
8215
}
8216
 
121 cycrow 8217
Utils::String CPackages::ConvertLanguage(int lang)
1 cycrow 8218
{
8219
	switch ( lang )
8220
	{
8221
		case 44:
8222
			return "English";
8223
		case 49:
8224
			return "German";
8225
		case 7:
8226
			return "Russian";
8227
		case 33:
8228
			return "French";
8229
		case 30:
8230
			return "Greek";
8231
		case 31:
8232
			return "Dutch";
8233
		case 32:
8234
			return "Belgian";
8235
		case 34:
8236
			return "Spanish";
8237
		case 36:
8238
			return "Hungarian";
8239
		case 39:
8240
			return "Italian";
8241
		case 40:
8242
			return "Romanian";
8243
		case 41:
8244
			return "Swiss";
8245
		case 42:
8246
			return "Czech";
8247
		case 43:
8248
			return "Austrian";
8249
		case 45:
8250
			return "Danish";
8251
		case 46:
8252
			return "Swedish";
8253
		case 47:
8254
			return "Norweigen";
8255
		case 48:
8256
			return "Polish";
8257
	}
8258
 
121 cycrow 8259
	return Utils::String::Number(lang);
1 cycrow 8260
}
8261
 
8262
bool CPackages::CheckAccessRights(CyString dir)
8263
{
8264
	if ( dir.Empty() )
8265
		dir = m_sCurrentDir;
8266
 
8267
	// write a file, then read the contents
8268
	CFileIO File(dir + "/accessrightscheck.dat");
8269
 
8270
	// check if file exists and remove it
52 cycrow 8271
	if ( File.exists() )
1 cycrow 8272
	{
8273
		// if we cant remove it, we dont have enough rights
52 cycrow 8274
		if ( !File.remove() )
1 cycrow 8275
			return false;
8276
 
8277
		// if its still there, we dont have enough rights
52 cycrow 8278
		if ( File.exists() )
1 cycrow 8279
			return false;
8280
	}
8281
 
8282
	// now create the file
82 cycrow 8283
	if ( !File.writeString("testing access rights") )
1 cycrow 8284
		return false;
8285
 
8286
	// now check it exists
52 cycrow 8287
	if ( !File.exists() )
1 cycrow 8288
		return false;
8289
 
8290
	// now read the file for the correct contents
8291
	CyStringList *lines = File.ReadLinesStr();
8292
	if ( !lines )
8293
		return false;
8294
 
8295
	// check that one of the lines is correct
8296
	for ( SStringList *s = lines->Head(); s; s = s->next )
8297
	{
8298
		if ( s->str == "testing access rights" )
8299
		{
8300
			delete lines;
8301
			return true;
8302
		}
8303
	}
8304
 
8305
	delete lines;
8306
 
8307
	return false;
8308
}
8309
 
8310
bool CPackages::LoadShipData(CyString file, CyStringList *list)
8311
{
8312
	CFileIO File;
8313
	bool deleteFile = false;
8314
 
8315
	// load from cat file
160 cycrow 8316
	if ( CFileIO(file).isFileExtension("cat") )
1 cycrow 8317
	{
8318
		CCatFile cat;
125 cycrow 8319
		if ( cat.open(file.ToString(), this->getAddonDir(), CATREAD_CATDECRYPT, false) != CATERR_NONE )
1 cycrow 8320
			return false;
8321
 
8322
		if ( !cat.ExtractFile("types\\TShips.pck", m_sTempDir + "/tships.txt") )
8323
			return false;
8324
 
118 cycrow 8325
		File.open(m_sTempDir + "/tships.txt");
1 cycrow 8326
		deleteFile = true;
8327
	}
8328
	// otherwise its a normal file
160 cycrow 8329
	else if ( CFileIO(file).isFileExtension("pck") )
1 cycrow 8330
	{
127 cycrow 8331
		C_File f(file.ToString());
1 cycrow 8332
		if ( !f.ReadFromFile() )
8333
			return false;
8334
		f.UnPCKFile();
8335
 
8336
		f.SetFilename(m_sTempDir + "/tships.txt");
129 cycrow 8337
		if ( !f.writeFilePointer() )
1 cycrow 8338
			return false;
8339
 
118 cycrow 8340
		File.open(m_sTempDir + "/tships.txt");
1 cycrow 8341
		deleteFile = true;
8342
	}
8343
	else
118 cycrow 8344
		File.open(file.ToString());
1 cycrow 8345
 
52 cycrow 8346
	if ( !File.exists() )
1 cycrow 8347
		return false;
8348
 
8349
	bool ret = false;
8350
	CyStringList *lines = File.ReadLinesStr();
8351
	if ( lines )
8352
	{
8353
		bool readFirst = false;
8354
		for ( SStringList *str = lines->Head(); str; str = str->next )
8355
		{
8356
			if ( str->str.Empty() )
8357
				continue;
8358
			str->str.RemoveChar('\r');
8359
			str->str.RemoveChar(9);
8360
			str->str.RemoveFirstSpace();
8361
			if ( str->str.Empty() )
8362
				continue;
8363
			if ( str->str[0] == '/' || str->str[0] == '#' )
8364
				continue;
8365
 
8366
			if ( !readFirst )
8367
				readFirst = true;
8368
			else
8369
			{
8370
				CyString t = str->str.GetToken(";", -2);
8371
				while ( t.Right(1) == ";" )
8372
					t.Truncate((int)t.Length() - 1);
8373
				list->PushBack(t, str->str);
8374
			}
8375
		}
8376
 
8377
		delete lines;
8378
		ret = true;
8379
	}
8380
 
8381
	if ( deleteFile )
52 cycrow 8382
		File.remove();
1 cycrow 8383
 
8384
	return ret;
8385
}
8386
 
8387
CyString CPackages::ReadShipData(CyString file, CyString id)
8388
{
8389
	CyStringList *list = this->LoadShipData(file);
8390
	if ( !list )
8391
		return NullString;
8392
 
8393
	CShipData data;
8394
	for ( SStringList *str = list->Head(); str; str = str->next )
8395
	{
8396
		if ( str->str.Compare(id) )
8397
		{
8398
			delete list;
8399
			return str->data;
8400
		}
8401
	}
8402
 
8403
	delete list;
8404
	return NullString;
8405
}
8406
 
8407
CyStringList *CPackages::LoadShipData(CyString file)
8408
{
8409
	CyStringList *list = new CyStringList;
8410
	if ( this->LoadShipData(file, list) )
8411
		return list;
8412
 
8413
	delete list;
8414
	return NULL;
8415
}
8416
 
8417
bool CPackages::ReadTextPage(CyString file, CyStringList *list, bool search, int page)
8418
{
8419
	CFileIO File;
8420
	bool deleteFile = false;
8421
 
8422
	// read all text files from mod
160 cycrow 8423
	if ( CFileIO(file).isFileExtension("cat") )
1 cycrow 8424
	{
8425
		bool done = false;
8426
 
8427
		CCatFile cat;
125 cycrow 8428
		if ( cat.open(file.ToString(), this->getAddonDir(), CATREAD_CATDECRYPT, false) != CATERR_NONE )
1 cycrow 8429
			return false;
8430
 
8431
		// extract 1 at a time
124 cycrow 8432
		for (unsigned int i = 0; i < cat.GetNumFiles(); i++ )
1 cycrow 8433
		{
8434
			SInCatFile *f = cat.GetFile(i);
8435
			CyString sF = f->sFile;
8436
			// is a text file
8437
			sF = sF.FindReplace("\\", "/");
8438
			if ( !sF.GetToken("/", 1, 1).Compare("t") )
8439
				continue;
8440
 
57 cycrow 8441
			CyString baseFile = CFileIO(sF.ToString()).baseName();
1 cycrow 8442
			// check language
8443
			int lang = 0;
8444
			if ( baseFile.FindPos("-L") != -1 ) // new language file
8445
				lang = baseFile.Right(3).ToInt();
8446
			else
8447
			{
8448
				baseFile.Truncate((int)baseFile.Length() - 4);
8449
				lang = baseFile.ToInt();
8450
			}
8451
 
8452
			if ( lang != m_iLanguage )
8453
				continue;
8454
 
8455
			// now extract and parse
57 cycrow 8456
			if ( cat.ExtractFile(f->sFile, m_sTempDir + "/" + CFileIO(f->sFile).baseName() + ".xml") )
1 cycrow 8457
			{
57 cycrow 8458
				if ( this->ReadTextPage(m_sTempDir + "/" + CFileIO(f->sFile).baseName() + ".xml", list, search, page) )
1 cycrow 8459
					done = true;
8460
			}
8461
		}
8462
 
8463
		return done;
8464
	}
8465
	// otherwise its a normal file
160 cycrow 8466
	else if ( CFileIO(file).isFileExtension("pck") )
1 cycrow 8467
	{
127 cycrow 8468
		C_File f(file.ToString());
1 cycrow 8469
		if ( !f.ReadFromFile() )
8470
			return false;
8471
		f.UnPCKFile();
8472
 
8473
		f.SetFilename(m_sTempDir + "/textfile.xml");
129 cycrow 8474
		if ( !f.writeFilePointer() )
1 cycrow 8475
			return false;
8476
 
118 cycrow 8477
		File.open(m_sTempDir + "/textfile.xml");
1 cycrow 8478
		deleteFile = true;
8479
	}
8480
	else
118 cycrow 8481
		File.open(file.ToString());
1 cycrow 8482
 
52 cycrow 8483
	if ( !File.exists() )
1 cycrow 8484
		return false;
8485
 
8486
	// open and read file
8487
	CyStringList *lines = File.ReadLinesStr();
8488
	if ( !lines )
8489
		return false;
8490
 
8491
	bool inPage = false;
8492
	for ( SStringList *str = lines->Head(); str; str = str->next )
8493
	{
8494
		// search for page
8495
		if ( !inPage )
8496
		{
8497
			if ( str->str.FindPos("<page") > -1 )
8498
			{
8499
				// find the page id
8500
				int pos = str->str.FindPos("\"");
8501
				if ( pos > -1 )
8502
				{
8503
					int endpos = str->str.FindPos("\"", pos + 1);
8504
					if ( endpos > -1 )
8505
					{
8506
						CyString p = str->str.Mid(pos + 2, endpos - pos - 1);
8507
						if ( p.Length() > 4 )
8508
							p = p.Right(4);
8509
						int checkPage = p.ToInt();
8510
						if ( checkPage == page )
8511
							inPage = true;
8512
					}
8513
				}
8514
			}
8515
 
8516
		}
8517
		// add each id
8518
		else
8519
		{
8520
			if ( str->str.FindPos("</page") > -1 )
8521
				break;
8522
 
8523
			if ( str->str.FindPos("<t id") > -1 )
8524
			{
8525
				int pos = str->str.FindPos("\"");
8526
				if ( pos > -1 )
8527
				{
8528
					int endpos = str->str.FindPos("\"", pos + 1);
8529
					if ( endpos > -1 )
8530
					{
8531
						int id = str->str.Mid(pos + 2, endpos - pos - 1).ToInt();
8532
						pos = str->str.FindPos(">", endpos);
8533
						if ( pos > -1 )
8534
						{
8535
							++pos;
8536
							endpos = str->str.FindPos("</", pos);
8537
							if ( endpos > -1 )
8538
							{
8539
								CyString text = str->str.Mid(pos + 1, endpos - pos);
8540
								while ( text.FindPos('(') != -1 && text.FindPos(')') != -1 )
8541
								{
8542
									int s = text.FindPos('(');
8543
									text = text.Erase(s, text.FindPos(')') - s + 1);
8544
								}
8545
								list->PushBack(CyString::Number(id), text, search);
8546
							}
8547
						}
8548
					}
8549
				}
8550
			}
8551
		}
8552
	}
8553
 
8554
	delete lines;
8555
 
8556
	return true;
8557
}
8558
 
8559
CyStringList *CPackages::ReadTextPage(CyString file, bool search, int page)
8560
{
8561
	CyStringList *list = new CyStringList;
8562
	if ( this->ReadTextPage(file, list, search, page) )
8563
		return list;
8564
 
8565
	delete list;
8566
	return NULL;
8567
}
8568
 
8569
int CPackages::AdjustFileType(CyString file, int filetype)
8570
{
8571
	CFileIO File(file);
121 cycrow 8572
	Utils::String dir = File.GetDirIO().topDir();
57 cycrow 8573
	CyString basename = File.baseName();
1 cycrow 8574
 
160 cycrow 8575
	Utils::String ext = File.extension();
8576
 
1 cycrow 8577
	// mod files
160 cycrow 8578
	if (ext.Compare("cat") || ext.Compare("dat"))
1 cycrow 8579
		return FILETYPE_MOD;
8580
	// check for text files
111 cycrow 8581
	if ( File.filename().isin("-L") && File.filename().left(4).isNumber() )
1 cycrow 8582
		return FILETYPE_TEXT;
57 cycrow 8583
	if ( File.baseName().Compare("conversations") )
43 cycrow 8584
		return FILETYPE_TEXT;
160 cycrow 8585
	if ( basename.Length() <= 4 && basename.IsNumber() && (File.isFileExtension("xml") || File.isFileExtension("pck")) )
1 cycrow 8586
		return FILETYPE_TEXT;
8587
	// X2/X3 text file
57 cycrow 8588
	if ( basename.Length() >= 5 && basename.Length() <= 8 && ((int)File.baseName()) )
1 cycrow 8589
		return FILETYPE_TEXT;
8590
	if ( filetype == FILETYPE_TEXT ) // should no longer be anything text
8591
		return FILETYPE_SCRIPT;
160 cycrow 8592
	if ( File.isFileExtension("wav") || File.isFileExtension("mp3") )
1 cycrow 8593
		return FILETYPE_SOUND;
8594
	return filetype;
8595
}
8596
 
8597
void CPackages::RemoveFailedFiles()
8598
{
160 cycrow 8599
	Utils::CStringList removed;
8600
	for (auto itr = m_lNonRemovedFiles.begin(); itr != m_lNonRemovedFiles.end(); itr++)
1 cycrow 8601
	{
160 cycrow 8602
		if (CFileIO::Remove((*itr)->str))
8603
			removed.pushBack((*itr)->str);
1 cycrow 8604
	}
160 cycrow 8605
	for (auto itr = removed.begin(); itr != removed.end(); itr++)
8606
		m_lNonRemovedFiles.remove((*itr)->str);
1 cycrow 8607
}
8608
 
35 cycrow 8609
CXspFile *CPackages::extractShip(const Utils::String &sCatFile, const Utils::String &sId, CProgressInfo *progress)
1 cycrow 8610
{
35 cycrow 8611
	CVirtualFileSystem *pVfs = new CVirtualFileSystem();
8612
	if ( !pVfs->addMod(sCatFile) ) {
8613
		delete pVfs;
1 cycrow 8614
		return NULL;
35 cycrow 8615
	}
1 cycrow 8616
 
8617
	CXspFile *newShip = new CXspFile;
35 cycrow 8618
	if ( !newShip->extractShip(pVfs, sId, progress) ) {
1 cycrow 8619
		delete newShip;
35 cycrow 8620
		newShip = NULL;
1 cycrow 8621
	}
8622
 
35 cycrow 8623
	delete pVfs;
8624
 
1 cycrow 8625
	return newShip;
8626
}
8627
 
124 cycrow 8628
void CPackages::getMergedFiles(Utils::CStringList &list, CCatFile *cat1, CCatFile *cat2)
1 cycrow 8629
{
8630
	// first add all files from the "primary" mod
124 cycrow 8631
	for (auto itr = cat1->GetFiles()->cbegin(); itr != cat1->GetFiles()->cend(); itr++)
8632
		list.pushBack((*itr)->sFile.findReplace("\\", "/"), "1");
1 cycrow 8633
 
8634
	// now add the ones from the secondary
124 cycrow 8635
	for (auto itr = cat2->GetFiles()->cbegin(); itr != cat2->GetFiles()->cend(); itr++)
1 cycrow 8636
	{
124 cycrow 8637
		Utils::String sFile = (*itr)->sFile.findReplace("\\", "/");
1 cycrow 8638
		// if its found on the 2nd list, dont add, just adjust the type
124 cycrow 8639
		if(!list.changeData(sFile, "-1"))
8640
			list.pushBack(sFile, "2");
1 cycrow 8641
	}
8642
}
8643
 
58 cycrow 8644
bool CPackages::CanWeMerge(const Utils::String &file) const
1 cycrow 8645
{
8646
	return CModDiff::CanBeDiffed(file);
8647
}
8648
 
8649
bool CPackages::NeedToMerge(CyString file)
8650
{
8651
	CyString firstDir = file.GetToken("/", 1, 1);
8652
	if ( firstDir.Compare("t") )
8653
		return true;
8654
	if ( firstDir.Compare("types") )
8655
		return true;
8656
	if ( firstDir.Compare("maps") )
8657
		return true;
8658
 
8659
	return false;
8660
}
8661
 
8662
bool CPackages::MergeMods(CCatFile *mod1, CCatFile *mod2, CyString outFile, CyStringList *cantMerge)
8663
{
8664
	CCatFile newCat;
125 cycrow 8665
	if ( newCat.open(outFile.ToString(), this->getAddonDir()) != CATERR_CREATED )
1 cycrow 8666
		return false;
8667
 
124 cycrow 8668
	Utils::CStringList list;
8669
	this->getMergedFiles(list, mod1, mod2);
8670
	if (list.empty())
8671
		return false;
8672
 
1 cycrow 8673
	// add all the files to the new mod first
124 cycrow 8674
	Utils::CStringList conflicts;
8675
	for(auto itr = list.begin(); itr != list.end(); itr++)
8676
	{		
8677
		int status = (*itr)->data.toInt();
1 cycrow 8678
		if ( status == 1 )
8679
		{
124 cycrow 8680
			if ( !newCat.WriteFromCat(mod1, (*itr)->str) )
1 cycrow 8681
			{
8682
				if ( cantMerge )
124 cycrow 8683
					cantMerge->PushBack(CyString((*itr)->str), "1");
1 cycrow 8684
			}
8685
		}
8686
		else if ( status == 2 )
8687
		{
124 cycrow 8688
			if ( !newCat.WriteFromCat(mod2, (*itr)->str) )
1 cycrow 8689
			{
8690
				if ( cantMerge )
124 cycrow 8691
					cantMerge->PushBack(CyString((*itr)->str), "2");
1 cycrow 8692
			}
8693
		}
8694
		else if ( status == -1 )
8695
		{
124 cycrow 8696
			if ( this->NeedToMerge((*itr)->str) )
1 cycrow 8697
			{
124 cycrow 8698
				if ( this->CanWeMerge((*itr)->str) )
8699
					conflicts.pushBack((*itr)->str);
1 cycrow 8700
				else if ( cantMerge )
124 cycrow 8701
					cantMerge->PushBack(CyString((*itr)->str), "-1");
1 cycrow 8702
			}
8703
			else
8704
			{
124 cycrow 8705
				if ( !newCat.WriteFromCat(mod1, (*itr)->str) )
1 cycrow 8706
				{
8707
					if ( cantMerge )
124 cycrow 8708
						cantMerge->PushBack(CyString((*itr)->str), "1");
1 cycrow 8709
				}
8710
			}
8711
		}
8712
	}
8713
 
8714
	/* 
8715
		Merging Files
8716
 
8717
		* Text Files: Join all text entries into a single file (excluding page 17)
8718
		* Weapons: TBullets and TLaser (grab matching entrys from text files and adjust ids)
8719
	*/
8720
	// new merge the conflicting files
8721
	// first the text files
8722
//	CyStringList *text = this->MergeTextFiles(conflicts, mod1, mod2);
8723
//	delete text;
8724
 
8725
	// write the cat file when we're done
8726
	if ( !newCat.WriteCatFile() )
8727
		return false;
8728
 
8729
	return true;
8730
}
8731
 
8732
/**
8733
 * Gets the file list from a mod that might have compatability problems
8734
 *
8735
 * This includes all types and text files
8736
 *
8737
 * Returns true if it finds any files
8738
 */
8739
bool CPackages::GetModCompatabilityList(C_File *file, CyStringList *list)
8740
{
8741
	// not a valid file
8742
	if ( !file ) return false;
8743
	if ( file->GetFileType() != FILETYPE_MOD ) return false;
8744
	if ( !file->GetFileExt().Compare("cat") ) return false;
8745
 
8746
	// we need to read the file list for the mod
8747
	CCatFile cat;
125 cycrow 8748
	if ( cat.open(file->filePointer(), this->getAddonDir(), CATREAD_JUSTCONTENTS, false) == CATERR_NONE )
1 cycrow 8749
	{
124 cycrow 8750
		for (unsigned int i = 0; i < cat.GetNumFiles(); i++ )
1 cycrow 8751
		{
8752
			SInCatFile *f = cat.GetFile(i);
8753
			CyString filename = f->sFile;
8754
			filename = filename.FindReplace("\\", "/");
50 cycrow 8755
			bool found = false;
1 cycrow 8756
			if ( filename.Left(2).Compare("t/") || filename.Left(6).Compare("types/") )
50 cycrow 8757
				found = true;
8758
			else if ( filename.Left(8).Compare("addon/t/") || filename.Left(12).Compare("addon/types/") )
8759
				found = true;
8760
 
8761
			if ( found ) {
1 cycrow 8762
				if ( list )
8763
					list->PushBack(filename, CyString(f->lSize));
8764
				else
8765
					return true;
8766
			}
8767
		}
8768
	}
8769
 
8770
	if ( list && !list->Empty() )
8771
		return true;
8772
 
8773
	return false;
8774
}
8775
 
8776
/**
8777
 * Gets the files that are not compatable with each other
8778
 *
8779
 * Returns true if theres any files that are not compatable
8780
 *
8781
 * If list is specified, fills up with all files that were found
8782
 */
8783
bool CPackages::CheckCompatabilityBetweenModFiles(C_File *from, C_File *to, CyStringList *list)
8784
{
8785
	// not a valid file
8786
	if ( !from || !to ) return false;
8787
	if ( from->GetFileType() != FILETYPE_MOD ) return false;
8788
	if ( to->GetFileType() != FILETYPE_MOD ) return false;
8789
	if ( !from->GetFileExt().Compare("cat") ) return false;
8790
	if ( !to->GetFileExt().Compare("cat") ) return false;
8791
 
8792
	// get file lists from each file
8793
	CyStringList fromList;
8794
	if ( GetModCompatabilityList(from, &fromList) )
8795
	{
8796
		CyStringList toList;
8797
		if ( GetModCompatabilityList(to, &toList) )
8798
		{
8799
			// both have files we need to check, compare them
8800
			for ( SStringList *str = fromList.Head(); str; str = str->next )
8801
			{
8802
				CyString fromFile = str->str;
8803
				fromFile = fromFile.FindReplace("\\", "/");
8804
				fromFile = fromFile.FindReplace("//", "/");
8805
				for ( SStringList *toStr = toList.Head(); toStr; toStr = toStr->next )
8806
				{
8807
					CyString toFile = toStr->str;
8808
					toFile = toFile.FindReplace("\\", "/");
8809
					toFile = toFile.FindReplace("//", "/");
8810
					if ( fromFile.Compare(toFile) )
8811
					{
8812
						if ( list )
158 cycrow 8813
							list->PushBack(CyString((from->filename() + "::" + str->str.ToString(), to->filename() + "::" + toStr->str.ToString())).c_str());
1 cycrow 8814
						else
8815
							return true;
8816
					}
8817
				}
8818
			}
8819
		}
8820
	}
8821
 
8822
	if ( list && !list->Empty() )
8823
		return true;
8824
 
8825
	return false;
8826
}
8827
 
8828
bool CPackages::CheckCompatabilityBetweenMods(CBaseFile *from, CBaseFile *to, CyStringList *list)
8829
{
8830
	if ( !from || !to ) return false;
8831
	if ( !from->IsEnabled() || !to->IsEnabled() ) return false;
8832
	if ( !from->AnyFileType(FILETYPE_MOD) ) return false;
8833
	if ( !to->AnyFileType(FILETYPE_MOD) ) return false;
8834
 
8835
	if ( from == to ) return false; // cant have incompatabilities to itself
8836
 
8837
	int count = 0;
8838
	for ( C_File *f = from->GetFirstFile(FILETYPE_MOD); f; f = from->GetNextFile(f) )
8839
	{
8840
		if ( !f->IsFakePatch() ) continue;
8841
		if ( f->GetFileExt().Compare("dat") ) continue;
8842
 
8843
		for ( C_File *compareFile = to->GetFirstFile(FILETYPE_MOD); compareFile; compareFile = to->GetNextFile(compareFile) )
8844
		{
8845
			if ( compareFile == f ) continue; // same file we're checking against
8846
			if ( !compareFile->IsFakePatch() ) continue;
8847
			if ( compareFile->GetFileExt().Compare("dat") ) continue;
8848
 
8849
			// now we have to files to compare
8850
			if ( CheckCompatabilityBetweenModFiles(f, compareFile, list) )
8851
				++count;
8852
		}
8853
	}
8854
 
8855
	if ( count )
8856
		return true;
8857
 
8858
	return false;
8859
}
8860
 
8861
int CPackages::CheckCompatabilityAgainstPackages(CBaseFile *newFile, CyStringList *list, CLinkList<CBaseFile> *packages)
8862
{
8863
	if ( !newFile->IsEnabled() ) return 0;
8864
	if ( !newFile->AnyFileType(FILETYPE_MOD) ) return 0;
8865
 
8866
	// we need to extract all mod files
8867
	for ( CListNode<C_File> *fNode = newFile->GetFileList()->Front(); fNode; fNode = fNode->next() )
8868
	{
8869
		C_File *f = fNode->Data();
8870
		if ( f->GetFileType() != FILETYPE_MOD ) continue;
8871
		if ( !f->IsFakePatch() ) continue;
8872
		if ( !f->CheckFileExt("cat") ) continue;
8873
 
8874
		if ( newFile->ExtractFile(f, m_sTempDir) )
8875
			f->SetFullDir(m_sTempDir);
8876
	}
8877
 
8878
	// compare mod files against all installed packages
8879
	int count = 0;
8880
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
8881
	{
8882
		if ( !node->Data() ) continue;
8883
		CBaseFile *p = node->Data();
8884
		if ( !p->IsEnabled() ) continue;
8885
		if ( !p->AnyFileType(FILETYPE_MOD) ) continue;
8886
 
8887
		if ( this->IsSamePackage(p, newFile) ) continue; // dont include self
8888
 
8889
		if ( CheckCompatabilityBetweenMods(newFile, p, list) )
8890
		{
8891
			++count;
8892
			if ( packages && !packages->FindData(p) )
8893
				packages->push_back(p);
8894
		}
8895
	}
8896
 
8897
	for ( CListNode<C_File> *fNode = newFile->GetFileList()->Front(); fNode; fNode = fNode->next() )
8898
	{
8899
		C_File *f = fNode->Data();
129 cycrow 8900
		CFileIO::Remove(f->filePointer());
1 cycrow 8901
		f->SetFullDir("");
8902
	}
8903
 
8904
	return count;
8905
}
8906
 
8907
bool CPackages::IsSamePackage(CBaseFile *p1, CBaseFile *p2)
8908
{
8909
	if ( !p1 || !p2 ) return false;
8910
	if ( p1 == p2 ) return true;
8911
 
50 cycrow 8912
	if ( p1->name().Compare(p2->name()) && p1->author().Compare(p2->author()) )
1 cycrow 8913
		return true;
8914
	return false;
8915
}
8916
 
160 cycrow 8917
void CPackages::ApplyFakePatchOrder(Utils::CStringList *list)
1 cycrow 8918
{
8919
	if ( !list ) return;
160 cycrow 8920
	m_lFakePatchOrder.clear();
8921
	for(auto itr = list->begin(); itr != list->end(); itr++)
8922
		m_lFakePatchOrder.pushBack((*itr)->str, (*itr)->data);
1 cycrow 8923
}
8924
 
8925
SAvailablePackage *CPackages::CreateAvailablePackageData(CBaseFile *package)
8926
{
8927
	if ( !package ) return NULL;
8928
 
8929
	SAvailablePackage *p = new SAvailablePackage;
8930
 
8931
	for ( CListNode<SGameCompat> *node = package->GetGameCompatabilityList()->Front(); node; node = node->next() ) {
8932
		SGameCompat *gc = new SGameCompat;
8933
		gc->iGame = node->Data()->iGame;
8934
		gc->iVersion = node->Data()->iVersion;
8935
		gc->sVersion = node->Data()->sVersion;
8936
		p->lGames.push_back(gc);
8937
	}
8938
	p->bSigned = package->IsSigned();
46 cycrow 8939
	p->iChanging = package->gameChanging();
8940
	p->iEase = package->easeOfUse();
48 cycrow 8941
	p->iPluginType = package->pluginType();
46 cycrow 8942
	p->iRec = package->recommended();
1 cycrow 8943
	p->iScriptType = -1;
8944
	if ( package->GetType() == TYPE_XSP )
8945
		p->iType = PACKAGETYPE_SHIP;
8946
	else if ( package->IsMod() )
8947
		p->iType = PACKAGETYPE_MOD;
8948
	else 
8949
	{
8950
		p->iType = ((CSpkFile *)package)->GetPackageType();
8951
		p->iScriptType = ((CSpkFile *)package)->GetScriptType();
8952
	}
50 cycrow 8953
	p->sAuthor = package->author();
48 cycrow 8954
	p->sDesc = package->description().findReplace("\n", "::newline::");
50 cycrow 8955
	p->sName = package->name();
8956
	p->sUpdated = package->creationDate();
8957
	p->sVersion = package->version();
111 cycrow 8958
	p->sFilename = CFileIO(package->filename()).filename();
1 cycrow 8959
 
8960
	return p;
8961
}
8962
 
126 cycrow 8963
Utils::String CPackages::FormatAvailablePackageData(CBaseFile *package)
1 cycrow 8964
{
8965
	SAvailablePackage *p = CPackages::CreateAvailablePackageData(package);
126 cycrow 8966
	Utils::String ret = CPackages::FormatAvailablePackageData(p);
1 cycrow 8967
	delete p;
8968
	return ret;
8969
}
8970
 
126 cycrow 8971
Utils::String CPackages::FormatAvailablePackageData(SAvailablePackage *package)
1 cycrow 8972
{
126 cycrow 8973
	Utils::String ret = (long)package->iType;
1 cycrow 8974
 
126 cycrow 8975
	Utils::String gameCompat;
1 cycrow 8976
	for ( CListNode<SGameCompat> *node = package->lGames.Front(); node; node = node->next() ) {
126 cycrow 8977
		if ( !gameCompat.empty() )
1 cycrow 8978
			gameCompat += "!";
126 cycrow 8979
		gameCompat += Utils::String::Number(node->Data()->iGame);
1 cycrow 8980
	}
8981
 
126 cycrow 8982
	if ( gameCompat.empty() )
1 cycrow 8983
		gameCompat = "0";
8984
 
126 cycrow 8985
	ret = ret.addToken("::", gameCompat);
8986
	ret = ret.addToken("::", package->sName);
8987
	ret = ret.addToken("::", package->sAuthor);
8988
	ret = ret.addToken("::", package->sVersion);
8989
	ret = ret.addToken("::", package->sUpdated);
8990
	ret = ret.addToken("::", package->sFilename);
8991
	ret = ret.addToken("::", Utils::String::Number(package->iEase));
8992
	ret = ret.addToken("::", Utils::String::Number(package->iChanging));
8993
	ret = ret.addToken("::", Utils::String::Number(package->iRec));
8994
	ret = ret.addToken("::", Utils::String::Number(package->iPluginType));
8995
	ret = ret.addToken("::", Utils::String::Number(package->iScriptType));
8996
	ret = ret.addToken("::", (package->bSigned) ? "1" : "0");
8997
	ret = ret.addToken("::", package->sDesc);
1 cycrow 8998
 
8999
	return ret;
9000
}
9001
 
100 cycrow 9002
void CPackages::ParseAvailablePackage(CyString sStr, CyString webaddress)
1 cycrow 9003
{
9004
	// first check game
100 cycrow 9005
	Utils::String str = sStr.ToString();
1 cycrow 9006
 
9007
	int num = 0;
100 cycrow 9008
	Utils::String *tok = str.tokenise("::", &num);
1 cycrow 9009
	if ( !num || !tok ) return;
100 cycrow 9010
	// invalid number of entries?
1 cycrow 9011
	if ( num < 7 ) { CLEANSPLIT(tok, num); return; }
9012
 
9013
	SAvailablePackage *p = new SAvailablePackage;
100 cycrow 9014
	p->iType = tok[0].toLong();
1 cycrow 9015
	p->bSigned = false;
9016
 
100 cycrow 9017
	// theres multiple games, so we need to split it
9018
	if ( m_iGame ) {
9019
		Utils::String sGame = tok[1];
9020
		if ( sGame.isin("!") ) {
9021
			for(int i = 1; i <= sGame.countToken("!"); i++) {
1 cycrow 9022
				SGameCompat *gc = new SGameCompat;
9023
				gc->iVersion = 0;
100 cycrow 9024
				gc->iGame = sGame.token("!", i).toLong();
1 cycrow 9025
				p->lGames.push_back(gc);
9026
			}
9027
		}
100 cycrow 9028
		else {
9029
			SGameCompat *gc = new SGameCompat;
9030
			gc->iVersion = 0;
9031
			gc->iGame = sGame.toLong();
9032
			p->lGames.push_back(gc);
9033
		}
1 cycrow 9034
	}
100 cycrow 9035
 
1 cycrow 9036
	p->sName = tok[2];
9037
	p->sAuthor = tok[3];
9038
	p->sVersion = tok[4];
9039
	p->sUpdated = tok[5];
9040
	p->sFilename = tok[6];
9041
 
9042
	if ( !webaddress.Empty() )
126 cycrow 9043
		p->sFilename = webaddress.ToString() + "/" + p->sFilename;
1 cycrow 9044
 
9045
	p->iChanging = p->iEase = p->iPluginType = p->iRec = p->iScriptType = -1;
9046
 
100 cycrow 9047
	// check if we have the extra values
1 cycrow 9048
	if ( num >= 12 )
9049
	{
100 cycrow 9050
		p->iEase = tok[7].toLong();
9051
		p->iChanging = tok[8].toLong();
9052
		p->iRec = tok[9].toLong();
9053
		p->iPluginType = tok[10].toLong();
9054
		p->iScriptType = tok[11].toLong();
1 cycrow 9055
		if ( num > 12 ) {
9056
			if ( num > 13 ) {
100 cycrow 9057
				p->sDesc = tok[13];
9058
				p->bSigned = tok[12].toBool();
1 cycrow 9059
			}
9060
			else
100 cycrow 9061
				p->sDesc = tok[12];
1 cycrow 9062
		}
9063
	}
9064
	else if ( num > 7 )
100 cycrow 9065
		p->sDesc = tok[8];
1 cycrow 9066
 
126 cycrow 9067
	if ( !p->sDesc.empty() )
9068
		p->sDesc = p->sDesc.findReplace("::newline::", "\\n");
1 cycrow 9069
 
9070
	AddAvailablePackage(p);
9071
 
9072
	CLEANSPLIT(tok, num);
9073
}
9074
 
126 cycrow 9075
SAvailablePackage *CPackages::FindAvailablePackage(const Utils::String &filename)
1 cycrow 9076
{
9077
	for ( CListNode<SAvailablePackage> *node = m_lAvailablePackages.Front(); node; node = node->next() )
9078
	{
9079
		if ( node->Data()->sFilename.Compare(filename) )
9080
			return node->Data();
9081
	}
9082
	return NULL;
9083
}
9084
 
9085
bool CPackages::AddAvailablePackage(SAvailablePackage *package)	
9086
{ 
9087
	if ( !package->lGames.empty() ) {
9088
		bool found = false;
9089
		for ( CListNode<SGameCompat> *node = package->lGames.Front(); node; node = node->next() ) {
9090
			if ( !node->Data()->iGame || node->Data()->iGame == m_iGame ) {
9091
				found = true;
9092
				break;
9093
			}
9094
		}
9095
 
9096
		if ( !found )
9097
			return false;
9098
	}
9099
 
9100
	SAvailablePackage *p = FindAvailablePackage(package->sFilename);
9101
	if ( p )
9102
		m_lAvailablePackages.remove(p);
9103
	m_lAvailablePackages.push_back(package); 
9104
 
9105
	return true;
9106
}
9107
 
9108
bool CPackages::AnyAvailablePackages(int type)
9109
{
9110
	if ( type == -1 ) return !m_lAvailablePackages.empty();
9111
 
9112
	for ( CListNode<SAvailablePackage> *node = m_lAvailablePackages.Front(); node; node = node->next() )
9113
	{
9114
		if ( node->Data()->iType == type )
9115
			return true;
9116
	}
9117
 
9118
	return false;
9119
}
9120
 
9121
int CPackages::FindAllServers(CyStringList *list)
9122
{
9123
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
9124
	{
49 cycrow 9125
		if ( !node->Data()->webAddress().empty() )
9126
			list->PushBack(CyString(node->Data()->webAddress()), true);
1 cycrow 9127
		if ( node->Data()->AnyWebMirrors() )
9128
		{
9129
			for ( SStringList *str = node->Data()->GetWebMirrors()->Head(); str; str = str->next )
9130
				list->PushBack(str->str, true);
9131
		}
9132
	}
9133
 
76 cycrow 9134
	CFileIO File("data\\web");
9135
 
9136
	if ( File.startRead() ) {
9137
		while(!File.atEnd()) {
9138
			Utils::String line = File.readEndOfLine();
9139
			line.removeChar("\n\r\t ");
9140
			if ( !line.empty() )
9141
				list->PushBack(CyString(line), true);
9142
		}
9143
		File.close();
9144
	}
9145
 
9146
	list->PushBack("http://xpluginmanager.co.uk/tcscripts", true);
9147
	list->PushBack("http://xpluginmanager.co.uk/apscripts", true);
160 cycrow 9148
	list->PushBack("http://xpluginmanager.co.uk/flscripts", true);
76 cycrow 9149
 
1 cycrow 9150
	return list->Count();
9151
}
9152
 
9153
void CPackages::ReadArchiveData(CyString filename, CBaseFile *archive)
9154
{
9155
	size_t size;
9156
	char *data = CFileIO(filename).ReadToData(&size);
9157
	if ( size && data )
9158
		ReadArchiveData(data, size, archive);
9159
}
9160
 
9161
void CPackages::ReadArchiveData(const char *buf, size_t len, CBaseFile *archive)
9162
{
98 cycrow 9163
	Utils::CStringList otherGames;
127 cycrow 9164
	Utils::CStringList gameAddons;
9165
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
9166
	{
9167
		SGameExe *exe = m_gameExe.GetGame(i);
9168
		if (!exe->sAddon.empty())
9169
			gameAddons.pushBack(Utils::String::Number(i + 1), exe->sAddon);
9170
	}
98 cycrow 9171
 
1 cycrow 9172
	CyString data(buf);
9173
	int max;
9174
	CyString *str = data.SplitToken("\n", &max);
9175
	if ( str && max )
9176
	{
9177
		for ( int i = 0; i < max; i++ )
9178
		{
155 cycrow 9179
			Utils::String line = str[i].ToString();
9180
			if ( line.empty() )
1 cycrow 9181
				continue;
9182
 
9183
			// filter out any spaces, tabs in front
155 cycrow 9184
			line.removeChar('\t');
9185
			line.removeChar('\r');
9186
			Utils::String linenospace = line;
9187
			linenospace.removeFirstSpace();
9188
			if ( linenospace.empty() )
1 cycrow 9189
				continue;
9190
 
9191
			// check for any comments
155 cycrow 9192
			if ( linenospace.left(2) == "//" )
1 cycrow 9193
				continue;
9194
			if ( linenospace[0] == '#' )
9195
				continue;
9196
 
9197
			// all commands start with a keyword followed by a colon, if one doesn't exist, it cant be a valid line
155 cycrow 9198
			if ( !line.contains(':'))
1 cycrow 9199
				continue;
9200
 
155 cycrow 9201
			Utils::String first = line.token(":", 1);
9202
			Utils::String rest = line.tokens(":", 2).removeFirstSpace();
1 cycrow 9203
 
155 cycrow 9204
			Utils::String checkType = first;
1 cycrow 9205
			bool shared = false;
155 cycrow 9206
			if ( checkType.left(6).Compare("Shared") )
1 cycrow 9207
			{
155 cycrow 9208
				checkType = first.right(-6);
1 cycrow 9209
				shared = true;
9210
			}
155 cycrow 9211
			bool packed = false;
9212
			if (checkType.right(3).compare("PCK"))
9213
			{
9214
				checkType = checkType.left(-3);
9215
				packed = true;
9216
			}
1 cycrow 9217
 
9218
			// now check type name
9219
			int filetype = GetFileTypeFromString(checkType);
155 cycrow 9220
			if (filetype == -1)
9221
			{
9222
				archive->LoadPackageData(first, rest, Utils::String::Null(), otherGames, gameAddons, NULL);
9223
			}
1 cycrow 9224
		}
9225
	}
9226
 
9227
	CLEANSPLIT(str, max)
9228
}
9229
 
43 cycrow 9230
CBaseFile *CPackages::_archive_fromRar(CyString filename, bool toInstall )
1 cycrow 9231
{
9232
	// make sure we can open the zip file
9233
	CBaseFile *archive = NULL;
9234
#ifdef _RAR
43 cycrow 9235
	HANDLE hArcData;
9236
	int RHCode,PFCode;
9237
	char CmtBuf[16384];
9238
	struct RARHeaderDataEx HeaderData;
9239
	struct RAROpenArchiveDataEx OpenArchiveData;
1 cycrow 9240
 
43 cycrow 9241
	// find the pluginmanager text to covnert to spkfile
9242
	if ( toInstall ) {
1 cycrow 9243
		memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
9244
		OpenArchiveData.ArcName=(char *)filename.c_str();
9245
		OpenArchiveData.CmtBuf=CmtBuf;
9246
		OpenArchiveData.CmtBufSize=sizeof(CmtBuf);
43 cycrow 9247
		OpenArchiveData.OpenMode=RAR_OM_LIST;
1 cycrow 9248
		hArcData=RAROpenArchiveEx(&OpenArchiveData);
9249
 
43 cycrow 9250
		if (OpenArchiveData.OpenResult!=0) return NULL;
1 cycrow 9251
 
9252
		HeaderData.CmtBuf=NULL;
9253
		memset(&OpenArchiveData.Reserved,0,sizeof(OpenArchiveData.Reserved));
9254
 
43 cycrow 9255
		while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0) {
9256
			if ( CyString(HeaderData.FileName).Compare("pluginmanager.txt") ) {
9257
				toInstall = false;
1 cycrow 9258
				break;
9259
			}
43 cycrow 9260
		}
9261
		RARCloseArchive(hArcData);
9262
	}
1 cycrow 9263
 
43 cycrow 9264
	if ( toInstall )
9265
		archive = new CArchiveFile(); // just installing an archive file
9266
	else
9267
		archive = new CSpkFile(); // converting to a spk file
9268
 
9269
	memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
9270
	OpenArchiveData.ArcName=(char *)filename.c_str();
9271
	OpenArchiveData.CmtBuf=CmtBuf;
9272
	OpenArchiveData.CmtBufSize=sizeof(CmtBuf);
9273
	OpenArchiveData.OpenMode=RAR_OM_EXTRACT;
9274
	OpenArchiveData.UserData=EXTRACT;
9275
	hArcData=RAROpenArchiveEx(&OpenArchiveData);
9276
 
9277
	if (OpenArchiveData.OpenResult!=0) return NULL;
9278
 
9279
	HeaderData.CmtBuf=NULL;
9280
	memset(&OpenArchiveData.Reserved,0,sizeof(OpenArchiveData.Reserved));
9281
 
9282
	bool error = false;
160 cycrow 9283
	Utils::String extractedFile = CDirIO(m_sTempDir).file("extracted.tst").findReplace("/", "\\").findReplace("\\\\", "\\");
43 cycrow 9284
	while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0)
9285
	{
160 cycrow 9286
		Utils::String fileName = HeaderData.FileName;
43 cycrow 9287
 
9288
		if ( HeaderData.FileAttr == 16 )
9289
			continue;
9290
		wchar_t wText[200];
160 cycrow 9291
		::MultiByteToWideChar(CP_ACP, NULL, (char *)extractedFile.c_str(), -1, wText, extractedFile.length() + 1);
43 cycrow 9292
		PFCode=RARProcessFileW(hArcData, RAR_EXTRACT, NULL, NULL);
9293
		if (PFCode!=0)
9294
		{
9295
			error = true;
9296
			break;
9297
		}
9298
 
9299
		CFileIO File(fileName);
52 cycrow 9300
		if ( File.exists() )
43 cycrow 9301
		{
9302
			if ( fileName.Compare("pluginmanager.txt") )
102 cycrow 9303
				this->ReadArchiveData(File.fullFilename(), archive);
43 cycrow 9304
			else
1 cycrow 9305
			{
43 cycrow 9306
				CyString extradir;
9307
				int type = SPK::GetAutomaticFiletype(fileName, &extradir, true);
9308
				// check for special file types
9309
				C_File *f = NULL;
1 cycrow 9310
 
43 cycrow 9311
				if ( type == FILETYPE_SCRIPT_UNINSTALL ) {
111 cycrow 9312
					f = archive->AddFile(CFileIO(fileName).filename(), "", FILETYPE_SCRIPT);
43 cycrow 9313
					if ( f ) {
102 cycrow 9314
						f->ReadFromFile(File.fullFilename());
17 cycrow 9315
					}
43 cycrow 9316
					type = FILETYPE_UNINSTALL;
1 cycrow 9317
				}
9318
 
43 cycrow 9319
				if ( type == -1 )
102 cycrow 9320
					f = archive->AddFile(CFileIO(fileName).filename(), CFileIO(fileName).dir(), FILETYPE_EXTRA);
43 cycrow 9321
				else
102 cycrow 9322
					f = archive->AddFile(CFileIO(fileName).filename(), extradir, type);
9323
				f->ReadFromFile(File.fullFilename());
1 cycrow 9324
			}
43 cycrow 9325
 
52 cycrow 9326
			File.remove();
1 cycrow 9327
		}
43 cycrow 9328
	}
1 cycrow 9329
 
43 cycrow 9330
	RARCloseArchive(hArcData);
1 cycrow 9331
 
43 cycrow 9332
	if ( error )
9333
	{
9334
		delete archive;
9335
		archive = NULL;
9336
	}
1 cycrow 9337
#endif
9338
 
43 cycrow 9339
	return archive;
9340
}
1 cycrow 9341
 
43 cycrow 9342
CBaseFile *CPackages::_archive_fromZip(CyString filename, bool toInstall)
9343
{
9344
	CBaseFile *archive = NULL;
1 cycrow 9345
 
43 cycrow 9346
	TCHAR buf[5000];
9347
	wsprintf(buf, L"%hs", filename.c_str());
9348
	HZIP hz = OpenZip(buf, 0);
9349
	if ( !hz ) 
9350
		return NULL;
1 cycrow 9351
 
43 cycrow 9352
	int index;
9353
	// move the files from the zip to the package
9354
	ZIPENTRY ze;
9355
	if ( FindZipItem(hz, L"pluginmanager.txt", true, &index, &ze) == Z_OK )
9356
		toInstall = false;
9357
	CloseZip(hz);
1 cycrow 9358
 
43 cycrow 9359
	hz = OpenZip(buf, 0);
9360
	if ( !hz ) 
9361
		return NULL;
9362
 
9363
	// create the correct package
9364
	if ( toInstall )
9365
		archive = new CArchiveFile(); // just installing an archive file
9366
	else
9367
		archive = new CSpkFile(); // converting to a spk file
9368
 
9369
	GetZipItem(hz, -1, &ze);
9370
	int numitems = ze.index;
9371
 
9372
	bool error = false;
9373
	for ( int zi = 0; zi < numitems; zi++ )
9374
	{
9375
		ZIPENTRY ze;
9376
		if ( GetZipItem(hz, zi, &ze) != Z_OK )
1 cycrow 9377
		{
43 cycrow 9378
			error = true;
9379
			break;
9380
		}
1 cycrow 9381
 
43 cycrow 9382
		if ( ze.attr & FILE_ATTRIBUTE_DIRECTORY )
9383
			continue; // dont do directories
1 cycrow 9384
 
9385
 
43 cycrow 9386
		char *iBuf = new char[ze.unc_size];
9387
		UnzipItem(hz, zi, iBuf, ze.unc_size);
1 cycrow 9388
 
43 cycrow 9389
		CyString Name(ze.name);
1 cycrow 9390
 
43 cycrow 9391
		// if its the data file, dont add it, but extract to get settings from
9392
		if ( Name.Compare("pluginmanager.txt") )
9393
		{
9394
			this->ReadArchiveData(iBuf, ze.unc_size, archive);
9395
			delete[] iBuf;
9396
		}
9397
		else
9398
		{
9399
			CyString extradir;
9400
			int type = SPK::GetAutomaticFiletype(Name, &extradir, true);
1 cycrow 9401
 
43 cycrow 9402
			C_File *f = NULL;
17 cycrow 9403
 
126 cycrow 9404
			Utils::String filename = CFileIO(Name).filename();
9405
			Utils::String dir = CFileIO(Name).dir();
9406
 
43 cycrow 9407
			// check for special file types
9408
			if ( type == FILETYPE_SCRIPT_UNINSTALL ) {
126 cycrow 9409
				f = archive->AddFile(filename, dir, FILETYPE_SCRIPT);
43 cycrow 9410
				if ( f ) {
9411
					f->copyData((const unsigned char *)iBuf, ze.unc_size);
17 cycrow 9412
				}
43 cycrow 9413
				type = FILETYPE_UNINSTALL;
9414
			}
17 cycrow 9415
 
126 cycrow 9416
			int game = 0;
9417
			// check for addons
9418
			if (dir.contains('/', true)) 
9419
			{
9420
				Utils::String first = dir.token("/", 1);
9421
				int g = m_gameExe.findAddonType(first);
9422
				if (g != -1)
9423
					game = g + 1;
9424
			}
9425
 
43 cycrow 9426
			if ( type == -1 )
126 cycrow 9427
				f = archive->AddFile(filename, dir, FILETYPE_EXTRA, game);
43 cycrow 9428
			else
126 cycrow 9429
				f = archive->AddFile(filename, extradir, type, game);
1 cycrow 9430
 
43 cycrow 9431
			if ( f )
9432
				f->SetData((const unsigned char *)iBuf, ze.unc_size);
9433
			else
9434
				delete[] iBuf;
1 cycrow 9435
		}
43 cycrow 9436
	}
1 cycrow 9437
 
43 cycrow 9438
	CloseZip(hz);
1 cycrow 9439
 
43 cycrow 9440
	if ( error )
9441
	{
9442
		delete archive;
9443
		archive = NULL;
1 cycrow 9444
	}
43 cycrow 9445
	return archive;
9446
}
1 cycrow 9447
 
43 cycrow 9448
CBaseFile *CPackages::CreateFromArchive(CyString filename, bool toInstall )
9449
{
9450
	// make sure we can open the zip file
9451
	CBaseFile *archive = NULL;
160 cycrow 9452
	if ( CFileIO(filename).isFileExtension("rar") )
43 cycrow 9453
		archive = this->_archive_fromRar(filename, toInstall);
160 cycrow 9454
	else if ( CFileIO(filename).isFileExtension("zip") )
43 cycrow 9455
		archive = this->_archive_fromZip(filename, toInstall);
9456
 
9457
	if ( archive ) {
160 cycrow 9458
		archive->setFilename(CFileIO(filename).changeFileExtension("spk"));
1 cycrow 9459
		if ( toInstall )
57 cycrow 9460
			archive->setName(CFileIO(filename).filename());
1 cycrow 9461
		else
57 cycrow 9462
			archive->setName(CFileIO(filename).baseName());
1 cycrow 9463
	}
9464
 
9465
	return archive;
9466
}
9467
 
131 cycrow 9468
Utils::String CPackages::CreateFromPackagerScript(CPackages *packages, const Utils::String &filename)
1 cycrow 9469
{
131 cycrow 9470
	Utils::String curDir = CFileIO(filename).dir();
9471
	Utils::CStringList variables;
9472
	variables.pushBack("$PATH", curDir);
9473
	CBaseFile *package = packages->LoadPackagerScript(filename, NULL, NULL, NULL, &variables);
1 cycrow 9474
 
9475
	if ( !package )
131 cycrow 9476
		return Utils::String::Null();
1 cycrow 9477
 
131 cycrow 9478
	Utils::String saveto = package->filename();
9479
	saveto = saveto.findReplace("$DEFAULTDIR", curDir + "/");
9480
	saveto = saveto.findReplace("$PATH", curDir);
9481
	saveto = saveto.findReplace("\\", "/");
9482
	saveto = saveto.findReplace("//", "/");
9483
	if ( !saveto.right(4).Compare(".spk") && package->GetType() != TYPE_XSP )
1 cycrow 9484
		saveto += ".spk";
131 cycrow 9485
	else if ( !saveto.right(4).Compare(".xsp") && package->GetType() == TYPE_XSP )
1 cycrow 9486
		saveto += ".xsp";
9487
 
9488
	// write script
9489
	if ( package->WriteFile(saveto) )
9490
	{
9491
		if ( package->AutoGenerateUpdateFile() )
134 cycrow 9492
			package->createUpdateFile(CFileIO(saveto).dir());
1 cycrow 9493
		return saveto;
9494
	}
9495
 
131 cycrow 9496
	return Utils::String::Null();
1 cycrow 9497
}
9498
 
160 cycrow 9499
int CPackages::GeneratePackageUpdateData(const Utils::String &dir, bool includeSingle)
1 cycrow 9500
{
126 cycrow 9501
	Utils::CStringList filedata;
1 cycrow 9502
 
9503
	CPackages packages;
9504
 
9505
	CDirIO Dir(dir);
9506
	for ( int i = 0; i < 2; i++ )
9507
	{
126 cycrow 9508
		Utils::String pattern;
1 cycrow 9509
		if ( i == 0 ) pattern = "*.spk";
9510
		else if ( i == 1 ) pattern = ".xsp";
9511
		else break;
9512
 
126 cycrow 9513
		Utils::CStringList files;
9514
		if(Dir.dirList(files, "", pattern))
1 cycrow 9515
		{
126 cycrow 9516
			for(auto itr = files.begin(); itr != files.end(); itr++)
1 cycrow 9517
			{
9518
				int error = 0;
126 cycrow 9519
				CBaseFile *p = packages.OpenPackage(Dir.file((*itr)->str), &error, 0, SPKREAD_NODATA);
1 cycrow 9520
				if ( !p )
9521
					continue;
9522
 
9523
				if ( includeSingle )
160 cycrow 9524
					p->createUpdateFile(dir);
126 cycrow 9525
				filedata.pushBack(CPackages::FormatAvailablePackageData(p));
1 cycrow 9526
				delete p;
9527
			}
9528
		}
9529
	}
9530
 
126 cycrow 9531
	if ( !filedata.empty() )
1 cycrow 9532
	{
9533
		CFileIO File(dir + "/xpackagedata.dat");
126 cycrow 9534
		if ( File.writeFile(&filedata) )
9535
			return filedata.size();
1 cycrow 9536
	}
9537
 
9538
	return 0;
9539
}
9540
 
9541
int CPackages::VerifyInstalledFiles(CyStringList *missingFiles, bool getPackages)
9542
{
9543
	int count = 0;
9544
	for ( CListNode<C_File> *fn = m_lFiles.Front(); fn; fn = fn->next() )
9545
	{
9546
		C_File *f = fn->Data();
9547
		bool exists = false;
9548
		if ( f->GetFilePointer().IsIn("::") ) {
9549
			CyString modFile = f->GetFilePointer().GetToken("::", 1, 1);
9550
			CyString file = f->GetFilePointer().GetToken("::", 2, 2);
9551
 
52 cycrow 9552
			if ( CFileIO(modFile).ExistsOld() ) {
1 cycrow 9553
				CCatFile catFile;
125 cycrow 9554
				if ( catFile.open(modFile.ToString(), "", CATREAD_CATDECRYPT, false) == CATERR_NONE ) {
1 cycrow 9555
					if ( catFile.FindData(file) )
9556
						exists = true;
9557
				}
9558
			}
9559
		}
9560
		else {
52 cycrow 9561
			exists = CFileIO(f->GetFilePointer()).ExistsOld();
1 cycrow 9562
		}
9563
 
9564
		if ( !exists )
9565
		{
9566
			++count;
9567
			if ( missingFiles )
9568
			{
9569
				CyString packages;
9570
				if ( getPackages )
9571
				{
9572
					for ( CListNode<CBaseFile> *p = m_lPackages.Front(); p; p = p->next() )
9573
					{
9574
						CBaseFile *package = p->Data();
9575
						if ( package->IsFileAdded(f) )
9576
						{
9577
							if ( !packages.Empty() )
9578
								packages += "\n";
9579
							packages += package->GetFullPackageName(m_iLanguage);
9580
						}
9581
					}
9582
				}
9583
				CyString filename = f->GetFilePointer();
9584
				filename = filename.Remove(m_sCurrentDir);
9585
				missingFiles->PushBack(filename, packages, false);
9586
			}
9587
		}
9588
	}
9589
	return count;
35 cycrow 9590
}