Subversion Repositories spk

Rev

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

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