Subversion Repositories spk

Rev

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