Subversion Repositories spk

Rev

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