Subversion Repositories spk

Rev

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