Subversion Repositories spk

Rev

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