Subversion Repositories spk

Rev

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