Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
#include "spk.h"
2
#include "emp.h"
3
 
4
#include <time.h>
5
#include <vector>
6
 
93 cycrow 7
#include "OriginalFiles.h"
98 cycrow 8
#include "spkdef.h"
160 cycrow 9
#include <set>
93 cycrow 10
 
1 cycrow 11
#ifdef _RAR
12
#include <unrar.h>
13
#endif
14
 
15
enum {READ_START, READ_GLOBAL, READ_SCRIPT, READ_SCRIPTFILE, READ_WARES};
16
enum { EXTRACT, TEST, PRINT, LIST };
17
 
18
typedef struct SDummyEntry {
216 cycrow 19
	Utils::WString		sSection;
20
	Utils::WStringList	lEntries;
1 cycrow 21
} SDummyEntry;
22
 
23
typedef struct SComponantEntry2 {
216 cycrow 24
	Utils::WString		sSection;
25
	Utils::WStringList	lEntries;
1 cycrow 26
} SComponantEntry2;
27
 
28
typedef struct SComponantEntry {
216 cycrow 29
	Utils::WString		sSection;
1 cycrow 30
	CLinkList<SComponantEntry2>	lEntries;
31
} SComponantEntry;
32
 
197 cycrow 33
Utils::WString CPackages::m_sTempDir;
79 cycrow 34
 
133 cycrow 35
//////////////////////////////////////////////////////////////////////////////////////
36
 
37
//////////////////////////////////////////////////////////////////////////////////////
38
 
93 cycrow 39
CPackages::CPackages() : m_pCurrentGameExe(NULL),
125 cycrow 40
	_pOriginalFiles(NULL),
41
	_pCurrentDir(NULL)	
1 cycrow 42
{
43
	m_bRenameText = false;
44
	m_iLanguage = 0;
45
	m_iGame = -1;
46
	m_iGameVersion = -1;
47
	m_iGameFlags = 0;
48
	m_bSurpressProtectedWarning = false;
49
	m_iMaxPatch = 1;
50
	m_iLastUpdated = 0;
51
	m_iFakePatch = -1;
52
	m_bVanilla = true;
53
	m_pEnabledMod = NULL;
54
	m_bForceModInstall = false;
55
	m_bLoaded = false;
56
	m_bRedo = false;
57
	m_bOldPlugin = false;
58
	m_bUsedWare = false;
59
	m_pPackageNode = NULL;
60
	m_bRemoveDir = false;
61
	m_bDisableVanilla = false;
62
	m_bLoadVFS = true;
63
	m_iSaveGame = -1;
64
	m_iSaveGameManager = -1;
65
	m_bForceEMP = false;
66
 
67
	for ( int i = 0; i < WAREBUFFERS; i++ )
68
		m_iWareBuffer[i] = 0;
69
	m_iShipBuffer = 0;
70
}
71
 
72
CPackages::~CPackages ()
73
{
74
	m_lDisableList.clear();
75
	m_lEnableList.clear();
76
	this->Reset();
77
}
78
 
197 cycrow 79
void CPackages::setCurrentDir(const Utils::WString &dir)
125 cycrow 80
{ 
158 cycrow 81
	m_sCurrentDir = dir;
125 cycrow 82
	if (_pCurrentDir) delete _pCurrentDir;
83
	_pCurrentDir = new GameDirectory();
158 cycrow 84
	_pCurrentDir->dir = dir;
125 cycrow 85
	_pCurrentDir->id = -1;
86
 
197 cycrow 87
	m_gameExe.getDirectoryData(_pCurrentDir);
221 cycrow 88
	_pCurrentDir->langid = this->getGameLanguage(_pCurrentDir->dir);
125 cycrow 89
	if (_pCurrentDir->langid > 0)
220 cycrow 90
		_pCurrentDir->langname = this->ConvertLanguage(_pCurrentDir->langid);
164 cycrow 91
 
213 cycrow 92
	updateFoundPackages(L"");
125 cycrow 93
}
94
 
164 cycrow 95
 
1 cycrow 96
void CPackages::SetVanilla(bool b)
97
{
98
	if ( m_bVanilla != b && b ) {
99
		for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() ) {
100
			pNode->Data()->SetModifiedEnabled(pNode->Data()->IsEnabled());
101
		}
102
	}
103
	m_bVanilla = b;
104
}
105
 
197 cycrow 106
void CPackages::setMod(const Utils::WString &mod)
160 cycrow 107
{
197 cycrow 108
	if (mod != L"PluginManager")
160 cycrow 109
		m_sSetMod = mod;
110
}
111
 
126 cycrow 112
void CPackages::setSaveGameManager(bool managed)
113
{
114
	m_iSaveGameManager = managed ? 1 : 0;
115
 
116
	if (managed)
117
	{
118
		// find new save directory
119
		CDirIO dir(this->saveDirectory());
120
		if (dir.exists())
121
		{
122
			int id = 1;
197 cycrow 123
			while (dir.exists(Utils::WString::PadNumber(id, 4)))
126 cycrow 124
				++id;
197 cycrow 125
			Utils::WString d = Utils::WString::PadNumber(id, 4);
160 cycrow 126
			dir.create(d);
126 cycrow 127
			_sSaveDir = d;
128
 
129
			CDirIO destDir1(dir.dir(d));
197 cycrow 130
			destDir1.create(L"Vanilla");
131
			destDir1.cd(L"Vanilla");
126 cycrow 132
			CDirIO destDir2(dir.dir(d));
197 cycrow 133
			destDir2.create(L"Modified");
134
			destDir2.cd(L"Modified");
126 cycrow 135
 
197 cycrow 136
			Utils::WStringList files;
137
			if (dir.dirList(files, Utils::WString::Null(), L"*.sav"))
126 cycrow 138
			{
139
				for (auto itr = files.begin(); itr != files.end(); ++itr)
140
				{
196 cycrow 141
					Utils::WString f = dir.file((*itr)->str);
126 cycrow 142
					CFileIO(f).copy(destDir1.file((*itr)->str));
143
					CFileIO(f).copy(destDir2.file((*itr)->str));
144
				}
145
			}
146
		}
147
	}
148
	else
149
	{
150
		_sSaveDir.clear();
151
	}
152
}
153
 
154
 
1 cycrow 155
void CPackages::Reset()
156
{
157
	m_lFiles.MemoryClear();
158
	m_lUninstallFiles.MemoryClear();
159
	for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )
160
		pNode->Data()->GetFileList()->clear();
161
	m_lPackages.MemoryClear();
93 cycrow 162
 
163
	SafeDelete(_pOriginalFiles);
164
 
1 cycrow 165
	m_iFakePatch = -1;
166
	m_bVanilla = false;
167
	m_pEnabledMod = NULL;
168
	m_bLoaded = false;
169
	m_iLanguage = 0;
170
	m_bOldPlugin = false;
171
	m_bRemoveDir = false;
172
	m_bDisableVanilla = false;
173
	m_bSurpressProtectedWarning = false;
174
	m_iSaveGame = -1;
175
	m_iSaveGameManager = -1;
213 cycrow 176
	m_sSetMod = L"";
1 cycrow 177
 
178
	for ( int i = 0; i < WAREBUFFERS; i++ )
179
	{
180
		m_iWareBuffer[i] = 0;
181
		m_lGameWares[i].MemoryClear();
182
	}
183
	m_iShipBuffer = 0;
184
 
185
	m_lGameShips.MemoryClear();
186
	m_lAvailablePackages.MemoryClear();
164 cycrow 187
	m_lFoundPackages.MemoryClear();
1 cycrow 188
	m_lInstallList.MemoryClear();
189
	m_lEnableList.MemoryClear();
190
	m_lDisableList.MemoryClear();
191
 
197 cycrow 192
	_lCreatedFiles.clear();
193
	_lNonRemovedFiles.clear();
194
	_lGlobals.clear();
195
	_lFakePatchOrder.clear();
125 cycrow 196
	if (_pCurrentDir)
197
		delete _pCurrentDir;
198
	_pCurrentDir = NULL;
1 cycrow 199
}
200
 
201
void CPackages::LoadVirtualFileSystem()
202
{
203
	if ( !m_bLoadVFS )
204
		return;
205
 
125 cycrow 206
	m_pGameVFS.setAddon(this->getAddonDir());
1 cycrow 207
	if ( m_pEnabledMod )
208
	{
209
		C_File *f;
210
		for ( f = m_pEnabledMod->GetFirstFile(FILETYPE_MOD); f; f = m_pEnabledMod->GetNextFile(f) )
211
		{
178 cycrow 212
			if (f->IsFakePatch()) continue;
213 cycrow 213
			if (f->checkFileExt(L"cat")) break;
1 cycrow 214
		}
215
 
216
		if ( f )
158 cycrow 217
			m_pGameVFS.LoadFilesystem(m_sCurrentDir, f->filePointer(), 0);
1 cycrow 218
		else
158 cycrow 219
			m_pGameVFS.LoadFilesystem(m_sCurrentDir, 0);
1 cycrow 220
	}
221
	else
158 cycrow 222
		m_pGameVFS.LoadFilesystem(m_sCurrentDir, 0);
1 cycrow 223
}
224
 
212 cycrow 225
bool CPackages::isOldDir(const Utils::WString &dir)
1 cycrow 226
{
227
	bool oldPlugin = false;
228
 
212 cycrow 229
	CFileIO datFile(dir + L"/PluginManager/pluginmanager.dat");
52 cycrow 230
	if ( datFile.exists() )
1 cycrow 231
	{
212 cycrow 232
		std::vector<Utils::WString> readFile;
233
		if(datFile.readLines(readFile))
1 cycrow 234
		{
212 cycrow 235
			for ( int i = 0; i < (int)readFile.size(); i++ )
1 cycrow 236
			{
212 cycrow 237
				Utils::WString line(readFile.at(i));
238
				Utils::WString cmd = line.token(L":", 1);
239
				if ( cmd.Compare(L"<script>") || cmd.Compare(L"</scripts>") )
1 cycrow 240
					break;
212 cycrow 241
				else if ( cmd.Compare(L"spkinstaller") || cmd.Compare(L"globalfiles") )
1 cycrow 242
					break;
212 cycrow 243
				else if ( cmd.Compare(L"pluginmanager") )
1 cycrow 244
				{
245
					oldPlugin = true;
246
					break;
247
				}
248
			}
249
		}
250
	}
251
 
252
	return oldPlugin;
253
}
254
 
197 cycrow 255
bool CPackages::read(const Utils::WString& dir, CProgressInfo* progress)
121 cycrow 256
{
1 cycrow 257
	m_sCurrentDir = dir;
213 cycrow 258
	m_sCurrentDir = m_sCurrentDir.findReplace(L"\\", L"/");
158 cycrow 259
	this->setCurrentDir(dir);
1 cycrow 260
	m_bOldPlugin = false;
197 cycrow 261
	_lCreatedFiles.clear();
1 cycrow 262
	m_bRemoveDir = false;
263
	m_bSurpressProtectedWarning = false;
264
	m_iSaveGame = -1;
265
	m_iSaveGameManager = -1;
197 cycrow 266
	_lNonRemovedFiles.clear();
267
	_lGlobals.clear();
268
	_lFakePatchOrder.clear();
1 cycrow 269
 
93 cycrow 270
	if ( _pOriginalFiles ) delete _pOriginalFiles;
158 cycrow 271
	_pOriginalFiles = new COriginalFiles(m_sCurrentDir);
93 cycrow 272
 
1 cycrow 273
	m_bVanilla = true;
274
 
275
	// check the pluginmanager data file exists
197 cycrow 276
	CFileIO datFile(m_sCurrentDir + L"/PluginManager/pluginmanager.dat");
52 cycrow 277
	if ( datFile.exists() )
1 cycrow 278
	{
197 cycrow 279
		std::vector<Utils::WString> readFile;
280
		if(datFile.readLines(readFile))
1 cycrow 281
		{
282
			float fVersion = 0;
283
			bool spkinstaller = false;
284
			float fBeta = 0;
285
 
286
			int iStatus = READ_START;
287
			int iCount = 0;
288
			int iWare = -1;
289
			int iShip = -1;
290
 
291
			CBaseFile *packageFile = 0;
292
 
197 cycrow 293
			for ( int i = 0; i < (int)readFile.size(); i++ )
1 cycrow 294
			{
197 cycrow 295
				Utils::WString line(readFile.at(i));
1 cycrow 296
 
197 cycrow 297
				Utils::WString cmd = line.token(L":", 1).lower();
298
				Utils::WString rest = line.tokens(L":", 2).removeFirstSpace();
1 cycrow 299
 
300
				if ( iStatus == READ_GLOBAL )
301
				{
197 cycrow 302
					if ( cmd == L"<script>" )
1 cycrow 303
					{
304
						packageFile = new CSpkFile();
305
						iStatus = READ_SCRIPT;
306
					}
197 cycrow 307
					else if ( cmd == L"<ship>" )
1 cycrow 308
					{
309
						packageFile = new CXspFile();
310
						iStatus = READ_SCRIPT;
311
					}
197 cycrow 312
					else if ( cmd == L"<base>" )
1 cycrow 313
					{
314
						packageFile = new CBaseFile();
315
						iStatus = READ_SCRIPT;
316
					}
197 cycrow 317
					else if ( cmd == L"<archive>" )
1 cycrow 318
					{
319
						packageFile = new CArchiveFile();
320
						iStatus = READ_SCRIPT;
321
					}
197 cycrow 322
					else if ( cmd != L"</scripts>" )
1 cycrow 323
					{
324
						int game = 0;
325
						bool disabled = false;
197 cycrow 326
						Utils::WString fileName = line.tokens(L":", 5);
327
						Utils::WString origName;
328
						if ( fileName.left(2) == L"D#" )
1 cycrow 329
						{
83 cycrow 330
							fileName.erase(0, 2);
1 cycrow 331
							disabled = true;
332
						}
197 cycrow 333
						if ( fileName.left(2) == L"G#" ) {
83 cycrow 334
							fileName.erase(0, 2);
197 cycrow 335
							game = fileName.token(L"#", 1).toLong();
336
							fileName = fileName.tokens(L"#", 2);
1 cycrow 337
						}
197 cycrow 338
						if ( fileName.isin(L"O#") )
1 cycrow 339
						{
197 cycrow 340
							origName = fileName.token(L"O#", 2);
341
							fileName = fileName.token(L"O#", 1);
1 cycrow 342
						}
343
 
158 cycrow 344
						C_File *newFile = new C_File(m_sCurrentDir + fileName);
127 cycrow 345
						newFile->setGame(game);
1 cycrow 346
						newFile->SetOriginalName(origName);
347
						newFile->SetDisabled(disabled);
197 cycrow 348
						newFile->setFileType(static_cast<FileType>(line.token(L":", 1).toLong()));
349
						newFile->SetCreationTime(static_cast<time_t>(line.token(L":", 2).toLong()));
350
						newFile->setDir(line.token(L":", 3));
351
						if ( line.token(L":", 4).toLong() )
1 cycrow 352
							newFile->SetShared(true);
353
						newFile->UpdateSigned();
354
 
355
						m_lFiles.push_back(newFile);
356
					}
357
				}
358
				else if ( iStatus == READ_SCRIPT )
359
				{
197 cycrow 360
					if ( cmd == L"installspk" )
83 cycrow 361
						packageFile->setFilename(rest);
197 cycrow 362
					else if ( cmd == L"files" )
1 cycrow 363
					{
364
						iStatus = READ_SCRIPTFILE;
365
						if ( spkinstaller )
366
						{
197 cycrow 367
							std::vector<Utils::WString> files;
368
							rest.tokenise(L" ", files);
369
							for (size_t i = 0; i < files.size(); i++ )
1 cycrow 370
							{
83 cycrow 371
								int fileNum = files[i].toLong();
1 cycrow 372
								if ( fileNum >= 0 && fileNum < m_lFiles.size() )
373
									packageFile->AddFile(m_lFiles[fileNum]);
374
							}
375
						}
376
					}
197 cycrow 377
					else if ( cmd == L"disabled" )
1 cycrow 378
						packageFile->SetEnabled(false);
197 cycrow 379
					else if ( cmd == L"modifieddisabled" )
1 cycrow 380
						packageFile->SetModifiedEnabled(false);
197 cycrow 381
					else if ( cmd == L"icon" )
1 cycrow 382
					{
197 cycrow 383
						C_File *icon = new C_File(rest.tokens(L" ", 2));
221 cycrow 384
						packageFile->setIcon(icon, rest.token(L" ", 1));
1 cycrow 385
					}
386
					else
207 cycrow 387
						packageFile->parseValueLine(line);
1 cycrow 388
				}
389
				else if ( iStatus == READ_SCRIPTFILE )
390
				{
197 cycrow 391
					if ( cmd == L"<script>" )
1 cycrow 392
					{
393
						if ( packageFile->IsMod() && packageFile->IsEnabled() )
394
							m_pEnabledMod = packageFile;
395
 
248 cycrow 396
 
397
						_processAddPackage(packageFile);
1 cycrow 398
						packageFile = new CSpkFile();
399
						iStatus = READ_SCRIPT;
400
 
401
					}
197 cycrow 402
					else if ( cmd == L"<ship>" )
1 cycrow 403
					{
248 cycrow 404
						_processAddPackage(packageFile);
1 cycrow 405
						packageFile = new CXspFile();
406
						iStatus = READ_SCRIPT;
407
					}
197 cycrow 408
					else if ( cmd == L"<base>" )
1 cycrow 409
					{
248 cycrow 410
						_processAddPackage(packageFile);
1 cycrow 411
						packageFile = new CBaseFile();
412
						iStatus = READ_SCRIPT;
413
					}
197 cycrow 414
					else if ( cmd == L"<archive>" )
1 cycrow 415
					{
248 cycrow 416
						_processAddPackage(packageFile);
1 cycrow 417
						packageFile = new CArchiveFile();
418
						iStatus = READ_SCRIPT;
419
					}
248 cycrow 420
					else if (cmd == L"</scripts>")
1 cycrow 421
					{
422
						if ( packageFile->IsMod() && packageFile->IsEnabled() )
423
							m_pEnabledMod = packageFile;
424
 
248 cycrow 425
						_processAddPackage(packageFile);
1 cycrow 426
					}
427
					else
428
					{
197 cycrow 429
						int fileNum = line.token(L"::", 1).toLong();
1 cycrow 430
						if ( fileNum >= 0 && fileNum < m_lFiles.size() )
431
							packageFile->AddFile(m_lFiles[fileNum]);
432
					}
433
				}
434
				else if ( iWare != -1 )
435
				{
436
					--iCount;
437
 
438
					SGameWare *gm = new SGameWare;
197 cycrow 439
					gm->iPos = line.token(L" ", 1).toLong();
440
					gm->iType = line.token(L" ", 2).toLong();
441
					gm->cType = line.token(L" ", 3)[0];
1 cycrow 442
					gm->pWare = NULL;
197 cycrow 443
					gm->sWareName = line.tokens(L" ", 4);
1 cycrow 444
					m_lGameWares[iWare].push_back(gm);
445
					if ( iCount <= 0 )
446
						iWare = -1;
447
				}
448
				else if ( iShip != -1 )
449
				{
450
					--iCount;
451
 
452
					SGameShip *gm = new SGameShip;
197 cycrow 453
					gm->iType = line.token(L" ", 1).toLong();
454
					if ( line.token(L" ", 2).left(4) == L"$#C:" )
1 cycrow 455
					{
197 cycrow 456
						gm->sShipClass = line.token(L" ", 2).right(-4);
457
						gm->sShipID = line.tokens(L" ", 3);
1 cycrow 458
					}
459
					else
460
					{
197 cycrow 461
						gm->sShipID = line.tokens(L" ", 2);
462
						gm->sShipClass = L"OBJ_SHIP_M5";
1 cycrow 463
					}
464
					gm->pPackage = NULL;
465
					m_lGameShips.push_back(gm);
466
					if ( iCount <= 0 )
467
						iShip = -1;
468
				}
197 cycrow 469
				else if ( cmd.Compare(L"savegamemanager") )
83 cycrow 470
					m_iSaveGameManager = rest.toLong();
197 cycrow 471
				else if ( cmd.Compare(L"savegame") )
83 cycrow 472
					m_iSaveGame = rest.toLong();
197 cycrow 473
				else if ( cmd == L"fakepatch" )
83 cycrow 474
					m_iFakePatch = rest.toLong();
197 cycrow 475
				else if ( cmd == L"updatetime" )
83 cycrow 476
					m_iLastUpdated = rest.toLong();
197 cycrow 477
				else if ( cmd == L"surpressprotectedwarning" )
1 cycrow 478
					m_bSurpressProtectedWarning = true;
197 cycrow 479
				else if ( cmd == L"pluginmanager" )
1 cycrow 480
				{
83 cycrow 481
					fVersion = rest.toFloat();
1 cycrow 482
					m_bOldPlugin = true;
483
				}
197 cycrow 484
				else if ( cmd == L"setmod" )
1 cycrow 485
					m_sSetMod = rest;
197 cycrow 486
				else if ( cmd == L"shipbuffer" )
83 cycrow 487
					m_iShipBuffer = rest.toLong();
197 cycrow 488
				else if(cmd == L"savedir")
126 cycrow 489
					_sSaveDir = rest;
197 cycrow 490
				else if ( cmd == L"warebuffers" )
1 cycrow 491
				{
197 cycrow 492
					int max = rest.countToken(L" ");
1 cycrow 493
					for ( int i = 0; i < WAREBUFFERS; i++ )
494
					{
495
						if ( i > max )
496
							m_iWareBuffer[i] = 0;
497
						else
197 cycrow 498
							m_iWareBuffer[i] = rest.token(L" ", i + 1).toLong();
1 cycrow 499
					}
500
				}
197 cycrow 501
				else if ( cmd == L"createdfile" )
502
					_lCreatedFiles.pushBack(rest);
503
				else if ( cmd == L"wares" )
1 cycrow 504
				{
197 cycrow 505
					iWare = rest.token(L" ", 1).toLong();
506
					iCount = rest.token(L" ", 2).toLong();
1 cycrow 507
				}
197 cycrow 508
				else if ( cmd == L"ships" )
1 cycrow 509
				{
510
					iShip = 1;
197 cycrow 511
					iCount = rest.token(L" ", 1).toLong();
1 cycrow 512
				}
197 cycrow 513
				else if ( cmd == L"modified" )
1 cycrow 514
					m_bVanilla = false;
197 cycrow 515
				else if ( cmd == L"spkinstaller" )
1 cycrow 516
				{
83 cycrow 517
					fVersion = rest.toFloat();
1 cycrow 518
					spkinstaller = true;
519
				}
197 cycrow 520
				else if ( cmd == L"betaversion" )
83 cycrow 521
					fBeta = rest.toFloat();
197 cycrow 522
				else if ( cmd == L"uninstall" )
1 cycrow 523
				{
524
					C_File *uf = new C_File();
160 cycrow 525
					uf->setFileType(FILETYPE_SCRIPT);
197 cycrow 526
					uf->SetCreationTime(rest.token(L" ", 1).toLong());
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
 */
937
void CPackages::ConvertOldPackage(CBaseFile *package)
938
{
939
	for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {
940
		if ( gNode->Data()->iGame == -1 ) {
941
			// all versions
942
			if ( gNode->Data()->iVersion == 0 )
943
				gNode->Data()->iGame = 0;
944
			else
945
			{
946
				int version = 0;
197 cycrow 947
				gNode->Data()->iGame = m_gameExe.convertGameType(gNode->Data()->iVersion, &version);
1 cycrow 948
				gNode->Data()->iVersion = version;
949
			}
950
		}
951
	}
952
 
213 cycrow 953
	if ( package->forumLink().empty() && package->webSite().contains(L"forum.egosoft")) {
49 cycrow 954
		package->setForumLink(package->webSite());
213 cycrow 955
		package->setWebSite(L"");
1 cycrow 956
	}
957
 
958
	// convert the version
959
	if ( package->GetType() == TYPE_SPK )
960
	{
961
		CSpkFile *spk = (CSpkFile *)package;
6 cycrow 962
		if ( spk->GetScriptType() == CSpkFile::SCRIPTTYPE_CUSTOM )
1 cycrow 963
		{
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
 
197 cycrow 1117
int CPackages::checkOpenPackage(const Utils::WString &file, int *error)
1 cycrow 1118
{
1119
	// first check if it exists
182 cycrow 1120
	if (!CFileIO::Exists(file))
1 cycrow 1121
	{
1122
		*error = INSTALLERR_NOEXIST;
1123
		return -1;
1124
	}
1125
 
1126
	// open the spk file
1127
	float fVersion = 0.0f;
182 cycrow 1128
	int check = CBaseFile::CheckFile(file, &fVersion);
1 cycrow 1129
 
1130
	// wrong version
1131
	if ( fVersion > (float)FILEVERSION )
1132
	{
1133
		*error = INSTALLERR_VERSION;
1134
		return -1;
1135
	}
1136
 
1137
	return check;
1138
}
1139
 
197 cycrow 1140
CMultiSpkFile *CPackages::openMultiPackage(const Utils::WString &file, int *error, CProgressInfo *progress)
1 cycrow 1141
{
182 cycrow 1142
	int check = checkOpenPackage(file, error);
1 cycrow 1143
	if ( *error == -1 )
1144
		return false;
1145
 
1146
	if ( check != SPKFILE_MULTI )
1147
	{
1148
		*error = INSTALLERR_NOMULTI;
1149
		return false;
1150
	}
1151
 
1152
	*error = INSTALLERR_NONE;
1153
 
1154
	CMultiSpkFile *package = new CMultiSpkFile;
1155
 
1156
	bool ret = false;
182 cycrow 1157
	if ( package->readFile(file, true))
1 cycrow 1158
	{
177 cycrow 1159
		if ( package->readAllPackages(SPKREAD_NODATA) )
1 cycrow 1160
		{
1161
			for ( CListNode<SMultiSpkFile> *node = package->GetFileList()->Front(); node; node = node->next() )
1162
				this->ConvertOldPackage(node->Data()->pFile);
1163
 
1164
			ret = true;
1165
		}
1166
	}
1167
 
1168
	if ( ret )
1169
		return package;
1170
 
1171
	delete package;
1172
	return NULL;
1173
}
1174
 
197 cycrow 1175
bool CPackages::openMultiPackage(const Utils::WString &file, CLinkList<CBaseFile> *packageList, int *error, CProgressInfo *progress )
1 cycrow 1176
{
182 cycrow 1177
	int check = checkOpenPackage(file, error);
1 cycrow 1178
	if ( *error == -1 )
1179
		return false;
1180
 
1181
	if ( check != SPKFILE_MULTI )
1182
	{
1183
		*error = INSTALLERR_NOMULTI;
1184
		return false;
1185
	}
1186
 
1187
	*error = INSTALLERR_NONE;
1188
 
1189
	CMultiSpkFile *package = new CMultiSpkFile;
1190
 
1191
	bool ret = false;
182 cycrow 1192
	if ( package->readFile(file, true))
1 cycrow 1193
	{
177 cycrow 1194
		if ( package->readAllPackages(SPKREAD_ALL, packageList) )
1 cycrow 1195
		{
1196
			for ( CListNode<CBaseFile> *node = packageList->Front(); node; node = node->next() )
1197
				this->ConvertOldPackage(node->Data());
1198
 
1199
 
1200
			ret = true;
1201
		}
1202
	}
1203
 
1204
	delete package;
1205
 
1206
	return ret;
1207
}
1208
 
221 cycrow 1209
int CPackages::prepareMultiPackage(const Utils::WString &file, CLinkList<CBaseFile> *errorPackageList, int *error, CProgressInfo *progress)
1 cycrow 1210
{
182 cycrow 1211
	int check = checkOpenPackage(file, error);
1 cycrow 1212
	if ( *error == -1 )
1213
		return 0;
1214
 
1215
	if ( check != SPKFILE_MULTI )
1216
	{
1217
		*error = INSTALLERR_NOMULTI;
1218
		return 0;
1219
	}
1220
 
1221
	*error = INSTALLERR_NONE;
1222
 
1223
	CMultiSpkFile *package = new CMultiSpkFile;
1224
 
1225
	int count = 0;
182 cycrow 1226
	if ( package->readFile(file, true))
1 cycrow 1227
	{
1228
		CLinkList<CBaseFile> packageList;
177 cycrow 1229
		if ( package->readAllPackages(SPKREAD_ALL, &packageList) )
1 cycrow 1230
		{
1231
			for ( CListNode<CBaseFile> *node = packageList.Front(); node; node = node->next() )
1232
			{
1233
				CBaseFile *p = node->Data();
1234
				this->ConvertOldPackage(p);
1235
				int error = this->PrepareInstallPackage(p);
1236
				if ( error )
1237
				{
1238
					node->Data()->SetLoadError(error);
1239
					errorPackageList->push_back(p);
1240
				}
1241
				else
1242
					++count;
1243
			}
1244
		}
1245
		packageList.clear();
1246
	}
1247
 
1248
	for ( SMultiSpkFile *ms = package->GetFileList()->First(); ms; ms = package->GetFileList()->Next() )
1249
		ms->pFile = NULL;
1250
	delete package;
1251
 
1252
	return count;
1253
}
1254
 
197 cycrow 1255
CBaseFile *CPackages::openPackage(const Utils::WString &file, int *error, CProgressInfo *progress, int readtype, int flags)
1 cycrow 1256
{
182 cycrow 1257
	int check = checkOpenPackage(file, error);
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
	{
4747
		int size = 0;
197 cycrow 4748
		std::vector<Utils::WString> data;
4749
		if(!(*itr)->data.tokenise(L":", data))			
4750
			continue; // huh ? we shouldn't have this
1 cycrow 4751
 
4752
		// lets search for a matching id
4753
		int useId = 0;
4754
		bool found = false;
4755
		for ( int i = 0; i < size; i++ )
4756
		{
197 cycrow 4757
			if ( data[i] == L"NULL" )
1 cycrow 4758
				useId = -1;
4759
			else
4760
			{
160 cycrow 4761
				int num = data[i].toInt();
1 cycrow 4762
				if ( num == m_iLanguage )
4763
				{
4764
					found = true;
4765
					useId = m_iLanguage;
4766
					break;
4767
				}
4768
				// prioities the text file to use, no language first, then 44, then 49, otherwise, we pick the first available
4769
				else if ( num == 44 && useId != -1)
4770
					useId = 44;
4771
				// if we have a german language, and its not yet found english or null
4772
				else if ( num == 49 && useId != 44 && useId != -1 )
4773
					useId = 49;
4774
				// if we have not found a valid language yet, we will use this one
4775
				else if ( !useId )
4776
					useId = num;
4777
			}
4778
		}
4779
 
160 cycrow 4780
		if (found)
1 cycrow 4781
			continue;
4782
 
4783
		if ( !useId )
160 cycrow 4784
			useId = data[0].toInt();
1 cycrow 4785
		if ( !useId )
4786
			useId = -1;
4787
 
197 cycrow 4788
		renameTextFile((*itr)->str, useId, errors);
1 cycrow 4789
	}
4790
}
4791
 
4792
/**
4793
 * Rename a text file
4794
 *
160 cycrow 4795
 * Creates a new text file for the selected langage by copying an existing one
1 cycrow 4796
 */
197 cycrow 4797
bool CPackages::renameTextFile(const Utils::WString &textid, int languageid, Utils::WStringList *errors)
1 cycrow 4798
{
4799
	// lets check if the file already exists
197 cycrow 4800
	Utils::WString newFilename = SPK::FormatTextName(textid.toInt(), m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT));
4801
	C_File *addFile = findFile(FILETYPE_TEXT, newFilename + L".xml");
1 cycrow 4802
	if ( !addFile )
197 cycrow 4803
		addFile = findFile(FILETYPE_TEXT, newFilename + L".pck");
1 cycrow 4804
 
4805
	// we have found the file, lets just add it to our scripts
4806
	if ( addFile )
4807
	{
182 cycrow 4808
		addTextFileToScripts(addFile, textid);
1 cycrow 4809
		return true;
4810
	}
4811
 
4812
	// first we need to find our text file
197 cycrow 4813
	Utils::WString filename;
1 cycrow 4814
	if ( languageid != -1 )
160 cycrow 4815
		filename = SPK::FormatTextName(textid.toInt(), languageid, (m_iGameFlags & EXEFLAG_TCTEXT));
1 cycrow 4816
	else
160 cycrow 4817
		filename = textid;
1 cycrow 4818
 
197 cycrow 4819
	C_File *textFile = findFile(FILETYPE_TEXT, filename + L".xml");
1 cycrow 4820
	if ( !textFile )
4821
	{
197 cycrow 4822
		textFile = findFile(FILETYPE_TEXT, filename + L".pck");
1 cycrow 4823
		if ( !textFile )
4824
			return false;
4825
	}
4826
 
4827
	// now lets create out new text file
160 cycrow 4828
	CFileIO readFile(textFile->filePointer());
1 cycrow 4829
 
197 cycrow 4830
	std::vector<Utils::WString> lines;
4831
	readFile.readLines(lines);
4832
 
1 cycrow 4833
	// find the language id in the lines
197 cycrow 4834
	std::vector<Utils::WString> frontLines;
4835
	for(std::vector<Utils::WString>::iterator it = lines.begin(); it != lines.end(); ++it)
1 cycrow 4836
	{
197 cycrow 4837
		Utils::WString line = *it;
4838
		int pos = line.findPos(L"<language id");
1 cycrow 4839
		if ( pos != -1)
4840
		{
197 cycrow 4841
			Utils::WString newLine = L"<language id=\"";
4842
			newLine += Utils::WString::Number(m_iLanguage);
4843
			newLine += L"\">";
4844
			newLine += line.tokens(L">", 2);
1 cycrow 4845
 
4846
			frontLines.insert(frontLines.begin(), newLine);
4847
 
197 cycrow 4848
			lines.erase(lines.begin(), ++it);
1 cycrow 4849
			break;
4850
		}
4851
		frontLines.insert(frontLines.begin(), line);
4852
	}
4853
 
197 cycrow 4854
	for(std::vector<Utils::WString>::iterator it = frontLines.begin(); it != frontLines.end(); ++it)
4855
		lines.insert(lines.begin(), *it);
1 cycrow 4856
 
130 cycrow 4857
	addFile = new C_File(newFilename + ".xml");
160 cycrow 4858
	addFile->setFileType(FILETYPE_TEXT);
1 cycrow 4859
 
197 cycrow 4860
	CFileIO writeFile(m_sCurrentDir + L"/" + addFile->getNameDirectory(NULL));
160 cycrow 4861
	if ( writeFile.writeFile(lines) )
1 cycrow 4862
	{
160 cycrow 4863
		this->addLogEntry(SPKINSTALL_WRITEFILE, addFile->getNameDirectory(NULL), errors);
1 cycrow 4864
 
197 cycrow 4865
		addFile->setFilename(m_sCurrentDir + L"/" + addFile->getNameDirectory(NULL));
1 cycrow 4866
		// now we have the file wrriten, we need to add it to all scripts that need it
4867
		// first we add it to the global list
4868
		m_lFiles.push_back(addFile);
4869
 
4870
		// now add it to the scripts
182 cycrow 4871
		addTextFileToScripts(addFile, textid);
1 cycrow 4872
	}
4873
	else
4874
	{
160 cycrow 4875
		this->addLogEntry(SPKINSTALL_WRITEFILE_FAIL, addFile->getNameDirectory(NULL), errors);
1 cycrow 4876
		return false;
4877
	}
4878
 
4879
	return true;
4880
}
4881
 
4882
/**
4883
 * Add file to scripts
4884
 *
4885
 * Adds a file to all scripts that need it
4886
 */
197 cycrow 4887
void CPackages::addTextFileToScripts(C_File *file, const Utils::WString &textid)
1 cycrow 4888
{
4889
	// now we need to find all scripts that have a matching file and add this to the list
4890
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
4891
	{
4892
		CBaseFile *package = node->Data();
4893
 
4894
		// first make sure it doesn't already exist
4895
		if ( package->GetFileList()->FindData(file) )
4896
			continue;
4897
 
4898
		bool found = false;
4899
		for ( CListNode<C_File> *fNode = package->GetFileList()->Front(); fNode; fNode = fNode->next() )
4900
		{
4901
			C_File *tFile = fNode->Data();
4902
			if ( tFile->GetFileType() != FILETYPE_TEXT )
4903
				continue;
4904
 
197 cycrow 4905
			Utils::WString id = tFile->baseName().token(L"-", 1);
182 cycrow 4906
			if ( id == textid )
1 cycrow 4907
			{
4908
				found = true;
4909
				break;
4910
			}
4911
		}
4912
 
4913
		if ( found )
4914
			package->GetFileList()->push_back(file);
4915
	}
4916
}
4917
 
197 cycrow 4918
bool CPackages::removeFile(C_File *file, Utils::WStringList *errors)
1 cycrow 4919
{
4920
	if ( !file )
4921
		return true;
4922
 
197 cycrow 4923
	Utils::WString remFileStr = file->filePointer().findReplace(m_sCurrentDir, L"");
1 cycrow 4924
 
197 cycrow 4925
	if ( file->filePointer().contains(L"::")) {
4926
		CFileIO CatFile(file->filePointer().token(L"::", 1));
52 cycrow 4927
		if ( CatFile.exists() ) {
1 cycrow 4928
			CCatFile cat;
202 cycrow 4929
			if ( cat.open(CatFile.fullFilename(), this->getAddonDir(), CATREAD_DAT, false) == CATERR_NONE) {
197 cycrow 4930
				Utils::WString fileName = file->filePointer().token(L"::", 2);
181 cycrow 4931
				if ( cat.findData(fileName) ) {
178 cycrow 4932
					if ( cat.removeFile(fileName) ) {
183 cycrow 4933
						this->addLogEntry(SPKINSTALL_DELETEFILE, remFileStr, errors);
1 cycrow 4934
					}
4935
					else {
183 cycrow 4936
						this->addLogEntry(SPKINSTALL_DELETEFILE_FAIL, remFileStr, errors);
1 cycrow 4937
						return false;
4938
					}
4939
				}
4940
			}
4941
		}
4942
	}
4943
	else {
158 cycrow 4944
		CFileIO f(file->filePointer());
52 cycrow 4945
		if ( f.exists() )
1 cycrow 4946
		{
183 cycrow 4947
			if ( f.remove() ) this->addLogEntry(SPKINSTALL_DELETEFILE, remFileStr, errors);
1 cycrow 4948
			else if ( errors )
4949
			{
183 cycrow 4950
				this->addLogEntry(SPKINSTALL_DELETEFILE_FAIL, remFileStr, errors);
1 cycrow 4951
				return false;
4952
			}
4953
			else
4954
				return false;
4955
		}
4956
	}
4957
 
4958
	return true;
4959
}
4960
 
197 cycrow 4961
int CPackages::removeAllPackages(Utils::WStringList *errors, CProgressInfo *progress)
1 cycrow 4962
{
4963
	int files = 0;
4964
 
4965
	// remove all files
93 cycrow 4966
	int max = m_lFiles.size() + _pOriginalFiles->count() + m_lUninstallFiles.size();
1 cycrow 4967
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
4968
	{
4969
		// update the progress
4970
		if ( progress )
4971
			progress->UpdateProgress(files, max);
4972
		++files;
4973
 
183 cycrow 4974
		removeFile(node->Data());
1 cycrow 4975
		delete node->Data();
4976
	}
4977
	m_lFiles.clear();
4978
 
4979
	// restore any original files that are backed up
93 cycrow 4980
	//TODO: find a better way to do the progress
4981
	files = _pOriginalFiles->restoreAll(progress, files, max);
1 cycrow 4982
 
4983
	// remove any uninstall files that remain
4984
	for ( CListNode<C_File> *uNode = m_lUninstallFiles.Front(); uNode; uNode = uNode->next() )
4985
	{
4986
		// update the progress
4987
		if ( progress )
4988
			progress->UpdateProgress(files, max);
4989
		++files;
4990
 
183 cycrow 4991
		removeFile(uNode->Data());
1 cycrow 4992
		delete uNode->Data();
4993
	}
4994
	m_lUninstallFiles.clear();
4995
 
4996
	// delete all packages
4997
	for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )
4998
	{
4999
		// clear file list as we have removed them already
5000
		pNode->Data()->GetFileList()->clear();
5001
		// delete the memory for the package
5002
		delete pNode->Data();
5003
	}
5004
	m_lPackages.clear();
5005
 
5006
	return files;
5007
}
5008
 
5009
/**
5010
 * Get Install Before Text
5011
 *
5012
 * Returns the install before text for the package in the correct language
5013
 */
206 cycrow 5014
Utils::WString CPackages::getInstallBeforeText(CBaseFile *package) const
1 cycrow 5015
{
46 cycrow 5016
	return package->installText(m_iLanguage, true);
1 cycrow 5017
}
206 cycrow 5018
Utils::WString CPackages::getInstallAfterText(CBaseFile *package) const
1 cycrow 5019
{
46 cycrow 5020
	return package->installText(m_iLanguage, false);
1 cycrow 5021
}
206 cycrow 5022
Utils::WString CPackages::getUninstallBeforeText(CBaseFile *package) const
1 cycrow 5023
{
46 cycrow 5024
	return package->uninstallText(m_iLanguage, true);
1 cycrow 5025
}
206 cycrow 5026
Utils::WString CPackages::getUninstallAfterText(CBaseFile *package) const
1 cycrow 5027
{
46 cycrow 5028
	return package->uninstallText(m_iLanguage, false);
1 cycrow 5029
}
5030
 
5031
int CPackages::GetChildPackages(CBaseFile *package, CLinkList<CBaseFile> *children, bool recursive)
5032
{
5033
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5034
	{
5035
		CBaseFile *p = node->Data();
5036
		if ( p->GetParent() == package )
5037
		{
5038
			children->push_back(p);
5039
 
5040
			if ( recursive )
5041
				this->GetChildPackages(p, children, recursive);
5042
		}
5043
	}
5044
 
5045
	return children->size();
5046
}
5047
 
5048
void CPackages::AssignPackageNumbers()
5049
{
5050
	int num = 0;
5051
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5052
		node->Data()->SetNum(num++);
5053
}
5054
 
196 cycrow 5055
Utils::WString CPackages::findDataDir(const Utils::WString &dir, const Utils::WString &file)
1 cycrow 5056
{
127 cycrow 5057
	CDirIO Dir(dir);
125 cycrow 5058
 
1 cycrow 5059
	// data files could be in 4 places depending on what program is used, check for all of these
127 cycrow 5060
	if (Dir.exists(file))
125 cycrow 5061
		return Dir.file(file);
196 cycrow 5062
	else if (Dir.exists(L"Data/" + file))
5063
		return Dir.file(L"Data/" + file);
5064
	else if (Dir.exists(L"../" + file))
5065
		return Dir.file(L"../" + file);
5066
	else if (Dir.exists(L"../Data/" + file))
5067
		return Dir.file(L"../Data/" + file);
1 cycrow 5068
 
196 cycrow 5069
	return Utils::WString::Null();
1 cycrow 5070
}
5071
 
197 cycrow 5072
void CPackages::startup(const Utils::WString &dir, const Utils::WString &tempDir, const Utils::WString &myDoc)
1 cycrow 5073
{
127 cycrow 5074
	this->setTempDirectory(tempDir);
5075
	this->setMyDocuments(myDoc);
1 cycrow 5076
 
5077
	// need to read the game exe versions
5078
	m_gameExe.Reset();
5079
 
196 cycrow 5080
	Utils::WString exeFile = this->findDataDir(dir, L"exe");
1 cycrow 5081
 
5082
	// if file exists, read it, otherwise, just add
127 cycrow 5083
	if (!exeFile.empty() && CFileIO::Exists(exeFile))
197 cycrow 5084
		m_gameExe.readFile(exeFile);
1 cycrow 5085
	else
5086
	{
233 cycrow 5087
		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");
5088
		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");
5089
		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");
5090
		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 5091
		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 5092
	}
5093
}
197 cycrow 5094
void CPackages::startup(const Utils::WString &dir, const Utils::WString &tempDir, const Utils::WString &myDoc, const Utils::WString &mod)
127 cycrow 5095
{
5096
	startup(dir, tempDir, myDoc);
5097
	m_sSetMod = mod;
5098
}
1 cycrow 5099
 
182 cycrow 5100
int CPackages::getGameLanguage() const
1 cycrow 5101
{
182 cycrow 5102
	return this->getGameLanguage(m_sCurrentDir);
121 cycrow 5103
}
197 cycrow 5104
int CPackages::getGameLanguage(const Utils::WString &sDir) const
121 cycrow 5105
{
197 cycrow 5106
	Utils::WString dir = sDir;
121 cycrow 5107
	if (dir.empty())
158 cycrow 5108
		dir = m_sCurrentDir;
121 cycrow 5109
	else
5110
		dir = this->getProperDir(dir);
1 cycrow 5111
 
5112
	CDirIO Dir(dir);
5113
 
5114
	// check for lang.dat file
197 cycrow 5115
	if ( Dir.exists(L"lang.dat") )
1 cycrow 5116
	{
197 cycrow 5117
		CFileIO File(Dir.file(L"lang.dat"));
1 cycrow 5118
 
5119
		size_t size;
5120
		char *data = File.ReadToData(&size);
5121
 
5122
		if ( data )
5123
		{
221 cycrow 5124
			Utils::WString str(data);
5125
			return str.token(L"\n", 1).token(L" ", 1).toLong();
1 cycrow 5126
		}
5127
	}
5128
 
5129
	return 0;
5130
}
197 cycrow 5131
Utils::WString CPackages::getGameRunExe(const Utils::WString &dir) const
1 cycrow 5132
{
197 cycrow 5133
	return m_gameExe.gameRunExe(dir);
1 cycrow 5134
}
197 cycrow 5135
Utils::WString CPackages::getGameRunExe() const
121 cycrow 5136
{
197 cycrow 5137
	return m_gameExe.gameRunExe(m_sCurrentDir);
121 cycrow 5138
}
1 cycrow 5139
 
197 cycrow 5140
Utils::WString CPackages::getGameNameFromType(int game) const
1 cycrow 5141
{
197 cycrow 5142
	return m_gameExe.gameNameFromType(game - 1);
1 cycrow 5143
}
197 cycrow 5144
Utils::WString CPackages::getGameName() const
121 cycrow 5145
{
158 cycrow 5146
	return getGameName(m_sCurrentDir);
121 cycrow 5147
}
5148
 
197 cycrow 5149
Utils::WString CPackages::getGameName(const Utils::WString &dir) const
121 cycrow 5150
{
197 cycrow 5151
	return m_gameExe.gameName(dir.empty() ? m_sCurrentDir : dir);
121 cycrow 5152
}
5153
 
197 cycrow 5154
Utils::WString CPackages::getProperDir() const
1 cycrow 5155
{
158 cycrow 5156
	return getProperDir(m_sCurrentDir);
1 cycrow 5157
}
197 cycrow 5158
Utils::WString CPackages::getProperDir(const Utils::WString &dir) const
121 cycrow 5159
{
197 cycrow 5160
	return m_gameExe.properDir((dir.empty()) ? m_sCurrentDir : dir);
121 cycrow 5161
}
197 cycrow 5162
Utils::WString CPackages::getAddonDir() const
121 cycrow 5163
{
158 cycrow 5164
	return getAddonDir(m_sCurrentDir);
121 cycrow 5165
}
197 cycrow 5166
Utils::WString CPackages::getAddonDir(const Utils::WString &dir) const
121 cycrow 5167
{
197 cycrow 5168
	return m_gameExe.addonDir((dir.empty()) ? m_sCurrentDir : dir);
121 cycrow 5169
}
197 cycrow 5170
int CPackages::getGameAddons(Utils::WStringList &exes, const Utils::WString &dir) const
121 cycrow 5171
{
182 cycrow 5172
	return m_gameExe.getGameAddons((dir.empty()) ? m_sCurrentDir : dir, exes);
121 cycrow 5173
}
197 cycrow 5174
int CPackages::getGameAddons(Utils::WStringList &exes) const
121 cycrow 5175
{
182 cycrow 5176
	return m_gameExe.getGameAddons(m_sCurrentDir, exes);
121 cycrow 5177
}
1 cycrow 5178
 
197 cycrow 5179
Utils::WString CPackages::getGameTypesString(CBaseFile *package, bool includeVersion) const
1 cycrow 5180
{
5181
	if ( !package->AnyGameCompatability() )
197 cycrow 5182
		return L"";
1 cycrow 5183
 
197 cycrow 5184
	Utils::WString sGames;
1 cycrow 5185
	for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {
98 cycrow 5186
		if ( !sGames.empty() )
197 cycrow 5187
			sGames += L", ";
5188
		sGames += m_gameExe.gameNameFromType(gNode->Data()->iGame - 1);
1 cycrow 5189
		if ( includeVersion ) {
197 cycrow 5190
			Utils::WString version = m_gameExe.gameVersionFromType(gNode->Data()->iGame - 1, gNode->Data()->iVersion - 1, gNode->Data()->sVersion);
98 cycrow 5191
			if ( !version.empty() ) {
197 cycrow 5192
				sGames += L" (";
98 cycrow 5193
				sGames += version;
197 cycrow 5194
				sGames += L")";
98 cycrow 5195
			}
1 cycrow 5196
		}
5197
	}
5198
	return sGames;
5199
}
5200
 
197 cycrow 5201
Utils::WString CPackages::getGameVersionString(CBaseFile *package) const
1 cycrow 5202
{
5203
	for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {
5204
		if ( gNode->Data()->iGame == m_iGame ) {
197 cycrow 5205
			return m_gameExe.gameVersionFromType(m_iGame - 1, gNode->Data()->iVersion - 1, gNode->Data()->sVersion);
1 cycrow 5206
		}
5207
	}
5208
 
197 cycrow 5209
	return Utils::WString::Null();
1 cycrow 5210
}
5211
 
197 cycrow 5212
Utils::WString CPackages::getGameVersionFromType(int game, int version, const Utils::WString &sVersion) const
1 cycrow 5213
{
197 cycrow 5214
	return m_gameExe.gameVersionFromType(game - 1, version - 1, sVersion);
1 cycrow 5215
}
5216
 
5217
int CPackages::CountBuiltInPackages(bool onlyEnabled)
5218
{
5219
	int count = 0;
5220
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5221
	{
5222
		if ( !node->Data()->CheckGameCompatability(m_iGame) )
5223
			continue;
5224
		if ( onlyEnabled && !node->Data()->IsEnabled() )
5225
			continue;
213 cycrow 5226
		if ( node->Data()->author().Compare(L"PluginManager") )
1 cycrow 5227
			++count;
5228
	}
5229
 
5230
	return count;
5231
}
5232
 
179 cycrow 5233
int CPackages::countPackages(int type, bool onlyEnabled) const
1 cycrow 5234
{
5235
	int count = 0;
5236
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5237
	{
5238
		CBaseFile *p = node->Data();
5239
 
5240
		if ( (type != TYPE_BASE) && (p->GetType() != type) )
5241
			continue;
5242
 
5243
		if ( (onlyEnabled) && (!p->IsEnabled()) )
5244
			continue;
5245
 
5246
		++count;
5247
	}
5248
 
5249
	return count;
5250
}
5251
 
197 cycrow 5252
int CPackages::extractGameFile(const Utils::WString &aFilename, const Utils::WString &aTo, const Utils::WString &aDir, const Utils::WString &addon) const
1 cycrow 5253
{
5254
	// first check the enabled mod
197 cycrow 5255
	Utils::WString dir = aDir;
173 cycrow 5256
	if (dir.empty())
1 cycrow 5257
		dir = m_sCurrentDir;
5258
 
197 cycrow 5259
	Utils::WString addonDir = addon;
173 cycrow 5260
	if (addonDir.empty()) addonDir = this->getAddonDir(dir);
1 cycrow 5261
 
173 cycrow 5262
	if (m_pEnabledMod && m_pEnabledMod->AnyFileType(FILETYPE_MOD))
1 cycrow 5263
	{
173 cycrow 5264
		for (C_File* file = m_pEnabledMod->GetFirstFile(FILETYPE_MOD); file; file = m_pEnabledMod->GetNextFile(file))
1 cycrow 5265
		{
197 cycrow 5266
			if (!file->checkFileExt(L"cat"))
1 cycrow 5267
				continue;
5268
 
5269
			CCatFile catFile;
173 cycrow 5270
			if (catFile.open(file->filePointer(), addonDir, CATREAD_CATDECRYPT, false) == CATERR_NONE)
1 cycrow 5271
			{
181 cycrow 5272
				if (catFile.extractFile(aFilename, aTo))
1 cycrow 5273
					return 1;
173 cycrow 5274
				if (catFile.error() == CATERR_INVALIDDEST || catFile.error() == CATERR_CANTCREATEDIR)
1 cycrow 5275
				{
181 cycrow 5276
					if (catFile.extractFile(aFilename))
1 cycrow 5277
						return -1;
5278
				}
5279
 
5280
			}
5281
		}
5282
	}
173 cycrow 5283
	else if (!m_sSetMod.empty())
1 cycrow 5284
	{
197 cycrow 5285
		if (CFileIO::Exists(m_sCurrentDir + L"/mods/" + m_sSetMod + L".cat"))
1 cycrow 5286
		{
5287
			CCatFile catFile;
221 cycrow 5288
			if (catFile.open(m_sCurrentDir + L"/mods/" + m_sSetMod + L".cat", addonDir, CATREAD_CATDECRYPT, false) == CATERR_NONE)
1 cycrow 5289
			{
181 cycrow 5290
				if (catFile.extractFile(aFilename, aTo))
1 cycrow 5291
					return 1;
173 cycrow 5292
				if (catFile.error() == CATERR_INVALIDDEST || catFile.error() == CATERR_CANTCREATEDIR)
1 cycrow 5293
				{
181 cycrow 5294
					if (catFile.extractFile(aFilename))
1 cycrow 5295
						return -1;
5296
				}
5297
			}
5298
		}
5299
	}
5300
 
5301
	// find the highest cat number
5302
	int catNumber = 1;
197 cycrow 5303
	while (CFileIO::Exists(dir + L"/" + Utils::WString::PadNumber(catNumber, 2) + L".cat") && catNumber < 99)
1 cycrow 5304
		++catNumber;
5305
 
5306
	// get the last one, not the next free one
5307
	--catNumber;
5308
 
5309
	// work backwards until we find the file
173 cycrow 5310
	for (; catNumber; catNumber--)
1 cycrow 5311
	{
5312
		CCatFile catFile;
221 cycrow 5313
		if (catFile.open((dir + L"/" + Utils::WString::PadNumber(catNumber, 2) + L".cat"), addonDir, CATREAD_CATDECRYPT, false) == CATERR_NONE)
1 cycrow 5314
		{
5315
			// check for the file
181 cycrow 5316
			if (catFile.extractFile(aFilename, aTo))
1 cycrow 5317
				return 1;
173 cycrow 5318
			if (catFile.error() == CATERR_INVALIDDEST || catFile.error() == CATERR_CANTCREATEDIR)
1 cycrow 5319
			{
181 cycrow 5320
				if (catFile.extractFile(aFilename))
1 cycrow 5321
					return -1;
5322
			}
5323
		}
5324
	}
5325
 
5326
	return 0;
5327
}
5328
 
5329
void CPackages::CreateWareFiles()
5330
{
5331
	// do each ware
5332
	int wareTextID = WARETEXTSTART;
5333
	for ( int i = 0; i < WAREBUFFERS; i++ )
5334
	{
5335
		// its empty, no need to create ware files
5336
		if ( !m_lGameWares[i].size() )
5337
			continue;
5338
 
5339
		// lets extract the ware file
197 cycrow 5340
		wchar_t wareType = CPackages::ConvertWareTypeBack(i);
5341
		Utils::WString wareFile = L"TWare";
218 cycrow 5342
		wareFile += (wchar_t)std::toupper(wareType);
1 cycrow 5343
 
197 cycrow 5344
		Utils::WString openFile;
1 cycrow 5345
 
5346
		int e;
197 cycrow 5347
		if ( i == WARES_TECH && CFileIO::Exists(m_sTempDir + L"/TWareT.txt") )
5348
			openFile = m_sTempDir + L"/TWareT.txt";
1 cycrow 5349
		else {
197 cycrow 5350
			e = extractGameFile(L"types/" + wareFile + L".pck", m_sTempDir + L"/" + wareFile + L".txt");
1 cycrow 5351
			if ( e == 1 )
197 cycrow 5352
				openFile = m_sTempDir + L"/" + wareFile + L".txt";
1 cycrow 5353
			else if ( e == -2 )
197 cycrow 5354
				openFile = wareFile + L".txt";
1 cycrow 5355
		}
5356
 
181 cycrow 5357
		if ( !openFile.empty() )
1 cycrow 5358
		{
5359
			// read the file into memory
197 cycrow 5360
			Utils::WStringList wareLines;
160 cycrow 5361
			size_t oldSize = -1;
1 cycrow 5362
			int version = -1;
5363
 
5364
			// read first number
197 cycrow 5365
			CFileIO readFile(m_sTempDir + L"/" + wareFile + L".txt");
5366
			std::vector<Utils::WString> lines;
5367
			if(readFile.readLines(lines))
1 cycrow 5368
			{
197 cycrow 5369
				for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 5370
				{
197 cycrow 5371
					Utils::WString line = *itr;
160 cycrow 5372
					line.removeFirstSpace();
5373
					line.removeChar(9);
5374
					line.removeChar('\r');
5375
					if ( line.empty() )
1 cycrow 5376
						continue;
5377
					if ( line[0] == '/' )
5378
						continue;
5379
 
5380
					if ( oldSize == -1 )
5381
					{
197 cycrow 5382
						version = line.token(L";", 1).toInt();
5383
						oldSize = line.token(L";", 2).toInt();
1 cycrow 5384
					}
5385
					else
5386
					{
160 cycrow 5387
						line.removeEndSpace();
197 cycrow 5388
						if ( line.back() != L';')
5389
							line += L";";
160 cycrow 5390
						wareLines.pushBack(line);
5391
						if ( wareLines.size() >= oldSize )
1 cycrow 5392
							break;
5393
					}
5394
				}
5395
 
5396
				// apply the buffer
5397
				if ( m_iWareBuffer[i] <= 0 )
160 cycrow 5398
					m_iWareBuffer[i] = wareLines.size() + 10;
1 cycrow 5399
				// last resort, readjust the buffer
160 cycrow 5400
				else if ( wareLines.size() > static_cast<size_t>(m_iWareBuffer[i]) )
5401
					m_iWareBuffer[i] = wareLines.size();
1 cycrow 5402
 
5403
				// add the buffers
160 cycrow 5404
				while ( wareLines.size() < static_cast<size_t>(m_iWareBuffer[i]) )
197 cycrow 5405
					wareLines.pushBack(L"27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_FILLER;");
1 cycrow 5406
 
5407
				// add the ware lines
5408
				bool create = false;
5409
				for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() )
5410
				{
5411
					SGameWare *w = node->Data();
5412
 
5413
					if ( w->iType == WARETYPE_NONE )
5414
						continue;
5415
					else if ( w->iType == WARETYPE_DISABLED )
5416
					{
5417
						create = true;
197 cycrow 5418
						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 5419
					}
5420
					else if ( w->iType == WARETYPE_DELETED || !w->pWare )
5421
					{
5422
						create = true;
249 cycrow 5423
						wareLines.pushBack(L"27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_DELETED;");						
1 cycrow 5424
					}
5425
					else if ( w->iType == WARETYPE_ADDED )
5426
					{
5427
						create = true;
5428
						w->pWare->iDescID = wareTextID;
5429
						w->iText = wareTextID;
5430
						wareTextID += 10;
160 cycrow 5431
						w->iPos = wareLines.size();
88 cycrow 5432
						long price = this->customWareOveridePrice(w->pWare->sID);
5433
						int notority = w->pWare->iNotority;
5434
						if ( !this->customWareOverideNoto(w->pWare->sID, &notority) ) notority = w->pWare->iNotority;
5435
						if ( !price ) price = w->pWare->iPrice;
5436
 
197 cycrow 5437
						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 5438
					}
5439
				}
5440
 
5441
				if ( create )
5442
				{
221 cycrow 5443
					wareLines.pushFront(Utils::WString::Number(version) + L";" + Utils::WString::Number(wareLines.size()) + L";", Utils::WString::Null());
197 cycrow 5444
					Utils::WString strV = Utils::WString::FromFloat(GetLibraryVersion(), 2);
5445
					wareLines.pushFront("// Created by SPKInstaller Libraries V" + strV, Utils::WString::Null());
160 cycrow 5446
					if ( readFile.writeFile(&wareLines) )
197 cycrow 5447
						this->packFile(&readFile, L"types\\" + wareFile + L".pck");
1 cycrow 5448
				}
5449
			}
52 cycrow 5450
			readFile.remove();
1 cycrow 5451
		}
5452
	}
5453
}
5454
 
197 cycrow 5455
Utils::WString CPackages::empWaresForGame(size_t *maxsize)
1 cycrow 5456
{
88 cycrow 5457
	if ( maxsize ) (*maxsize) = 0;
1 cycrow 5458
 
5459
	if ( m_iGame == GAME_X3TC )
5460
	{
88 cycrow 5461
		if ( maxsize ) (*maxsize) = EMP_X3TC;
5462
		return GetX3TCEmp();
1 cycrow 5463
	}
126 cycrow 5464
	else if (m_iGame == GAME_X3AP)
1 cycrow 5465
	{
126 cycrow 5466
		if (maxsize) (*maxsize) = EMP_X3AP;
88 cycrow 5467
		return GetX3TCEmp();
1 cycrow 5468
	}
126 cycrow 5469
	else if (m_iGame == GAME_X3FL)
5470
	{
5471
		if (maxsize) (*maxsize) = EMP_X3FL;
5472
		return GetX3TCEmp();
5473
	}
1 cycrow 5474
	else if ( m_iGame == GAME_X3 )
5475
	{
88 cycrow 5476
		if ( maxsize ) (*maxsize) = EMP_X3;
5477
		return GetX3Emp();
1 cycrow 5478
	}
5479
 
221 cycrow 5480
	return Utils::WString::Null();
88 cycrow 5481
}
5482
 
197 cycrow 5483
void CPackages::_addWareOverride(enum WareTypes type, int pos, const Utils::WString &id, int value, bool noto)
88 cycrow 5484
{
5485
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
5486
		SWarePriceOverride *wp = node->Data();
5487
		if ( wp->type == type ) {
5488
			if ( wp->type == Ware_Custom && !wp->id.Compare(id) ) continue;
5489
			else if ( wp->type != Ware_Custom && wp->pos != pos ) continue;
5490
			if ( noto ) {
5491
				wp->notority  = value;
89 cycrow 5492
				wp->bNotority = true;
88 cycrow 5493
			}
5494
			else wp->relval = value;
5495
			return;
5496
		}
5497
	}
5498
 
5499
	SWarePriceOverride *ware = new SWarePriceOverride;
5500
	ware->bNotority = noto;
5501
	ware->notority = (noto) ? value : 0;
5502
	ware->relval = (noto) ? 0 : value;
5503
	ware->type = type;
5504
	ware->pos = pos;
5505
	ware->id = id;
5506
 
5507
	m_lWarePrices.push_back(ware);
5508
}
5509
 
5510
void CPackages::addEMPPriceOverride(int empId, int price)
5511
{
197 cycrow 5512
	_addWareOverride(Ware_EMP, empId, Utils::WString::Null(), price, false);
88 cycrow 5513
}
5514
 
5515
void CPackages::addEMPNotoOverride(int empId, int noto)
5516
{
197 cycrow 5517
	_addWareOverride(Ware_EMP, empId, Utils::WString::Null(), noto, true);
88 cycrow 5518
}
5519
 
5520
void CPackages::addBuiltInWarePriceOverride(int empId, int price)
5521
{
197 cycrow 5522
	_addWareOverride(Ware_BuiltIn, empId, Utils::WString::Null(), price, false);
88 cycrow 5523
}
5524
 
5525
void CPackages::addBuiltInWareNotoOverride(int empId, int noto)
5526
{
197 cycrow 5527
	_addWareOverride(Ware_BuiltIn, empId, Utils::WString::Null(), noto, false);
88 cycrow 5528
}
5529
 
197 cycrow 5530
void CPackages::addCustomWarePriceOverride(const Utils::WString &id, int price)
88 cycrow 5531
{
5532
	_addWareOverride(Ware_Custom, 0, id, price, false);
5533
}
5534
 
197 cycrow 5535
void CPackages::addCustomWareNotoOverride(const Utils::WString &id, int noto)
88 cycrow 5536
{
5537
	_addWareOverride(Ware_Custom, 0, id, noto, true);
5538
}
5539
 
5540
 
221 cycrow 5541
void CPackages::createEMPFile(const Utils::WString &progDir)
88 cycrow 5542
{
5543
	// do emp wares
160 cycrow 5544
	size_t maxsize = 0;
197 cycrow 5545
	Utils::WString empWares = empWaresForGame(&maxsize);
88 cycrow 5546
 
1 cycrow 5547
	if ( maxsize )
5548
	{
197 cycrow 5549
		int e = extractGameFile(L"types/TWareT.pck", m_sTempDir + L"/TWareT.txt");
182 cycrow 5550
		if (e)
1 cycrow 5551
		{
5552
			// read the file into memory
197 cycrow 5553
			Utils::WStringList wareLines;
160 cycrow 5554
			size_t oldSize = -1;
1 cycrow 5555
			int version = -1;
5556
 
5557
			// read first number
197 cycrow 5558
			CFileIO readFile((e == -1) ? L"TWareT.txt" : m_sTempDir + L"/TWareT.txt");
5559
			std::vector<Utils::WString> lines;
182 cycrow 5560
			if(readFile.readLines(lines))
1 cycrow 5561
			{
182 cycrow 5562
				for ( int i = 0; i < (int)lines.size(); i++ )
1 cycrow 5563
				{
197 cycrow 5564
					Utils::WString line(lines.at(i));
88 cycrow 5565
					line.removeFirstSpace();
5566
					line.removeChar('\r');
5567
					line.removeChar(9);
1 cycrow 5568
					if ( line[0] == '/' )
5569
						continue;
5570
 
5571
					if ( oldSize == -1 )
5572
					{
197 cycrow 5573
						version = line.token(L";", 1).toLong();
5574
						oldSize = line.token(L";", 2).toLong();
1 cycrow 5575
					}
5576
					else
5577
					{
88 cycrow 5578
						line.removeEndSpace();
197 cycrow 5579
						if ( line.right(1) != L";" )
5580
							line += L";";
88 cycrow 5581
 
5582
						// check for any override values for built in wares
5583
						if ( (i >= 62 && i <= 81) || (i >= 88 && i <= 93) ) {
5584
							int pos = i - ((i >= 88) ? 88 : 62);
5585
							int price = this->builtInWareOveridePrice(pos);
5586
							if ( price ) {
197 cycrow 5587
								line = line.replaceToken(L";", 9, Utils::WString::Number(price));
5588
								line = line.replaceToken(L";", 13, Utils::WString::Number(price));
88 cycrow 5589
							}
5590
 
5591
							int noto = 0;
5592
							if ( this->builtInWareOverideNoto(pos, &noto) ) {
197 cycrow 5593
								line = line.replaceToken(L";", 14, Utils::WString::Number(noto));
88 cycrow 5594
							}
5595
						}
5596
 
5597
						// check for any override values for EMP
5598
						if ( i >= 116 ) {
5599
							int price = this->empOveridePrice(i - 116);
5600
							if ( price ) {
197 cycrow 5601
								line = line.replaceToken(L";", 9, Utils::WString::Number(price));
5602
								line = line.replaceToken(L";", 13, Utils::WString::Number(price));
88 cycrow 5603
							}
5604
 
5605
							int noto = 0;
5606
							if ( this->empOverideNoto(i - 116, &noto) ) {
197 cycrow 5607
								line = line.replaceToken(L";", 14, Utils::WString::Number(noto));
88 cycrow 5608
							}
5609
						}
5610
 
160 cycrow 5611
						wareLines.pushBack(line);
5612
						if ( wareLines.size() >= oldSize )
1 cycrow 5613
							break;
5614
					}
5615
				}
5616
			}
5617
 
5618
			// now we too add/remove entries to match
5619
			// need filler entries
160 cycrow 5620
			while ( wareLines.size() < maxsize )
197 cycrow 5621
				wareLines.pushBack(L"27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_FILLER;");
1 cycrow 5622
 
197 cycrow 5623
			std::vector<Utils::WString> empStr;
5624
			if(empWares.tokenise(L"\n", empStr))
1 cycrow 5625
			{
88 cycrow 5626
				// apply any price overrides
197 cycrow 5627
				size_t empEntries = empStr.size();
5628
				for(size_t i = 0; i < empEntries; i++) {
88 cycrow 5629
					int price = this->empOveridePrice(i);
5630
					if ( price ) {
197 cycrow 5631
						empStr[i] = empStr[i].replaceToken(L";", 9, Utils::WString::Number(price));
5632
						empStr[i] = empStr[i].replaceToken(L";", 13, Utils::WString::Number(price));
88 cycrow 5633
					}
5634
 
5635
					int noto = 0;
5636
					if ( this->empOverideNoto(i, &noto) ) {
197 cycrow 5637
						empStr[i] = empStr[i].replaceToken(L";", 14, Utils::WString::Number(noto));
88 cycrow 5638
					}
5639
				}
1 cycrow 5640
				// remove any empty end entries
88 cycrow 5641
				while ( empStr[empEntries - 1].empty() )
1 cycrow 5642
					--empEntries;
5643
 
197 cycrow 5644
				Utils::WStringList addAfter;
160 cycrow 5645
				if ( wareLines.size() > maxsize )
1 cycrow 5646
				{
5647
					// force emp, remove entries to allow them to be added
5648
					if ( m_bForceEMP )
5649
					{
5650
						// more after emp
160 cycrow 5651
						if ( wareLines.size() > (maxsize + empEntries) )
1 cycrow 5652
						{
160 cycrow 5653
							for (size_t i = (maxsize + empEntries); i < wareLines.size(); i++)
1 cycrow 5654
							{
160 cycrow 5655
								auto node = wareLines.get(i);
5656
								addAfter.pushBack(node->str);
1 cycrow 5657
							}
5658
						}
5659
 
5660
						// no remove them all
160 cycrow 5661
						while (wareLines.size() > maxsize)
5662
							wareLines.removeAt(wareLines.size() - 1);
1 cycrow 5663
					}
126 cycrow 5664
					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 5665
					{
160 cycrow 5666
						if ( wareLines.size() > 128 )
1 cycrow 5667
						{
197 cycrow 5668
							Utils::WString test = wareLines.get(128)->str;
5669
							if ( test.tokens(L";", -2).Compare(L"SS_WARE_SW_CUSTOM16_1;") )
1 cycrow 5670
							{
5671
								// if theres any at the end, remove the last emp entry
160 cycrow 5672
								if ( wareLines.size() > (maxsize + empEntries - 1) )
1 cycrow 5673
								{
160 cycrow 5674
									wareLines.removeAt(maxsize + empEntries - 2);
1 cycrow 5675
								}
197 cycrow 5676
								wareLines.insertAt(128, L"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;128;");
1 cycrow 5677
							}
5678
						}
5679
					}
5680
				}
5681
 
5682
				// too many entries, need to remove the first set of EMP wares
197 cycrow 5683
				size_t i = 0;
160 cycrow 5684
				if ( wareLines.size() > maxsize )
5685
					i = wareLines.size() - maxsize;
1 cycrow 5686
 
5687
				for ( ; i < empEntries; i++ )
5688
				{
197 cycrow 5689
					Utils::WString str = empStr[i];
160 cycrow 5690
					str.removeEndSpace();
5691
					str.removeChar(9);
5692
					str.removeChar('\r');
5693
					if ( str.empty() )
1 cycrow 5694
						continue;
197 cycrow 5695
					if ( str.right(1) != L";")
5696
						str += L";";
160 cycrow 5697
					wareLines.pushBack(str);
1 cycrow 5698
				}
5699
 
160 cycrow 5700
				for(auto afterItr = addAfter.begin(); afterItr != addAfter.end(); afterItr++)
5701
					wareLines.pushBack((*afterItr)->str);
1 cycrow 5702
 
5703
				// finally we write the whole file
197 cycrow 5704
				wareLines.pushFront(Utils::WString::Number(version) + ";" + Utils::WString::Number(wareLines.size()) + L";", Utils::WString::Null());
5705
				wareLines.pushFront(L"// Created by SPKInstaller Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2), Utils::WString::Null());
160 cycrow 5706
				if ( readFile.writeFile(&wareLines) )
197 cycrow 5707
					this->packFile(&readFile, L"types\\TWareT.pck");
1 cycrow 5708
			}
5709
		}
5710
	}
5711
}
5712
 
197 cycrow 5713
Utils::WString parseXmlText(const Utils::WString &str)
17 cycrow 5714
{
197 cycrow 5715
	Utils::WString newStr(str);
5716
	Utils::WStringList changes;
17 cycrow 5717
 
5718
	// find all XML commands, &<command>;
197 cycrow 5719
	Utils::WString sStr = str;
285 cycrow 5720
	std::wstring::size_type pos = sStr.toStdWString().find_first_of(L"&", 0);
5721
	while ( pos != std::wstring::npos ) {
17 cycrow 5722
		// find the next space and next ;.  If ; comes first, assume its acommand
285 cycrow 5723
		std::wstring::size_type spacePos = sStr.toStdWString().find_first_of(L" ", pos);
5724
		std::wstring::size_type colonPos = sStr.toStdWString().find_first_of(L";", pos);
5725
		if ( colonPos != std::wstring::npos && colonPos < spacePos ) {
17 cycrow 5726
			// replace with <::command::> so they the & doesn't get replaced
197 cycrow 5727
			Utils::WString repStr = sStr.substr(pos, (colonPos + 1) - pos);
5728
			Utils::WString repWithStr = L"<::" + sStr.substr(pos + 1, colonPos - pos - 1) + L"::>";
84 cycrow 5729
			newStr = newStr.findReplace(repStr, repWithStr);
185 cycrow 5730
			changes.pushBack(repStr, repWithStr);
17 cycrow 5731
		}
5732
 
5733
		// find the next command
285 cycrow 5734
		pos = sStr.toStdWString().find_first_of(L"&", pos + 1);
17 cycrow 5735
	}
5736
 
5737
	// replace the & now
197 cycrow 5738
	newStr = newStr.findReplace(L"&", L"&amp;");
17 cycrow 5739
 
5740
	// restore the commands
185 cycrow 5741
	for(auto itr = changes.begin(); itr != changes.end(); itr++)
5742
		newStr = newStr.findReplace((*itr)->data, (*itr)->str);
17 cycrow 5743
 
5744
	return newStr;
5745
}
5746
 
197 cycrow 5747
Utils::WString CPackages::convertTextString(const Utils::WString &sText)
1 cycrow 5748
{
17 cycrow 5749
	//process any &
197 cycrow 5750
	Utils::WString text = parseXmlText(sText);
17 cycrow 5751
 
5752
	// change special cases
197 cycrow 5753
	text = text.findReplace(L"(", L"\\(");
5754
	text = text.findReplace(L")", L"\\)");
5755
	text = text.findReplace(L"[", L"{");
5756
	text = text.findReplace(L"]", L"}");
5757
	text = text.findReplace(L">", L"&gt;");
5758
	text = text.findReplace(L"<", L"&lt;");
1 cycrow 5759
	return text;
5760
}
5761
 
56 cycrow 5762
int CPackages::_gameTextNumber() const
5763
{
5764
	int gameNumber = (m_pCurrentGameExe) ? m_pCurrentGameExe->iTextNum : -1;
5765
	if ( gameNumber != -1 ) return gameNumber;
5766
 
5767
	switch(m_iGame) {
5768
		case GAME_X3: return 30;
5769
		case GAME_X3TC: return 35;
5770
		case GAME_X3AP: return 38;
126 cycrow 5771
		case GAME_X3FL: return 39;
56 cycrow 5772
		default: return 0;
5773
	}
5774
}
5775
 
87 cycrow 5776
void CPackages::createPluginManagerOpenText()
5777
{
5778
	int gameNumber = _gameTextNumber();
5779
 
5780
	int lang = m_iLanguage;
5781
	if ( !lang || lang < 0 )
5782
		lang = 44;
5783
 
5784
	CDirIO Dir(m_sCurrentDir);
213 cycrow 5785
	if ( !Dir.exists(L"t") )
5786
		Dir.create(L"t");
87 cycrow 5787
 
197 cycrow 5788
	Utils::WString filename = SPK::FormatTextName(PMTEXTFILE, lang, (m_iGameFlags & EXEFLAG_TCTEXT));
5789
	CFileIO textFile(m_sCurrentDir + L"/t/" + filename + L".xml");
87 cycrow 5790
 
197 cycrow 5791
	std::vector<Utils::WString> writeData;
87 cycrow 5792
 
197 cycrow 5793
	writeData.push_back(L"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
5794
	writeData.push_back(L"<language id=\"" + Utils::WString::Number(lang) + L"\">");
87 cycrow 5795
 
5796
	if ( !gameNumber )
197 cycrow 5797
		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 5798
	else
227 cycrow 5799
		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 5800
 
197 cycrow 5801
	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>");
5802
	writeData.push_back(L"		<t id=\"99999\">2</t>");	
5803
	writeData.push_back(L"	</page>");
87 cycrow 5804
 
197 cycrow 5805
	writeData.push_back(L"</language>");
160 cycrow 5806
	textFile.writeFileUTF(&writeData);
87 cycrow 5807
 
5808
	size_t fileSize;
102 cycrow 5809
	char *fileData = CFileIO(textFile.fullFilename()).ReadToData(&fileSize);
87 cycrow 5810
 
5811
	if ( fileData && fileSize)
5812
	{
5813
		size_t newFileSize;
5814
		unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
5815
		if ( pckData )
5816
		{
197 cycrow 5817
			CFileIO pckFile(m_sCurrentDir + L"/t/" + filename + L".pck");
87 cycrow 5818
			pckFile.WriteData((char *)pckData, newFileSize);
202 cycrow 5819
			this->addCreatedFile(pckFile.fullFilename());
87 cycrow 5820
		}
5821
	}
5822
	textFile.remove();
5823
}
5824
 
1 cycrow 5825
void CPackages::CreatePluginManagerText()
5826
{
56 cycrow 5827
	int gameNumber = _gameTextNumber();
1 cycrow 5828
 
5829
	int lang = m_iLanguage;
5830
	if ( !lang || lang < 0 )
5831
		lang = 44;
5832
 
5833
	CDirIO Dir(m_sCurrentDir);
197 cycrow 5834
	if ( !Dir.exists(L"t") )
5835
		Dir.create(L"t");
1 cycrow 5836
 
5837
	m_iLastUpdated = (int)time(NULL);
5838
 
197 cycrow 5839
	Utils::WString filename = SPK::FormatTextName(PMTEXTFILE, lang, (m_iGameFlags & EXEFLAG_TCTEXT));
5840
	CFileIO textFile(m_sCurrentDir + L"/t/" + filename + L".xml");
1 cycrow 5841
 
197 cycrow 5842
	std::vector<Utils::WString> writeData;
1 cycrow 5843
 
5844
	CLinkList<SGameWare> lWares;
5845
	CLinkList<SGameShip> lShips;
5846
	for ( int i = 0; i < WAREBUFFERS; i++ )
5847
	{
5848
		for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() )
5849
		{
5850
			SGameWare *w = node->Data();
5851
			if ( w->iType == WARETYPE_NONE )
5852
				continue;
5853
			lWares.push_back(w);
5854
		}
5855
	}
5856
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
5857
	{
5858
		if ( node->Data()->iType == WARETYPE_NONE )
5859
			continue;
5860
		lShips.push_back(node->Data());
5861
	}
5862
 
197 cycrow 5863
	writeData.push_back(L"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
5864
	writeData.push_back(L"<language id=\"" + Utils::WString::Number(lang) + "\">");
1 cycrow 5865
 
5866
	if ( !gameNumber )
197 cycrow 5867
		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 5868
	else
197 cycrow 5869
		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 5870
 
5871
	// write the heading
5872
	int start = 10000;
197 cycrow 5873
	writeData.push_back(L"		<t id=\"1\">" + Utils::WString::Number(m_iLastUpdated) + L"</t>");
5874
	writeData.push_back(L"		<t id=\"2\">" + Utils::WString::Number(this->countPackages(TYPE_SPK, true)) + L"</t>");
5875
	writeData.push_back(L"		<t id=\"3\">" + Utils::WString::Number(start) + L"</t>");
5876
	writeData.push_back(L"		<t id=\"4\">" + Utils::WString::Number(lWares.size()) + L"</t>");
5877
	writeData.push_back(L"		<t id=\"6\">" + Utils::WString::Number(lShips.size()) + L"</t>");
1 cycrow 5878
 
5879
	// write some generic texts
197 cycrow 5880
	writeData.push_back(L"		<t id=\"110\">" + Utils::WString::Number((long)m_iLanguage) + L"</t>");
5881
	writeData.push_back(L"		<t id=\"109\">Plugin Manager: \\033GPoll Gui Data\\033X</t>");
5882
	writeData.push_back(L"		<t id=\"107\">Plugin Manager: \\033GExport Game Data\\033X </t>");
5883
	writeData.push_back(L"		<t id=\"100\">\\n</t>");
5884
	writeData.push_back(L"		<t id=\"101\">\\033B</t>");
5885
	writeData.push_back(L"		<t id=\"102\">\\033G</t>");
5886
	writeData.push_back(L"		<t id = \"103\">\\033B</t>");
5887
	writeData.push_back(L"		<t id=\"104\">\\033X</t>");
5888
	writeData.push_back(L"		<t id=\"105\">\\033Y</t>");
5889
	writeData.push_back(L"		<t id=\"106\">\\033C</t>");
5890
	writeData.push_back(L"		<t id=\"108\">\\033</t>");
87 cycrow 5891
 
197 cycrow 5892
	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>");
5893
	writeData.push_back(L"		<t id=\"99999\">1</t>");
1 cycrow 5894
	// now write each package
5895
	int settingStart = 100000;
5896
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
5897
	{
5898
		CBaseFile *p = node->Data();
5899
		if ( !p->IsEnabled() )
5900
			continue;
5901
 
5902
		if ( p->GetType() != TYPE_SPK )
5903
			continue;
5904
 
263 cycrow 5905
		if (p->author().Compare("PluginManager", false))
5906
			continue;
5907
 
1 cycrow 5908
		CSpkFile *spk = (CSpkFile *)p;
5909
 
5910
		// count text files
197 cycrow 5911
		Utils::WString textEntries;
1 cycrow 5912
		int textCount = 0;
5913
		C_File *f = p->GetFirstFile(FILETYPE_TEXT);
5914
		while ( f )
5915
		{
197 cycrow 5916
			Utils::WString sLang;
5917
			Utils::WString id;
1 cycrow 5918
			if ( m_iGameFlags & EXEFLAG_TCTEXT )
5919
			{
197 cycrow 5920
				id = f->baseName().token(L"-", 1);
5921
				sLang = f->baseName().token(L"-", 2);
160 cycrow 5922
				if ( sLang.empty() )
197 cycrow 5923
					sLang = L"NULL";
1 cycrow 5924
				else
160 cycrow 5925
					sLang = sLang.erase(0, 1);  // remove the "L"
1 cycrow 5926
			}
5927
			else
5928
			{
160 cycrow 5929
				sLang = f->baseName().left((int)f->baseName().length() - 4).padNumber(3);
5930
				id = f->baseName().mid(((int)f->baseName().length() - 4) + 1, 4);
1 cycrow 5931
			}
5932
 
197 cycrow 5933
			if ( sLang != L"NULL" )
1 cycrow 5934
			{
160 cycrow 5935
				if ( sLang.toInt() == lang )
1 cycrow 5936
				{
5937
					++textCount;
160 cycrow 5938
					if ( !textEntries.empty() )
197 cycrow 5939
						textEntries += L" ";
1 cycrow 5940
					textEntries += id;
5941
				}
5942
			}
5943
			f = p->GetNextFile(f);
5944
		}
5945
 
197 cycrow 5946
		Utils::WString sTextCount((long)textCount);
5947
		writeData.push_back(L"		<t id=\"" + Utils::WString::Number((long)start) + L"\">" + this->convertTextString(p->name()) + L"</t>");
5948
		writeData.push_back(L"		<t id=\"" + Utils::WString::Number((long)(start + 1)) + L"\">" + this->convertTextString(p->author()) + L"</t>");
5949
		writeData.push_back(L"		<t id=\"" + Utils::WString::Number((long)(start + 2)) + L"\">" + this->convertTextString(p->version()) + L"</t>");
5950
		writeData.push_back(L"		<t id=\"" + Utils::WString::Number((long)(start + 3)) + L"\">" + this->convertTextString(p->name(lang)) + L"</t>");
1 cycrow 5951
 
214 cycrow 5952
		CLinkList<SSettingType> *settings = spk->settingsList();
1 cycrow 5953
		if ( settings && settings->size() )
5954
		{
197 cycrow 5955
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 4) + L"\">" + (long)settings->size() + L"</t>");
5956
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 5) + L"\">" + (long)settingStart + L"</t>");
1 cycrow 5957
 
14 cycrow 5958
			for ( CListNode<SSettingType> *sNode = settings->Front(); sNode; sNode = sNode->next() )
1 cycrow 5959
			{
14 cycrow 5960
				SSettingType *st = sNode->Data();
214 cycrow 5961
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(settingStart++) + L"\">" + st->sKey + L"</t>");
5962
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(settingStart++) + L"\">" + spk->getSetting(st) + L"</t>");
1 cycrow 5963
			}
5964
		}
5965
		else
197 cycrow 5966
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 4) + L"\">0</t>");
1 cycrow 5967
 
197 cycrow 5968
		writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 6) + L"\">" + sTextCount + L"</t>");
1 cycrow 5969
		if ( textCount )
197 cycrow 5970
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 7) + L"\">" + textEntries + L"</t>");
1 cycrow 5971
 
5972
		start += 10;
5973
	}
5974
 
5975
	// write ware names
5976
	if ( lWares.size() )
5977
	{
197 cycrow 5978
		writeData.push_back(L"		<t id=\"5\">" + Utils::WString::Number(start) + L"</t>");
1 cycrow 5979
		for ( CListNode<SGameWare> *node = lWares.Front(); node; node = node->next() )
5980
		{
5981
			SGameWare *w = node->Data();
5982
			if ( w->pWare && w->iType == WARETYPE_ADDED )
197 cycrow 5983
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)start + L"\">" + this->convertTextString(w->sWareName) + L"</t>");
1 cycrow 5984
			else
197 cycrow 5985
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)start + L"\">-1</t>");
5986
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 1) + L"\">" + Utils::WString(w->cType) + L"</t>");
5987
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 2) + L"\">" + (long)w->iPos + L"</t>");
1 cycrow 5988
			start += 10;
5989
		}
5990
	}
5991
 
5992
	if ( lShips.size() )
5993
	{
197 cycrow 5994
		writeData.push_back(L"		<t id=\"7\">" + Utils::WString::Number(start) + L"</t>");
1 cycrow 5995
		for ( CListNode<SGameShip> *node = lShips.Front(); node; node = node->next() )
5996
		{
5997
			SGameShip *gs = node->Data();
5998
			if ( gs->iType == WARETYPE_NONE )
5999
				continue;
6000
			if ( gs->pPackage && gs->iType == WARETYPE_ADDED )
197 cycrow 6001
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)start + L"\">" + gs->sShipID + L"</t>");
1 cycrow 6002
			else
197 cycrow 6003
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)start + L"\">-1</t>");
6004
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 1) + L"\">" + (long)gs->iPos + L"</t>");
6005
			writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(start + 2) + L"\">Ship</t>");
1 cycrow 6006
 
6007
			// write shipyard info
6008
			if ( gs->pPackage )
6009
			{
6010
				int doStart = start + 5;
248 cycrow 6011
				for (ShipyardRace i = ShipyardRace::Argon; i <= ShipyardRace::Max; i = static_cast<ShipyardRace>(static_cast<unsigned int>(i) * 2))
1 cycrow 6012
				{
248 cycrow 6013
					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 6014
					++doStart;
6015
				}
6016
			}
6017
 
6018
			start += 20;
6019
		}
6020
	}
6021
 
197 cycrow 6022
	writeData.push_back(L"	</page>");
1 cycrow 6023
 
160 cycrow 6024
	// do emp
6025
	if (m_iGame == GAME_X3TC || m_iGame == GAME_X3 || m_iGame == GAME_X3AP || m_iGame == GAME_X3FL)
6026
	{
197 cycrow 6027
		writeData.push_back(L"  <page id=\"17\" title=\"Plugin Manager Objects\">");
160 cycrow 6028
		writeData.push_back(GetEMPText());
197 cycrow 6029
		writeData.push_back(L"  </page>");
160 cycrow 6030
	}
6031
 
1 cycrow 6032
	// wares
126 cycrow 6033
	if ( m_iGame == GAME_X3AP || m_iGame == GAME_X3TC || m_iGame == GAME_X3FL || m_iGame == GAME_X3 || lWares.size() || lShips.size() )
1 cycrow 6034
	{
160 cycrow 6035
 
1 cycrow 6036
		if ( !gameNumber )
197 cycrow 6037
			writeData.push_back(L"  <page id=\"17\" title=\"Plugin Manager Objects\">");
1 cycrow 6038
		else
197 cycrow 6039
			writeData.push_back(Utils::WString(L"  <page id=\"") + (long)gameNumber + L"0017\" title=\"Plugin Manager Objects\">");
1 cycrow 6040
 
197 cycrow 6041
		writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(SHIPSTARTTEXT - 1) + L"\">ZZ_BLANKSHIP</t>");
1 cycrow 6042
 
6043
		// object names
6044
		for ( CListNode<SGameWare> *node = lWares.Front(); node; node = node->next() )
6045
		{
6046
			SGameWare *w = node->Data();
6047
			if ( !w->pWare || w->iType != WARETYPE_ADDED )
6048
				continue;
6049
 
6050
			// find the correct text for the language
197 cycrow 6051
			Utils::WString name = CSpkFile::GetWareText(w->pWare, m_iLanguage);
6052
			Utils::WString desc = CSpkFile::GetWareDesc(w->pWare, m_iLanguage);
84 cycrow 6053
			if ( !name.empty() )
197 cycrow 6054
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(w->iText + 3) + L"\">" + this->convertTextString(name) + L"</t>");
84 cycrow 6055
			if ( !desc.empty() )
197 cycrow 6056
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(w->iText + 4) + L"\">" + this->convertTextString(desc) + L"</t>");
1 cycrow 6057
		}
6058
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6059
		{
6060
			SGameShip *s = node->Data();
6061
			if ( !s->pPackage || s->iType != WARETYPE_ADDED )
6062
				continue;
6063
			if ( s->pPackage->GetOriginalDescription() )
6064
				continue;
6065
 
206 cycrow 6066
			Utils::WString name = s->pPackage->textName(m_iLanguage);
6067
			Utils::WString desc = s->pPackage->textDescription(m_iLanguage);
84 cycrow 6068
			if ( !name.empty() )
197 cycrow 6069
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)s->iText + L"\">" + this->convertTextString(name) + L"</t>");
84 cycrow 6070
			if ( !desc.empty() )
197 cycrow 6071
				writeData.push_back(Utils::WString(L"		<t id=\"") + (long)(s->iText + 1) + L"\">" + this->convertTextString(desc) + L"</t>");
1 cycrow 6072
		}
197 cycrow 6073
		writeData.push_back(L"  </page>");
1 cycrow 6074
	}
197 cycrow 6075
	writeData.push_back(L"</language>");
160 cycrow 6076
	textFile.writeFileUTF(&writeData);
1 cycrow 6077
 
6078
	size_t fileSize;
102 cycrow 6079
	char *fileData = CFileIO(textFile.fullFilename()).ReadToData(&fileSize);
1 cycrow 6080
 
6081
	if ( fileData && fileSize)
6082
	{
6083
		size_t newFileSize;
6084
		unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
6085
		if ( pckData )
6086
		{
197 cycrow 6087
			CFileIO pckFile(m_sCurrentDir + L"/t/" + filename + L".pck");
1 cycrow 6088
			pckFile.WriteData((char *)pckData, newFileSize);
202 cycrow 6089
			this->addCreatedFile(pckFile.fullFilename());
1 cycrow 6090
		}
6091
	}
52 cycrow 6092
	textFile.remove();
248 cycrow 6093
 
6094
	// write out the settings file
6095
	if (m_iGameFlags & EXEFLAG_SETTINGFILE)
6096
	{
6097
		CDirIO Dir(m_sCurrentDir);
6098
		if (!Dir.exists(L"types"))
6099
			Dir.create(L"types");
6100
		Dir.cd(L"types");
6101
 
6102
		std::vector<Utils::WString> writeData;
6103
		CFileIO dataFile(Dir.file(L"manager.txt"));
6104
		if (dataFile.exists())
6105
			dataFile.remove();
6106
 
6107
		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";");
6108
 
6109
		for (CListNode<CBaseFile>* node = m_lPackages.Front(); node; node = node->next())
6110
		{
6111
			CBaseFile* p = node->Data();
6112
			if (!p->IsEnabled())
6113
				continue;
6114
 
6115
			if (p->GetType() != TYPE_SPK)
6116
				continue;
6117
 
262 cycrow 6118
			if (p->author().Compare("PluginManager", false))
6119
				continue;
6120
 
248 cycrow 6121
			CSpkFile* spk = (CSpkFile*)p;
6122
 
6123
			// count text files
6124
			Utils::WStringList textEntries;
6125
			C_File* f = p->GetFirstFile(FILETYPE_TEXT);
6126
			while (f)
6127
			{
6128
				Utils::WString sLang;
6129
				Utils::WString id;
6130
				if (m_iGameFlags & EXEFLAG_TCTEXT)
6131
				{
6132
					id = f->baseName().token(L"-", 1);
6133
					sLang = f->baseName().token(L"-", 2);
6134
					if (sLang.empty())
6135
						sLang = L"NULL";
6136
					else
6137
						sLang = sLang.erase(0, 1);  // remove the "L"
6138
				}
6139
				else
6140
				{
6141
					sLang = f->baseName().left((int)f->baseName().length() - 4).padNumber(3);
6142
					id = f->baseName().mid(((int)f->baseName().length() - 4) + 1, 4);
6143
				}
6144
 
6145
				if (sLang != L"NULL")
6146
				{
6147
					if (sLang.toInt() == lang)
6148
						textEntries.pushBack(id);
6149
				}
6150
				f = p->GetNextFile(f);
6151
			}
6152
 
6153
			CLinkList<SSettingType>* settings = spk->settingsList();
6154
 
6155
			Utils::WString str = L"Script;" + spk->name() + L";" + spk->author() + L";" + spk->version() + L";" + spk->name(lang) + L";" + Utils::WString::Number(textEntries.size());
6156
 
6157
			for (auto itr = textEntries.begin(); itr != textEntries.end(); itr++)
6158
				str += L";" + (*itr)->str;
6159
 
6160
			str += L";" + Utils::WString::Number(settings ? settings->size() : 0);
6161
			if (settings)
6162
			{
6163
				for (CListNode<SSettingType>* sNode = settings->Front(); sNode; sNode = sNode->next())
6164
				{
6165
					SSettingType* st = sNode->Data();
6166
					str += L";" + st->sKey + L";" + spk->getSetting(st);
6167
				}
6168
			}
6169
			writeData.push_back(str + L";");
6170
		}
6171
 
6172
		for (CListNode<SGameWare>* node = lWares.Front(); node; node = node->next())
6173
		{
6174
			SGameWare* w = node->Data();
6175
			Utils::WString str;
6176
			if (w->pWare && w->iType == WARETYPE_ADDED)
6177
				str = this->convertTextString(w->sWareName);
6178
			else
6179
				str = L"-1";
6180
			str += L";" + Utils::WString(w->cType) + L";" + Utils::WString::Number(w->iPos);
6181
			writeData.push_back(L"Ware;" + str + L";");
6182
		}
6183
 
6184
		for (CListNode<SGameShip>* node = lShips.Front(); node; node = node->next())
6185
		{
6186
			SGameShip* gs = node->Data();
6187
			if (gs->iType == WARETYPE_NONE)
6188
				continue;
6189
 
6190
			Utils::WString str;
6191
			if (gs->pPackage && gs->iType == WARETYPE_ADDED)
6192
				str = gs->sShipID;
6193
			else
6194
				str = L"-1";
6195
 
6196
			str += L";" + Utils::WString::Number(gs->iPos);
6197
 
6198
			// write shipyard info
6199
			if (gs->pPackage && gs->iType == WARETYPE_ADDED)
6200
			{
6201
				for (ShipyardRace i = ShipyardRace::Argon; i <= ShipyardRace::Max; i = static_cast<ShipyardRace>(static_cast<unsigned int>(i) * 2))
6202
				{
6203
					if (gs->pPackage->isShipyard(i))
6204
						str += L";" + GetShipyardName(i);
6205
				}
6206
			}
6207
			writeData.push_back(L"Ship;" + str + L";");
6208
		}
6209
 
6210
		dataFile.writeFileUTF(&writeData);
6211
	}
1 cycrow 6212
}
6213
 
197 cycrow 6214
bool CPackages::isCurrentDir(const Utils::WString &dir) const
1 cycrow 6215
{
197 cycrow 6216
	Utils::WString cur = m_sCurrentDir;
121 cycrow 6217
 
6218
	if ( dir.Compare(cur) )
1 cycrow 6219
		return true;
6220
 
197 cycrow 6221
	Utils::WString checkDir = cur;
6222
	checkDir = checkDir.findReplace(L"/", L"\\");
1 cycrow 6223
	if ( checkDir.Compare(dir) )
6224
		return true;
6225
 
197 cycrow 6226
	checkDir = checkDir.findReplace(L"\\", L"/");
1 cycrow 6227
	if ( checkDir.Compare(dir) )
6228
		return true;
6229
 
6230
	return false;
6231
}
6232
 
126 cycrow 6233
void CPackages::backupSaves(bool vanilla)
1 cycrow 6234
{
126 cycrow 6235
	if (!_sSaveDir.empty())
6236
	{
6237
		// copy any saves into the vanilla directory
221 cycrow 6238
		Utils::WString dir = (vanilla) ? L"Vanilla" : L"Modified";
1 cycrow 6239
 
126 cycrow 6240
		// make sure the directory exists
6241
		CDirIO saveDir(this->saveDirectory());
6242
		CDirIO gameSaveDir(saveDir.dir(_sSaveDir));
1 cycrow 6243
 
126 cycrow 6244
		if (!gameSaveDir.exists())
160 cycrow 6245
			gameSaveDir.create();
126 cycrow 6246
		if (!gameSaveDir.exists(dir))
160 cycrow 6247
			gameSaveDir.create(dir);
126 cycrow 6248
		gameSaveDir.cd(dir);
6249
 
6250
		// backup the saves
197 cycrow 6251
		Utils::WStringList files;
6252
		if(saveDir.dirList(files, Utils::WString::Null(), L"*.sav"))
1 cycrow 6253
		{
126 cycrow 6254
			for(auto itr = files.begin(); itr != files.end(); ++itr)
6255
			{
6256
				CFileIO File(saveDir.file((*itr)->str));
196 cycrow 6257
				if (!File.isFileExtension(L"sav"))
126 cycrow 6258
					continue;
6259
				// remove the file if already exists
6260
				if (gameSaveDir.exists((*itr)->str))
6261
					CFileIO::Remove(gameSaveDir.file((*itr)->str));
1 cycrow 6262
 
126 cycrow 6263
				// copy the file into the games save dir for backup
6264
				File.copy(gameSaveDir.file(File.filename()), true);
6265
			}
1 cycrow 6266
		}
6267
	}
6268
}
6269
 
126 cycrow 6270
void CPackages::restoreSaves(bool vanilla)
1 cycrow 6271
{
6272
	// get dir to restore from
126 cycrow 6273
	if (!_sSaveDir.empty())
6274
	{
221 cycrow 6275
		Utils::WString dir = (vanilla) ? L"Vanilla" : L"Modified";
126 cycrow 6276
		CDirIO toDir(this->saveDirectory());
6277
		CDirIO restoreDir(toDir.dir(_sSaveDir));
6278
		restoreDir.cd(dir);
1 cycrow 6279
 
126 cycrow 6280
		if (restoreDir.exists())
6281
		{
6282
			//if we are in vanilla mode, we should remove the saves (so we only have vanilla saves
6283
			/*
6284
			if (vanilla) {
222 cycrow 6285
 
6286
				Utils::WStringList *files = toDir.DirList();
126 cycrow 6287
				if (files) {
6288
					for (SStringList *node = files->Head(); node; node = node->next)
6289
					{
6290
						CFileIO saveFile(toDir.File(node->str));
6291
						if (saveFile.extension().Compare("sav")) {
6292
							saveFile.remove();
6293
						}
6294
					}
6295
					delete files;
86 cycrow 6296
				}
6297
			}
126 cycrow 6298
			*/
86 cycrow 6299
 
126 cycrow 6300
			// now we copy of the backed up save games
197 cycrow 6301
			Utils::WStringList files;
6302
			if(restoreDir.dirList(files, Utils::WString::Null(), L"*.sav"))
126 cycrow 6303
			{
6304
				for(auto itr = files.begin(); itr != files.end(); itr++)
6305
				{
6306
					CFileIO File(restoreDir.file((*itr)->str));
6307
					// remove the file if already exists
6308
					if (toDir.exists((*itr)->str)) CFileIO::Remove(toDir.file((*itr)->str));
1 cycrow 6309
 
126 cycrow 6310
					// move file over
6311
					File.copy(toDir.file((*itr)->str), true);
6312
				}
6313
			}
1 cycrow 6314
		}
6315
	}
6316
}
6317
 
6318
bool CPackages::RemoveCurrentDirectory()
6319
{
6320
	if ( !m_bLoaded )
6321
		return false;
6322
 
6323
	// remove all package files
183 cycrow 6324
	this->removeAllPackages();
1 cycrow 6325
 
6326
	// remove all plugin manager files
6327
	this->RemoveCreatedFiles();
6328
 
6329
	this->Reset();
6330
	m_bLoaded = false;
6331
 
6332
	// clear the plugin manager directory
6333
	CDirIO Dir(m_sCurrentDir);
213 cycrow 6334
	Dir.removeDir(L"PluginManager", true, true, 0);
6335
	Dir.removeDir(L"dds", false, true, 0);
6336
	Dir.removeDir(L"objects", false, true, 0);
6337
	Dir.removeDir(L"types", false, true, 0);
6338
	Dir.removeDir(L"textures", false, true, 0);
1 cycrow 6339
 
6340
	// remove the plugin manager mod files
213 cycrow 6341
	if ( Dir.exists(L"mods/PluginManager.cat") )	CFileIO::Remove(Dir.file(L"mods/PluginManager.cat"));
6342
	if ( Dir.exists(L"mods/PluginManager.dat") )	CFileIO::Remove(Dir.file(L"mods/PluginManager.dat"));
1 cycrow 6343
 
6344
	return true;
6345
}
6346
 
6347
void CPackages::CreateDummies()
6348
{
6349
	// first check we have any ships
179 cycrow 6350
	if ( m_lGameShips.empty() || !this->countPackages(TYPE_XSP, true) )
1 cycrow 6351
		return;
6352
 
6353
	CLinkList<SDummyEntry> dummyList;
6354
 
6355
	// now extract the existing dummies
213 cycrow 6356
	int e = extractGameFile(L"types/Dummies.pck", m_sTempDir + L"/Dummies.txt");
1 cycrow 6357
	if ( e )
6358
	{
6359
		// read the dummies
6360
		CFileIO File;
213 cycrow 6361
		if ( File.open((e == -1) ? L"Dummies.txt" : m_sTempDir + L"/Dummies.txt") )
1 cycrow 6362
		{
216 cycrow 6363
			std::vector<Utils::WString> lines;
184 cycrow 6364
			if(File.readLines(lines))
1 cycrow 6365
			{
6366
				int insection = 0;
6367
				SDummyEntry *currentSection = NULL;
184 cycrow 6368
				for ( int j = 0; j < (int)lines.size(); j++ )
1 cycrow 6369
				{
216 cycrow 6370
					Utils::WString line(lines.at(j));
160 cycrow 6371
					line.removeChar(9);
6372
					line.removeChar('\r');
6373
					line.removeFirstSpace();
6374
					line.removeEndSpace();
6375
					if ( line.empty() )
1 cycrow 6376
						continue;
6377
					if ( line[0] == '/' )
6378
						continue;
6379
 
6380
					// read the section, first entry is section, second is size
160 cycrow 6381
					while ( !line.empty() )
1 cycrow 6382
					{
6383
						if ( !insection )
6384
						{
216 cycrow 6385
							Utils::WString section = line.token(L";", 1);
6386
							insection = line.token(L";", 2).toInt();
1 cycrow 6387
 
6388
							// search for the sections
6389
							currentSection = NULL;
6390
							for ( CListNode<SDummyEntry> *node = dummyList.Front(); node; node = node->next() )
6391
							{
6392
								SDummyEntry *d = node->Data();
6393
								if ( d->sSection.Compare(section) )
6394
								{
6395
									currentSection = node->Data();
6396
									break;
6397
								}
6398
							}
6399
 
6400
							if ( !currentSection )
6401
							{
6402
								currentSection = new struct SDummyEntry;
6403
								currentSection->sSection = section;
6404
								dummyList.push_back(currentSection);
6405
							}
6406
 
6407
							// we have some more ?
216 cycrow 6408
							line = line.remTokens(L";", 1, 2);
1 cycrow 6409
						}
6410
						else
6411
						{
6412
							--insection;
6413
							// check the last entry for number of states
216 cycrow 6414
							if ( currentSection->sSection.Compare(L"SDTYPE_GUN") )
1 cycrow 6415
							{
216 cycrow 6416
								int states = line.token(L";", 3).toInt();
6417
								int parts = line.token(L";", 4 + (states * 2)).toInt();
6418
								Utils::WString data = line.tokens(L";", 1, 4 + (states * 2) + (parts * 2)) + L";";
184 cycrow 6419
								currentSection->lEntries.pushBack(data);
1 cycrow 6420
 
6421
								// remove done
216 cycrow 6422
								line = line.remTokens(L";", 1, 4 + (states * 2) + (parts * 2));
1 cycrow 6423
							}
6424
							else
6425
							{
216 cycrow 6426
								int states = line.token(L";", 3).toInt();
6427
								Utils::WString data = line.tokens(L";", 1, 3 + (states * 2)) + L";";
184 cycrow 6428
								currentSection->lEntries.pushBack(data);
1 cycrow 6429
 
6430
								// remove done
216 cycrow 6431
								line = line.remTokens(L";", 1, 3 + (states * 2));
1 cycrow 6432
							}
6433
						}
6434
					}
6435
				}
6436
			}
6437
 
52 cycrow 6438
			File.remove();
1 cycrow 6439
		}
6440
 
6441
		// add the new entries for the ships
6442
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6443
		{
6444
			SGameShip *s = node->Data();
6445
			if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6446
				continue;
6447
 
6448
			// no dummies to add?
6449
			if ( !s->pPackage->AnyDummies() )
6450
				continue;
6451
 
6452
			// add each dummy to list
6453
			for ( CListNode<SDummy> *dNode = s->pPackage->GetDummies()->Front(); dNode; dNode = dNode->next() )
6454
			{
6455
				SDummy *dummy = dNode->Data();
6456
				SDummyEntry *found = NULL;
6457
				for ( CListNode<SDummyEntry> *eNode = dummyList.Front(); eNode; eNode = eNode->next() )
6458
				{
184 cycrow 6459
					if ( eNode->Data()->sSection.Compare(dummy->sSection) )
1 cycrow 6460
					{
6461
						found = eNode->Data();
6462
						break;
6463
					}
6464
				}
6465
				if ( !found )
6466
				{
6467
					found = new SDummyEntry;
6468
					found->sSection = dummy->sSection;
6469
					dummyList.push_back(found);
6470
				}
6471
				// check if its already on the list
6472
				else
6473
				{
6474
					bool f = false;
184 cycrow 6475
					for(auto itr = found->lEntries.begin(); itr != found->lEntries.end(); itr++)
1 cycrow 6476
					{
216 cycrow 6477
						if ((*itr)->str.token(L";", 1).Compare(dummy->sData.token(L";", 1)))
1 cycrow 6478
						{
6479
							f = true;
6480
							break;
6481
						}
6482
					}
6483
 
6484
					if ( f )
6485
						continue;
6486
				}
6487
 
184 cycrow 6488
				found->lEntries.pushBack(dummy->sData);
1 cycrow 6489
			}
6490
		}
6491
 
6492
		// finally, write the file
216 cycrow 6493
		std::vector<Utils::WString> lines;
6494
		lines.push_back(L"// Dummies file, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2));
1 cycrow 6495
		for ( SDummyEntry *dummy = dummyList.First(); dummy; dummy = dummyList.Next() )
6496
		{
216 cycrow 6497
			lines.push_back(L"");
6498
			lines.push_back(L"// Section: " + dummy->sSection + L" Entries: " + Utils::WString::Number((long)dummy->lEntries.size()));
6499
			lines.push_back(dummy->sSection + L";" + Utils::WString::Number(dummy->lEntries.size()) + L";");
184 cycrow 6500
			for(auto itr = dummy->lEntries.begin(); itr != dummy->lEntries.end(); itr++)
1 cycrow 6501
			{
216 cycrow 6502
				Utils::WString strLine = (*itr)->str;
160 cycrow 6503
				strLine.removeChar(9);
6504
				strLine.removeChar('\r');
6505
				strLine.removeEndSpace();
6506
				strLine.removeFirstSpace();
216 cycrow 6507
				strLine = strLine.findReplace(L"<::PiPe::>", L"|");
6508
				if ( strLine.right(1) != L";" )
6509
					strLine += L";";
1 cycrow 6510
				lines.push_back(strLine);
6511
			}
6512
		}
216 cycrow 6513
		lines.push_back(L"");
1 cycrow 6514
 
6515
		// write the file to disk
213 cycrow 6516
		CFileIO WriteFile(m_sTempDir + L"/dummies.txt");
216 cycrow 6517
		if ( WriteFile.writeFile(lines) )
1 cycrow 6518
		{
213 cycrow 6519
			this->packFile(&WriteFile, L"types\\dummies.pck");
52 cycrow 6520
			WriteFile.remove();
1 cycrow 6521
		}
6522
	}
6523
}
6524
 
6525
void CPackages::CreateCutData()
6526
{
6527
	// first check we have any ships
179 cycrow 6528
	if ( m_lGameShips.empty() || !this->countPackages(TYPE_XSP, true) )
1 cycrow 6529
		return;
6530
 
6531
	bool found = false;
6532
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6533
	{
6534
		SGameShip *s = node->Data();
6535
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6536
			continue;
6537
 
6538
		// no dummies to add?
164 cycrow 6539
		if ( !s->pPackage->anyCutData() )
1 cycrow 6540
			continue;
6541
		found = true;
6542
		break;
6543
	}
6544
 
6545
	if ( !found )
6546
		return;
6547
 
216 cycrow 6548
	std::vector<Utils::WString> cutList;
213 cycrow 6549
	int e = extractGameFile(L"types/CutData.pck", m_sTempDir + L"/CutData.txt");
1 cycrow 6550
	if ( e )
6551
	{
6552
		CFileIO File;
213 cycrow 6553
		if ( File.open((e == -1) ? L"CutData.txt" : m_sTempDir + L"/CutData.txt") )
1 cycrow 6554
		{
216 cycrow 6555
			std::vector<Utils::WString> lines;
179 cycrow 6556
			if(File.readLines(lines))
1 cycrow 6557
			{
6558
				int entries = -1;
179 cycrow 6559
				for ( int j = 0; j < (int)lines.size(); j++ )
1 cycrow 6560
				{
216 cycrow 6561
					Utils::WString line(lines.at(j));
160 cycrow 6562
					line.removeChar(9);
6563
					line.removeChar('\r');
6564
					line.removeChar(' ');
6565
					if ( line.empty() || line[0] == '/' )
1 cycrow 6566
						continue;
6567
					if ( entries == -1 )
216 cycrow 6568
						entries = line.token(L";", 1).toInt();
1 cycrow 6569
					else
6570
					{
216 cycrow 6571
						if ( line.right(1) != L";" )
6572
							line += L";";
179 cycrow 6573
						cutList.push_back(line);
6574
						if ( static_cast<int>(cutList.size()) == entries)
1 cycrow 6575
							break;
6576
					}
6577
				}
6578
			}
6579
 
52 cycrow 6580
			File.remove();
1 cycrow 6581
		}
6582
	}
6583
 
6584
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6585
	{
6586
		SGameShip *s = node->Data();
6587
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6588
			continue;
6589
 
6590
		// no dummies to add?
164 cycrow 6591
		if ( !s->pPackage->anyCutData() )
1 cycrow 6592
			continue;
6593
 
6594
		// add each dummy to list
164 cycrow 6595
		auto& list = s->pPackage->getCutData();
6596
		for(auto itr = list.begin(); itr != list.end(); itr++)
1 cycrow 6597
		{
216 cycrow 6598
			Utils::WString str = (*itr)->str;
164 cycrow 6599
			str.removeChar(' ');
216 cycrow 6600
			if ( str.right(1) != L";" )
6601
				str += L";";
179 cycrow 6602
			if(std::find(cutList.begin(), cutList.end(), str) == cutList.end())
6603
				cutList.push_back(str);
1 cycrow 6604
		}
6605
	}
6606
 
216 cycrow 6607
	cutList.insert(cutList.begin(), Utils::WString::Number(cutList.size()) + ";");
6608
	cutList.insert(cutList.begin(), L"/cut id;filename (leave blank to use id)");
6609
	cutList.insert(cutList.begin(), L"// Cut Data file, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2));
1 cycrow 6610
 
6611
	// write the file to disk
213 cycrow 6612
	CFileIO WriteFile(m_sTempDir + L"/CutData.txt");
216 cycrow 6613
	if ( WriteFile.writeFile(cutList) )
1 cycrow 6614
	{
213 cycrow 6615
		this->packFile(&WriteFile, L"types\\CutData.pck");
52 cycrow 6616
		WriteFile.remove();
1 cycrow 6617
	}
6618
}
6619
 
6620
void CPackages::CreateAnimations()
6621
{
6622
	// first check we have any ships
179 cycrow 6623
	if ( m_lGameShips.empty() || !this->countPackages(TYPE_XSP, true) )
1 cycrow 6624
		return;
6625
 
6626
	bool found = false;
6627
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6628
	{
6629
		SGameShip *s = node->Data();
6630
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6631
			continue;
6632
 
6633
		// no dummies to add?
170 cycrow 6634
		if ( !s->pPackage->anyAnimations() )
1 cycrow 6635
			continue;
6636
		found = true;
6637
		break;
6638
	}
6639
 
6640
	if ( !found )
6641
		return;
6642
 
218 cycrow 6643
	Utils::WStringList aniList;
212 cycrow 6644
	int e = extractGameFile(L"types/Animations.pck", m_sTempDir + L"/Animations.txt");
1 cycrow 6645
	if ( e )
6646
	{
6647
		CFileIO File;
212 cycrow 6648
		if ( File.open((e == -1) ? L"Animations.txt" : m_sTempDir + L"/Animations.txt") )
1 cycrow 6649
		{
212 cycrow 6650
			std::vector<Utils::WString> lines;
6651
			if(File.readLines(lines))
1 cycrow 6652
			{
212 cycrow 6653
				for ( int j = 0; j < (int)lines.size(); j++ )
1 cycrow 6654
				{
212 cycrow 6655
					Utils::WString line(lines.at(j));
221 cycrow 6656
					aniList.pushBack(line);
1 cycrow 6657
				}
6658
			}
6659
 
52 cycrow 6660
			File.remove();
1 cycrow 6661
		}
6662
	}
6663
 
218 cycrow 6664
	Utils::WStringList parsedAniList;
170 cycrow 6665
	CXspFile::ReadAnimations(aniList, parsedAniList, 0);
1 cycrow 6666
 
6667
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6668
	{
6669
		SGameShip *s = node->Data();
6670
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6671
			continue;
6672
 
6673
		// no dummies to add?
170 cycrow 6674
		if ( !s->pPackage->anyAnimations() )
1 cycrow 6675
			continue;
6676
 
6677
		// add each dummy to list
170 cycrow 6678
		for(auto itr = s->pPackage->getAnimations().begin(); itr != s->pPackage->getAnimations().end(); itr++)
221 cycrow 6679
			parsedAniList.pushBack((*itr)->str);
1 cycrow 6680
	}
6681
 
6682
	// format the list with added spaces
218 cycrow 6683
	Utils::WStringList formatedAniList;
1 cycrow 6684
	int lineCount = -1;
170 cycrow 6685
	for(auto itr = parsedAniList.begin(); itr != parsedAniList.end(); itr++)
1 cycrow 6686
	{
6687
		// format the comment to match the line number
6688
		lineCount++;
218 cycrow 6689
		Utils::WString oldComment = (*itr)->str.tokens(L"//", 2);
6690
		Utils::WString comment = L"//" + Utils::WString::Number(lineCount);
170 cycrow 6691
		if (!oldComment.empty())
1 cycrow 6692
		{
218 cycrow 6693
			comment += L" ";
170 cycrow 6694
			oldComment.removeFirstSpace();
218 cycrow 6695
			if ( oldComment.token(L" ", 1).isNumber() )
6696
				comment += oldComment.tokens(L" ", 2);
1 cycrow 6697
			else
6698
				comment += oldComment;
6699
		}
218 cycrow 6700
		Utils::WString line = (*itr)->str.token(L"//", 1);
1 cycrow 6701
 
6702
		// split into seperate lines
218 cycrow 6703
		Utils::WString first = line.token(L";", 1);
6704
		if ( first.Compare(L"TAT_TAGSINGLESTEP") )
1 cycrow 6705
		{
218 cycrow 6706
			formatedAniList.pushBack(line.tokens(L";", 1, 5) + L";");
6707
			std::vector<Utils::WString> sLines;
6708
			if(line.tokens(L";", 6).tokenise(L";", sLines))
1 cycrow 6709
			{
218 cycrow 6710
				size_t max = sLines.size();
170 cycrow 6711
				if ( sLines[max - 1].empty() )
1 cycrow 6712
					--max; // remove the last ";"
6713
 
218 cycrow 6714
				for (size_t i = 0; i < max; i++ )
1 cycrow 6715
				{
218 cycrow 6716
					Utils::WString l = L"\t" + sLines[i] + L";";
1 cycrow 6717
					if ( i == (max - 1) )
170 cycrow 6718
						formatedAniList.pushBack(l + comment);
1 cycrow 6719
					else
170 cycrow 6720
						formatedAniList.pushBack(l);
1 cycrow 6721
				}
6722
			}
6723
		}
218 cycrow 6724
		else if ( (first.Compare(L"TAT_TAGONESHOT") || first.Compare(L"TAT_TAGLOOP")) && (line.contains(L"TATF_COORDS")) )
1 cycrow 6725
		{
218 cycrow 6726
			formatedAniList.pushBack(line.tokens(L";", 1, 5) + L";");
6727
			std::vector<Utils::WString> sLines;
6728
			if (line.tokens(L";", 6).tokenise(L";", sLines))
1 cycrow 6729
			{
218 cycrow 6730
				size_t max = sLines.size();
170 cycrow 6731
				if ( sLines[max - 1].empty() )
1 cycrow 6732
					--max; // remove the last ";"
6733
 
218 cycrow 6734
				Utils::WString prevLine;
6735
				for (size_t i = 0; i < max; i++ )
1 cycrow 6736
				{
218 cycrow 6737
					Utils::WString l = sLines[i] + L";";
6738
					if ( l.contains(L"TATF_COORDS") && !prevLine.empty() )
1 cycrow 6739
					{
218 cycrow 6740
						formatedAniList.pushBack(L"\t" + prevLine);
6741
						prevLine = L"";
1 cycrow 6742
					}
6743
					prevLine += l;
6744
				}
6745
 
170 cycrow 6746
				if ( !prevLine.empty() )
218 cycrow 6747
					formatedAniList.pushBack(L"\t" + prevLine + comment);
1 cycrow 6748
 
6749
			}
6750
		}
6751
		else
170 cycrow 6752
			formatedAniList.pushBack(line + comment);
1 cycrow 6753
	}
6754
 
218 cycrow 6755
	formatedAniList.pushFront(Utils::WString::Number(parsedAniList.size()) + L";");
6756
	formatedAniList.pushFront(L"// Animations, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2));
1 cycrow 6757
 
6758
	// write the file to disk
213 cycrow 6759
	CFileIO WriteFile(m_sTempDir + L"/Animations.txt");
170 cycrow 6760
	if ( WriteFile.writeFile(&formatedAniList) )
1 cycrow 6761
	{
213 cycrow 6762
		this->packFile(&WriteFile, L"types\\Animations.pck");
52 cycrow 6763
		WriteFile.remove();
1 cycrow 6764
	}
6765
}
6766
 
6767
void CPackages::CreateBodies()
6768
{
6769
	// first check we have any ships
179 cycrow 6770
	if ( m_lGameShips.empty() || !this->countPackages(TYPE_XSP, true) )
1 cycrow 6771
		return;
6772
 
6773
	bool found = false;
6774
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6775
	{
6776
		SGameShip *s = node->Data();
6777
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6778
			continue;
6779
 
6780
		// no dummies to add?
170 cycrow 6781
		if ( !s->pPackage->anyBodies() )
1 cycrow 6782
			continue;
6783
		found = true;
6784
		break;
6785
	}
6786
 
6787
	if ( !found )
6788
		return;
6789
 
6790
	// lets read our current bodies file
6791
	CLinkList<SBodies> bodiesList;
6792
	SBodies *currentSection = NULL;
212 cycrow 6793
	int e = extractGameFile(L"types/Bodies.pck", m_sTempDir + L"/Bodies.txt");
1 cycrow 6794
	if ( e )
6795
	{
6796
		CFileIO File;
212 cycrow 6797
		if ( File.open((e == -1) ? L"Bodies.txt" : m_sTempDir + L"/Bodies.txt") )
1 cycrow 6798
		{
221 cycrow 6799
			std::vector<Utils::WString> lines;
6800
			if(File.readLines(lines))
1 cycrow 6801
			{
6802
				int entries = 0;
221 cycrow 6803
				for (size_t j = 0; j < lines.size(); j++ )
1 cycrow 6804
				{
221 cycrow 6805
					Utils::WString line(lines.at(j));
160 cycrow 6806
					line.removeChar(' ');
6807
					line.removeChar(9);
6808
					if ( line.empty() || line[0] == '/' )
1 cycrow 6809
						continue;
6810
					if ( entries <= 0 )
6811
					{
221 cycrow 6812
						entries = line.token(L";", 2).toInt();
1 cycrow 6813
						currentSection = new SBodies;
221 cycrow 6814
						currentSection->sSection = line.token(L";", 1);
1 cycrow 6815
						bodiesList.push_back(currentSection);
6816
					}
6817
					else if ( currentSection )
6818
					{
221 cycrow 6819
						std::vector<Utils::WString> strs;
6820
						if(line.tokenise(L";", strs))
1 cycrow 6821
						{
221 cycrow 6822
							for (size_t i = 0; i < strs.size(); i++)
1 cycrow 6823
							{
160 cycrow 6824
								if ( strs[i].empty() )
1 cycrow 6825
									continue;
221 cycrow 6826
								if(!currentSection->lEntries.contains(strs[i] + L";"))
6827
									currentSection->lEntries.pushBack(strs[i] + L";");
1 cycrow 6828
								--entries;
6829
							}
6830
						}
6831
					}
6832
				}
6833
			}
52 cycrow 6834
			File.remove();
1 cycrow 6835
		}
6836
	}
6837
 
6838
	// lets now add any new entries
6839
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
6840
	{
6841
		SGameShip *s = node->Data();
6842
		if ( s->iType != WARETYPE_ADDED || !s->pPackage )
6843
			continue;
6844
 
6845
		// no dummies to add?
170 cycrow 6846
		if ( !s->pPackage->anyBodies() )
1 cycrow 6847
			continue;
6848
 
6849
		// add each dummy to list
170 cycrow 6850
		for(auto itr = s->pPackage->getBodies().begin(); itr != s->pPackage->getBodies().end(); itr++)
1 cycrow 6851
		{
216 cycrow 6852
			Utils::WString section = (*itr)->str.token(L";", 1);
6853
			Utils::WString body = (*itr)->str.tokens(L";", 2).remove(' ');
6854
			if ( body.right(1) != L";" )
6855
				body += L";";
1 cycrow 6856
 
6857
			// find the section to add into
6858
			SBodies *foundSection = NULL;
6859
			for ( CListNode<SBodies> *checkBody = bodiesList.Front(); checkBody; checkBody = checkBody->next() )
6860
			{
170 cycrow 6861
				if ( checkBody->Data()->sSection.Compare(section))
1 cycrow 6862
				{
6863
					foundSection = checkBody->Data();
6864
					break;
6865
				}
6866
			}
6867
 
6868
			if ( !foundSection )
6869
			{
6870
				foundSection = new SBodies;
216 cycrow 6871
				foundSection->sSection = section;
1 cycrow 6872
				bodiesList.push_back(foundSection);
6873
			}
170 cycrow 6874
			if(!foundSection->lEntries.contains(body))
6875
				foundSection->lEntries.pushBack(body);
1 cycrow 6876
		}
6877
	}
6878
 
6879
	// now write the file
221 cycrow 6880
	std::vector<Utils::WString> writeList;
1 cycrow 6881
	// the header first
221 cycrow 6882
	writeList.push_back(L"// Bodies file, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2));
6883
	writeList.push_back(L"//body type;num bodies;");
6884
	writeList.push_back(L"//[body id/name]");
1 cycrow 6885
 
6886
	// now our sections
6887
	for ( SBodies *bSection = bodiesList.First(); bSection; bSection = bodiesList.Next() )
6888
	{
221 cycrow 6889
		writeList.push_back(L"");
6890
		writeList.push_back(L"// Section: " + bSection->sSection);
6891
		writeList.push_back(bSection->sSection + L";" + Utils::WString::Number(bSection->lEntries.size()) + L";");
160 cycrow 6892
		for(auto itr = bSection->lEntries.begin(); itr != bSection->lEntries.end(); itr++)
1 cycrow 6893
		{
215 cycrow 6894
			Utils::WString str = (*itr)->str;
160 cycrow 6895
			str.removeChar(9);
6896
			str.removeChar(' ');
215 cycrow 6897
			if ( str.right(1) != L";" )
6898
				str += L";";
221 cycrow 6899
			writeList.push_back(str);
1 cycrow 6900
		}
6901
	}
6902
 
6903
	// write the file to disk
213 cycrow 6904
	CFileIO WriteFile(m_sTempDir + L"/Bodies.txt");
221 cycrow 6905
	if ( WriteFile.writeFile(writeList) )
1 cycrow 6906
	{
213 cycrow 6907
		this->packFile(&WriteFile, L"types\\Bodies.pck");
52 cycrow 6908
		WriteFile.remove();
1 cycrow 6909
	}
6910
}
6911
 
6912
void CPackages::CreateCustomStarts()
6913
{
6914
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
6915
	{
6916
		// find all spk files (only ones that can be custom starts
6917
		if ( node->Data()->GetType() != TYPE_SPK )
6918
			continue;
6919
 
6920
		CSpkFile *p = (CSpkFile *)node->Data();
6921
 
6922
		// only use custom starts
6923
		if ( !p->IsCustomStart() )
6924
			continue;
6925
 
6926
		// get the name of the start to use
216 cycrow 6927
		Utils::WString name = p->customStartName();
182 cycrow 6928
		if ( name.empty() )
1 cycrow 6929
			continue;
6930
 
6931
		// find if maps file exists
197 cycrow 6932
		Utils::WStringList createFiles;
6933
		createFiles.pushBack(name, L"maps/x3_universe");
6934
		createFiles.pushBack(name, L"types/Jobs");
6935
		createFiles.pushBack(name, L"types/JobWings");
1 cycrow 6936
 
182 cycrow 6937
		for(auto itr = createFiles.begin(); itr != createFiles.end(); itr++)
1 cycrow 6938
		{
196 cycrow 6939
			Utils::WString dir = CFileIO((*itr)->data).dir();
170 cycrow 6940
			FileType type = FileType::FILETYPE_EXTRA;
196 cycrow 6941
			if ( dir.Compare(L"maps") )
170 cycrow 6942
				type = FileType::FILETYPE_MAP;
1 cycrow 6943
 
197 cycrow 6944
			if ( !p->findFile((*itr)->str + L".xml", type) && !p->findFile((*itr)->str + L".pck", type))
1 cycrow 6945
			{
6946
				// create a maps files
197 cycrow 6947
				int e = this->extractGameFile((*itr)->data + L".pck", m_sTempDir + L"/" + (*itr)->data + L".pck");
1 cycrow 6948
				if ( e )
6949
				{
197 cycrow 6950
					CFileIO File((e == -1) ? ((*itr)->data + L".pck") : (m_sTempDir + L"/" + (*itr)->data + L".pck"));
52 cycrow 6951
					if ( File.exists() )
1 cycrow 6952
					{
197 cycrow 6953
						File.Rename(m_sCurrentDir + L"/" + dir + L"/" + (*itr)->str + L".pck");
6954
						this->addCreatedFile(dir + L"/" + (*itr)->str + L".pck");
1 cycrow 6955
					}
6956
				}
6957
			}
6958
		}
6959
	}
6960
}
6961
 
197 cycrow 6962
void CPackages::addCreatedFile(const Utils::WString &sFile)
1 cycrow 6963
{
197 cycrow 6964
	Utils::WString file = sFile.findRemove(m_sCurrentDir);
1 cycrow 6965
	while ( file[0] == '/' )
160 cycrow 6966
		file.erase(0, 1);
1 cycrow 6967
	while ( file[0] == '\\' )
160 cycrow 6968
		file.erase(0, 1);
1 cycrow 6969
 
197 cycrow 6970
	if(!_lCreatedFiles.contains(file, true))
6971
		_lCreatedFiles.pushBack(file);
1 cycrow 6972
}
6973
 
6974
void CPackages::CreateComponants()
6975
{
6976
	// first check we have any ships
179 cycrow 6977
	if ( m_lGameShips.empty() || !this->countPackages(TYPE_XSP, true) )
1 cycrow 6978
		return;
6979
 
6980
	CLinkList<SComponantEntry> dummyList;
6981
 
6982
	// now extract the existing dummies
213 cycrow 6983
	int e = extractGameFile(L"types/Components.pck", m_sTempDir + L"/Components.txt");
1 cycrow 6984
	if ( e )
6985
	{
6986
		// read the dummies
6987
		CFileIO File;
213 cycrow 6988
		if ( File.open((e == -1) ? L"Components.txt" : m_sTempDir + L"/Components.txt") )
1 cycrow 6989
		{
216 cycrow 6990
			std::vector<Utils::WString> lines;
6991
			if(File.readLines(lines))
1 cycrow 6992
			{
6993
				int insection = 0;
6994
				int insubsection = 0;
6995
				SComponantEntry *currentSection = NULL;
6996
				SComponantEntry2 *currentSubSection = NULL;
216 cycrow 6997
				for ( int j = 0; j < (int)lines.size(); j++ )
1 cycrow 6998
				{
216 cycrow 6999
					Utils::WString line(lines.at(j));
1 cycrow 7000
					if ( line[0] == '/' )
7001
						continue;
160 cycrow 7002
					line.removeChar('\r');
7003
					line = line.removeFirstSpace();
7004
					line = line.removeEndSpace();
7005
					if ( line.empty() )
1 cycrow 7006
						continue;
7007
 
7008
 
7009
					// read the section, first entry is section, second is size
160 cycrow 7010
					while ( !line.empty() )
1 cycrow 7011
					{
160 cycrow 7012
						line = line.removeFirstSpace();
7013
						if ( line.empty() )
1 cycrow 7014
							break;
7015
 
7016
						if ( !insection && !insubsection )
7017
						{
216 cycrow 7018
							Utils::WString section = line.token(L";", 1);
7019
							insection = line.token(L";", 2).toInt();
1 cycrow 7020
 
7021
							// search for the sections
7022
							currentSection = NULL;
7023
							for ( CListNode<SComponantEntry> *node = dummyList.Front(); node; node = node->next() )
7024
							{
7025
								SComponantEntry *d = node->Data();
184 cycrow 7026
								if ( d->sSection.Compare(section) )
1 cycrow 7027
								{
7028
									currentSection = node->Data();
7029
									break;
7030
								}
7031
							}
7032
 
7033
							if ( !currentSection )
7034
							{
7035
								currentSection = new SComponantEntry;
7036
								currentSection->sSection = section;
7037
								dummyList.push_back(currentSection);
7038
							}
7039
 
7040
							// we have some more ?
216 cycrow 7041
							line = line.remTokens(L";", 1, 2);
1 cycrow 7042
						}
7043
						else if ( !insubsection )
7044
						{
7045
							--insection;
216 cycrow 7046
							Utils::WString section = line.token(L";", 1);
7047
							insubsection = line.token(L";", 2).toInt();
1 cycrow 7048
 
7049
							currentSubSection = new SComponantEntry2;
7050
							currentSubSection->sSection = section;
7051
							currentSection->lEntries.push_back(currentSubSection);
7052
 
216 cycrow 7053
							line = line.remTokens(L";", 1, 2);
1 cycrow 7054
						}
7055
						else
7056
						{
7057
							--insubsection;
184 cycrow 7058
							line = line.remove(' ');
7059
							if(!currentSubSection->lEntries.contains(line))
7060
								currentSubSection->lEntries.pushBack(line);
216 cycrow 7061
							line = L"";
1 cycrow 7062
						}
7063
					}
7064
				}
7065
			}
7066
 
52 cycrow 7067
			File.remove();
1 cycrow 7068
		}
7069
 
7070
		// add the new entries for the ships
7071
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7072
		{
7073
			SGameShip *s = node->Data();
7074
			if ( s->iType != WARETYPE_ADDED || !s->pPackage )
7075
				continue;
7076
 
7077
			// no dummies to add?
7078
			if ( !s->pPackage->AnyComponents() )
7079
				continue;
7080
 
7081
			// add each dummy to list
7082
			for ( CListNode<SComponent> *dNode = s->pPackage->GetComponents()->Front(); dNode; dNode = dNode->next() )
7083
			{
7084
				SComponent *dummy = dNode->Data();
7085
				SComponantEntry *found = NULL;
7086
				SComponantEntry2 *found2 = NULL;
7087
				for ( CListNode<SComponantEntry> *eNode = dummyList.Front(); eNode; eNode = eNode->next() )
7088
				{
184 cycrow 7089
					if ( eNode->Data()->sSection.Compare(dummy->sSection) )
1 cycrow 7090
					{
7091
						found = eNode->Data();
7092
						break;
7093
					}
7094
				}
7095
				if ( !found )
7096
				{
7097
					found = new SComponantEntry;
7098
					found->sSection = dummy->sSection;
7099
					dummyList.push_back(found);
7100
					found2 = new SComponantEntry2;
7101
					found2->sSection = dummy->sSection2;
7102
					found->lEntries.push_back(found2);
7103
				}
7104
				// else check for the 2nd section
7105
				else
7106
				{
7107
					for ( CListNode<SComponantEntry2> *cNode = found->lEntries.Front(); cNode; cNode = cNode->next() )
7108
					{
184 cycrow 7109
						if ( cNode->Data()->sSection.Compare(dummy->sSection2) )
1 cycrow 7110
						{
7111
							found2 = cNode->Data();
7112
							break;
7113
						}
7114
					}
7115
 
7116
					if ( !found2 )
7117
					{
7118
						found2 = new SComponantEntry2;
7119
						found2->sSection = dummy->sSection2;
7120
						found->lEntries.push_back(found2);
7121
					}
7122
					else
7123
					{
7124
						bool f = false;
184 cycrow 7125
						for(auto itr = found2->lEntries.begin(); itr != found2->lEntries.end(); itr++)
1 cycrow 7126
						{
184 cycrow 7127
							if ( dummy->sData.remove(' ').Compare((*itr)->str) )
1 cycrow 7128
							{
7129
								f = true;
7130
								break;
7131
							}
7132
						}
7133
 
7134
						if ( f )
7135
							continue;
7136
					}
7137
				}
7138
 
184 cycrow 7139
				found2->lEntries.pushBack(dummy->sData.remove(' '));
1 cycrow 7140
			}
7141
		}
7142
 
7143
		// finally, write the file
216 cycrow 7144
		std::vector<Utils::WString> lines;
7145
		lines.push_back(L"// Components file, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2));
1 cycrow 7146
		for ( SComponantEntry *dummy = dummyList.First(); dummy; dummy = dummyList.Next() )
7147
		{
216 cycrow 7148
			lines.push_back(L"");
7149
			lines.push_back(L"// Section: " + dummy->sSection + L" Entries: " + Utils::WString::Number((long)dummy->lEntries.size()));
7150
			lines.push_back(dummy->sSection + L";" + Utils::WString::Number(dummy->lEntries.size()) + L";");
1 cycrow 7151
			for ( CListNode<SComponantEntry2> *comp = dummy->lEntries.Front(); comp; comp = comp->next() )
7152
			{
216 cycrow 7153
				lines.push_back(comp->Data()->sSection + L";" + Utils::WString::Number((long)comp->Data()->lEntries.size()) + L";");
184 cycrow 7154
				for(auto itr = comp->Data()->lEntries.begin(); itr != comp->Data()->lEntries.end(); itr++)
1 cycrow 7155
				{
216 cycrow 7156
					Utils::WString cStr = (*itr)->str;
160 cycrow 7157
					cStr.removeEndSpace();
7158
					cStr.removeChar(9);
7159
					cStr.removeChar('\r');
216 cycrow 7160
					if ( cStr.right(1) != L";" )
7161
						cStr += L";";
1 cycrow 7162
					lines.push_back(cStr);
7163
				}
7164
			}
7165
		}
7166
 
7167
		// write the file to disk
213 cycrow 7168
		CFileIO WriteFile(m_sTempDir + L"/Components.txt");
216 cycrow 7169
		if ( WriteFile.writeFile(lines) )
1 cycrow 7170
		{
213 cycrow 7171
			this->packFile(&WriteFile, L"types\\Components.pck");
52 cycrow 7172
			WriteFile.remove();
1 cycrow 7173
		}
7174
	}
7175
}
7176
 
89 cycrow 7177
bool CPackages::readWares(int iLang, CLinkList<SWareEntry> &list)
88 cycrow 7178
{
89 cycrow 7179
	if ( iLang == 0 ) iLang = m_iLanguage;
88 cycrow 7180
 
197 cycrow 7181
	Utils::WString empWares = this->empWaresForGame();
89 cycrow 7182
 
7183
	for(CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next()) {
91 cycrow 7184
		if ( !node->Data()->IsEnabled() ) continue;
89 cycrow 7185
		node->Data()->readWares(iLang, list, empWares);
88 cycrow 7186
	}
7187
 
89 cycrow 7188
	return true;
7189
}
88 cycrow 7190
 
89 cycrow 7191
bool CPackages::readCommands(int iLang, CLinkList<SCommandSlot> &list)
7192
{
7193
	if ( iLang == 0 ) iLang = m_iLanguage;
7194
 
7195
	for(CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next()) {
91 cycrow 7196
		if ( !node->Data()->IsEnabled() ) continue;
89 cycrow 7197
		node->Data()->readCommands(iLang, list);
88 cycrow 7198
	}
7199
 
89 cycrow 7200
	return true;
7201
}
88 cycrow 7202
 
89 cycrow 7203
bool CPackages::readWingCommands(int iLang, CLinkList<SCommandSlot> &list)
7204
{
7205
	if ( iLang == 0 ) iLang = m_iLanguage;
7206
 
7207
	for(CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next()) {
91 cycrow 7208
		if ( !node->Data()->IsEnabled() ) continue;
89 cycrow 7209
		node->Data()->readWingCommands(iLang, list);
7210
	}
7211
 
88 cycrow 7212
	return true;
7213
}
7214
 
197 cycrow 7215
int CPackages::_warePriceOverride(enum WareTypes type, int pos, const Utils::WString &id)
88 cycrow 7216
{
7217
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
7218
		if ( node->Data()->type == type ) {
7219
			if ( node->Data()->type == Ware_Custom && id.Compare(node->Data()->id) ) return node->Data()->relval;
7220
			else if ( node->Data()->type != Ware_Custom && node->Data()->pos == pos ) return node->Data()->relval;
7221
		}
7222
	}
7223
	return 0;
7224
}
7225
 
197 cycrow 7226
bool CPackages::_wareNotoOverride(enum WareTypes type, int pos, const Utils::WString &id, int *noto)
88 cycrow 7227
{
7228
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
7229
		if ( node->Data()->type == type && node->Data()->bNotority ) {
7230
			if ( node->Data()->type == Ware_Custom && !id.Compare(node->Data()->id) ) continue;
7231
			else if ( node->Data()->type != Ware_Custom && node->Data()->pos != pos ) continue;
7232
 
7233
			(*noto) = node->Data()->notority;
7234
			return true;
7235
		}
7236
	}
7237
	return false;
7238
}
7239
 
197 cycrow 7240
void CPackages::_removeWareOverride(enum WareTypes type, int pos, const Utils::WString &id)
88 cycrow 7241
{
7242
	for(CListNode<SWarePriceOverride> *node = m_lWarePrices.Front(); node; node = node->next()) {
7243
		if ( node->Data()->type == type ) {
7244
			if ( node->Data()->type == Ware_Custom && !id.Compare(node->Data()->id) ) continue;
7245
			else if ( node->Data()->type != Ware_Custom && node->Data()->pos != pos ) continue;
7246
			m_lWarePrices.remove(node);
7247
			break;
7248
		}
7249
	}
7250
}
7251
 
7252
int CPackages::empOveridePrice(int id)
7253
{
197 cycrow 7254
	return _warePriceOverride(Ware_EMP, id, Utils::WString::Null()); 
88 cycrow 7255
}
7256
 
7257
bool CPackages::empOverideNoto(int id, int *noto)
7258
{
197 cycrow 7259
	return _wareNotoOverride(Ware_EMP, id, Utils::WString::Null(), noto);
88 cycrow 7260
}
7261
 
7262
int CPackages::builtInWareOveridePrice(int id)
7263
{
197 cycrow 7264
	return _warePriceOverride(Ware_BuiltIn, id, Utils::WString::Null()); 
88 cycrow 7265
}
7266
 
7267
bool CPackages::builtInWareOverideNoto(int id, int *noto)
7268
{
197 cycrow 7269
	return _wareNotoOverride(Ware_BuiltIn, id, Utils::WString::Null(), noto);
88 cycrow 7270
}
7271
 
197 cycrow 7272
int CPackages::customWareOveridePrice(const Utils::WString &id)
88 cycrow 7273
{
7274
	return _warePriceOverride(Ware_Custom, 0, id); 
7275
}
7276
 
197 cycrow 7277
bool CPackages::customWareOverideNoto(const Utils::WString &id, int *noto)
88 cycrow 7278
{
7279
	return _wareNotoOverride(Ware_Custom, 0, id, noto);
7280
}
7281
 
7282
void CPackages::removeEmpOverride(int pos)
7283
{
197 cycrow 7284
	_removeWareOverride(Ware_EMP, pos, Utils::WString::Null());
88 cycrow 7285
}
7286
 
7287
void CPackages::removeBuiltinWareOverride(int pos)
7288
{
197 cycrow 7289
	_removeWareOverride(Ware_BuiltIn, pos, Utils::WString::Null());
88 cycrow 7290
}
7291
 
197 cycrow 7292
void CPackages::removeCustomWareOverride(const Utils::WString &id)
88 cycrow 7293
{
7294
	_removeWareOverride(Ware_Custom, 0, id);
7295
}
7296
 
7297
 
197 cycrow 7298
bool CPackages::readGlobals(Utils::WStringList &globals) const
1 cycrow 7299
{
197 cycrow 7300
	int e = extractGameFile(L"types/Globals.pck", m_sTempDir);
1 cycrow 7301
	if ( e )
7302
	{
197 cycrow 7303
		CFileIO File((e == -1) ? L"Globals.txt" : m_sTempDir + L"/Globals.txt");
52 cycrow 7304
		if ( File.exists() )
1 cycrow 7305
		{
197 cycrow 7306
			std::vector<Utils::WString> lines;
173 cycrow 7307
			if(File.readLines(lines))
1 cycrow 7308
			{
7309
				int entries = -1;
173 cycrow 7310
				for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 7311
				{
197 cycrow 7312
					Utils::WString str = itr->remove('\r').remove(9);
173 cycrow 7313
					str.removeFirstSpace();
1 cycrow 7314
 
173 cycrow 7315
					if ( str.empty() )
1 cycrow 7316
						continue;
197 cycrow 7317
					if ( str[0] == L'/' )
1 cycrow 7318
						continue;
7319
 
7320
					// remove comments
197 cycrow 7321
					if (str.contains(L"/") ) 
7322
						str = str.token(L"/", 1);
1 cycrow 7323
 
7324
					if ( entries == -1 )
197 cycrow 7325
						entries = str.token(L";", 1).toInt();
1 cycrow 7326
					else
197 cycrow 7327
						globals.pushBack(str.token(L";", 1), str.token(L";", 2));
1 cycrow 7328
				}
7329
 
7330
				return true;
7331
			}
7332
		}
7333
	}
7334
 
7335
	return false;
7336
}
7337
 
7338
void CPackages::CreateGlobals()
7339
{
238 cycrow 7340
	if (_lGlobals.empty())
7341
	{
7342
		bool anyGlobals = false;
7343
		for (CListNode<CBaseFile>* node = m_lPackages.Front(); node; node = node->next())
7344
		{
258 cycrow 7345
			if (node->Data()->IsEnabled() && node->Data()->getGlobals().size())
238 cycrow 7346
			{
7347
				anyGlobals = true;
7348
				break;
7349
			}
7350
		}
1 cycrow 7351
 
238 cycrow 7352
		if(!anyGlobals)
7353
			return; // no global settings
7354
	}
7355
 
197 cycrow 7356
	Utils::WStringList globals;
173 cycrow 7357
	if (readGlobals(globals))
1 cycrow 7358
	{
233 cycrow 7359
		// apply package settings
7360
		for (CListNode<CBaseFile>* node = m_lPackages.Front(); node; node = node->next())
7361
		{
7362
			CBaseFile* p = node->Data();
258 cycrow 7363
			if (p->IsEnabled())
233 cycrow 7364
			{
258 cycrow 7365
				auto& list = p->getGlobals();
7366
				for (auto itr = list.begin(); itr != list.end(); itr++)
7367
				{
7368
					if (!globals.changeData((*itr)->str, (*itr)->data))
7369
						globals.pushBack((*itr)->str, (*itr)->data);
7370
				}
233 cycrow 7371
			}
7372
		}
7373
 
1 cycrow 7374
		// apply out settings
233 cycrow 7375
		for (auto itr = _lGlobals.begin(); itr != _lGlobals.end(); itr++)
7376
		{
7377
			if(!globals.changeData((*itr)->str, (*itr)->data))
7378
				globals.pushBack((*itr)->str, (*itr)->data);
7379
		}
1 cycrow 7380
 
7381
		// now write it
197 cycrow 7382
		Utils::WStringList writeList;
173 cycrow 7383
		for(auto itr = globals.begin(); itr != globals.end(); itr++)
197 cycrow 7384
			writeList.pushBack((*itr)->str + L";" + (*itr)->data + L";");
1 cycrow 7385
 
7386
		// finally, write the file
213 cycrow 7387
		writeList.pushFront(Utils::WString::Number(writeList.size()) + L"; /globals amount", L"");
197 cycrow 7388
		writeList.pushFront(L"// Globals file, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2), L"");
1 cycrow 7389
 
197 cycrow 7390
		CFileIO WriteFile(m_sTempDir + L"/Globals.txt");
173 cycrow 7391
		if ( WriteFile.writeFile(&writeList) )
1 cycrow 7392
		{
197 cycrow 7393
			this->packFile(&WriteFile, L"types/Globals.pck");
52 cycrow 7394
			WriteFile.remove();
1 cycrow 7395
		}
7396
	}
7397
}
7398
 
7399
void CPackages::CreateTShips()
7400
{
7401
	// no ships ?
7402
	if ( m_lGameShips.empty() )
7403
		return;
7404
 
7405
	// get the cockpit list to match with ships turrets
216 cycrow 7406
	Utils::WStringList Cockpits;
7407
	Utils::WStringList cockpitList;
179 cycrow 7408
	if(_createCockpits(cockpitList))
1 cycrow 7409
	{
179 cycrow 7410
		for(auto itr = cockpitList.begin(); itr != cockpitList.end(); itr++)
1 cycrow 7411
		{
216 cycrow 7412
			Utils::WString id = (*itr)->str.token(L";", 19);
179 cycrow 7413
			Cockpits.pushBack(id);
1 cycrow 7414
		}
7415
	}
7416
 
7417
	CLinkList<SGameShip> shipOverrides;
7418
	for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7419
	{
7420
		if ( node->Data()->iType != WARETYPE_ADDED || !node->Data()->pPackage )
7421
			continue;		
7422
		if ( !node->Data()->pPackage->IsExistingShip() )
7423
			continue;
7424
		shipOverrides.push_back(node->Data());
7425
	}
7426
 
7427
	// read the existing tships file
213 cycrow 7428
	int e = extractGameFile(L"types/TShips.pck", m_sTempDir + L"/TShips.txt");
1 cycrow 7429
	if ( e )
7430
	{
7431
		int fileType = 51;
216 cycrow 7432
		std::vector<Utils::WString> tshipsList;
1 cycrow 7433
 
7434
		// if we have no buffer, lets create one
7435
		CFileIO File;
213 cycrow 7436
		if ( File.open((e == -1) ? L"TShips.txt" : m_sTempDir + L"/TShips.txt") )
1 cycrow 7437
		{
7438
			int shiptext = SHIPSTARTTEXT;
7439
 
216 cycrow 7440
			std::vector<Utils::WString> lines;
7441
			if(File.readLines(lines))
1 cycrow 7442
			{
7443
				int count = -1;
216 cycrow 7444
				for ( int j = 0; j < (int)lines.size(); j++ )
1 cycrow 7445
				{
216 cycrow 7446
					Utils::WString line(lines.at(j));
1 cycrow 7447
					if ( line[0] == '/' )
7448
						continue;
160 cycrow 7449
					line.removeChar('\r');
7450
					line.removeChar(9);
7451
					line = line.removeFirstSpace();
7452
					line = line.removeEndSpace();
7453
					if ( line.empty() )
1 cycrow 7454
						continue;
7455
 
7456
					if ( count == -1 )
7457
					{
216 cycrow 7458
						fileType = line.token(L";", 1).toInt();
7459
						count = line.token(L";", 2).toInt();
1 cycrow 7460
					}
7461
					else
7462
					{
216 cycrow 7463
						if ( line.right(1) != L";" )
7464
							line += L";";
1 cycrow 7465
 
7466
						// check for any ship overrides
7467
						bool added = false;
7468
						if ( !shipOverrides.empty() )
7469
						{
7470
							CShipData shipData;
170 cycrow 7471
							if ( shipData.readShipData(line) )
1 cycrow 7472
							{
7473
								for ( CListNode<SGameShip> *node = shipOverrides.Front(); node; node = node->next() )
7474
								{
7475
									SGameShip *s = node->Data();
217 cycrow 7476
									if ( !s->pPackage->shipID().Compare(shipData.sID))
1 cycrow 7477
										continue;
7478
									s->iText = shiptext;
7479
									if ( !s->pPackage->GetOriginalDescription() )
7480
										shiptext += 2;
179 cycrow 7481
									s->iPos = tshipsList.size();
1 cycrow 7482
									added = true;
179 cycrow 7483
									tshipsList.push_back(s->pPackage->formatShipData(Cockpits, &s->iText, m_iGame));
1 cycrow 7484
									shipOverrides.remove(node);
7485
									break;
7486
								}
7487
							}
7488
						}
7489
 
7490
						if ( !added )
179 cycrow 7491
							tshipsList.push_back(line);
1 cycrow 7492
						--count;
7493
						if ( count < 0 )
7494
							break;
7495
					}
7496
				}
7497
			}
7498
 
52 cycrow 7499
			File.remove();
1 cycrow 7500
 
7501
			// assign the ship buffer
7502
			if ( !m_iShipBuffer )
179 cycrow 7503
				m_iShipBuffer = tshipsList.size() + 15;
1 cycrow 7504
			// there seems to be too many additional entries, we have no choise but to change the buffer
179 cycrow 7505
			else if ( static_cast<size_t>(m_iShipBuffer) <= tshipsList.size() )
7506
				m_iShipBuffer = tshipsList.size() + 15;
1 cycrow 7507
 
216 cycrow 7508
			Utils::WString bufferStart;
1 cycrow 7509
			if ( m_iGame == GAME_X3 )
216 cycrow 7510
				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 7511
			else
249 cycrow 7512
				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;";
7513
 
1 cycrow 7514
			// add the buffers now
179 cycrow 7515
			for ( int i = tshipsList.size(); i < m_iShipBuffer; i++ )
216 cycrow 7516
				tshipsList.push_back(bufferStart + L"SHIP_BUFFER;");
1 cycrow 7517
 
7518
			// now lets add our tships line
7519
			for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7520
			{
7521
				SGameShip *s = node->Data();
7522
				if ( s->pPackage && s->pPackage->IsExistingShip() )
7523
					continue;
179 cycrow 7524
				s->iPos = tshipsList.size();
1 cycrow 7525
				if ( s->iType == WARETYPE_ADDED && s->pPackage )
7526
				{
7527
					s->iText = shiptext;
7528
					if ( !s->pPackage->GetOriginalDescription() )
7529
						shiptext += 2;
7530
 
179 cycrow 7531
					tshipsList.push_back(s->pPackage->formatShipData(Cockpits, &s->iText, m_iGame));
1 cycrow 7532
				}
7533
				else if ( s->iType == WARETYPE_DELETED )
216 cycrow 7534
					tshipsList.push_back(bufferStart + L"SHIP_DELETED;");
1 cycrow 7535
				else if ( s->iType == WARETYPE_DISABLED )
216 cycrow 7536
					tshipsList.push_back(bufferStart + L"SHIP_DISABLED;");
1 cycrow 7537
				else
216 cycrow 7538
					tshipsList.push_back(bufferStart + L"SHIP_SPACER;");
1 cycrow 7539
			}
7540
 
7541
			// finally, write the file
216 cycrow 7542
			tshipsList.insert(tshipsList.begin(), Utils::WString::Number(fileType) + L";" + Utils::WString::Number(tshipsList.size()) + L";");
7543
			tshipsList.insert(tshipsList.begin(), L"// TShips file, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2));
1 cycrow 7544
 
213 cycrow 7545
			CFileIO WriteFile(m_sTempDir + L"/TShips.txt");
216 cycrow 7546
			if ( WriteFile.writeFile(tshipsList) )
1 cycrow 7547
			{
213 cycrow 7548
				this->packFile(&WriteFile, L"types/TShips.pck");
52 cycrow 7549
				WriteFile.remove();
1 cycrow 7550
			}
7551
		}
7552
	}
7553
}
7554
 
197 cycrow 7555
bool CPackages::packFile(const Utils::WString &filename) const
1 cycrow 7556
{
7557
	// compress the file
7558
	CFileIO File(filename);
7559
	size_t fileSize;
7560
	char *fileData = File.ReadToData(&fileSize);
7561
 
7562
	if ( fileData && fileSize)
7563
	{
7564
		size_t newFileSize;
7565
		unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
7566
		if ( pckData )
7567
		{
196 cycrow 7568
			Utils::WString ext = L"pck";
7569
			if ( File.isFileExtension(L"bob") )
7570
				ext = L"pbb";
7571
			else if ( File.isFileExtension(L"bod") )
7572
				ext = L"pbd";
160 cycrow 7573
			CFileIO pckFile(File.changeFileExtension(ext));
121 cycrow 7574
			if ( !CDirIO(pckFile.dir()).exists() )
160 cycrow 7575
				CDirIO(pckFile.dir()).create();
1 cycrow 7576
			pckFile.WriteData((char *)pckData, newFileSize);
7577
			return true;
7578
		}
7579
	}
7580
 
7581
	return false;
7582
}
7583
 
197 cycrow 7584
bool CPackages::unPackFile(const Utils::WString &filename, bool checkxml) const
1 cycrow 7585
{
7586
	// compress the file
7587
	CFileIO File(filename);
7588
	size_t fileSize;
7589
	char *fileData = File.ReadToData(&fileSize);
7590
 
7591
	if ( fileData && fileSize)
7592
	{
7593
		size_t newFileSize;
96 cycrow 7594
		unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize, false);
7595
		if ( !pckData )
7596
			pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
7597
 
1 cycrow 7598
		if ( pckData )
7599
		{
196 cycrow 7600
			Utils::WString ext = L"txt";
7601
			if ( File.isFileExtension(L"pbb") )
7602
				ext = L"bob";
7603
			else if ( File.isFileExtension(L"pbd") )
7604
				ext = L"bod";
160 cycrow 7605
			CFileIO pckFile(File.changeFileExtension(ext));
121 cycrow 7606
			if ( !CDirIO(pckFile.dir()).exists() )
160 cycrow 7607
				CDirIO(pckFile.dir()).create();
1 cycrow 7608
			pckFile.WriteData((char *)pckData, newFileSize);
7609
 
7610
			// check for xml and rename
7611
			if ( checkxml )
7612
			{
7613
				int readmaxlines = 20;
7614
				bool isxml = false;
7615
				do {
221 cycrow 7616
					Utils::WString line = pckFile.readEndOfLine();
7617
					if ( line.contains(L"<language id=") )
1 cycrow 7618
					{
7619
						isxml = true;
7620
						break;
7621
					}
221 cycrow 7622
					else if ( line.contains(L"<page id=") )
1 cycrow 7623
					{
7624
						isxml = true;
7625
						break;
7626
					}
221 cycrow 7627
					else if ( line.contains(L"<?xml") || line.contains(L"<script>") )
1 cycrow 7628
					{
7629
						isxml = true;
7630
						break;
7631
					}
7632
					--readmaxlines;
7633
					if ( readmaxlines <= 0 )
7634
						break;
52 cycrow 7635
				} while (pckFile.isOpened());
1 cycrow 7636
 
52 cycrow 7637
				if ( pckFile.isOpened() )
82 cycrow 7638
					pckFile.close();
1 cycrow 7639
 
7640
				if ( isxml )
196 cycrow 7641
					pckFile.Rename(pckFile.changeFileExtension(L"xml"));
1 cycrow 7642
			}
7643
 
7644
			return true;
7645
		}
7646
	}
7647
 
7648
	return false;
7649
}
7650
 
197 cycrow 7651
bool CPackages::packFile(CFileIO* File, const Utils::WString &sFilename) const
1 cycrow 7652
{
197 cycrow 7653
	Utils::WString filename = sFilename.findReplace(L"\\", L"/");
1 cycrow 7654
	if ( m_iGame == GAME_X3 )
7655
	{
7656
		CCatFile catFile;
197 cycrow 7657
		int error = catFile.open(m_sCurrentDir + L"/mods/PluginManager.cat", this->getAddonDir(), CATREAD_CATDECRYPT, true);
1 cycrow 7658
		if ( error == CATERR_NONE || error == CATERR_CREATED )
7659
		{
7660
			// it it wrote ok, remove the old ones
197 cycrow 7661
			if ( !catFile.appendFile(File->fullFilename(), filename, true, true) )
1 cycrow 7662
				return false;
7663
			return true;
7664
		}
7665
	}
7666
	else
7667
	{
7668
		// compress the file
7669
		size_t fileSize;
102 cycrow 7670
		char *fileData = CFileIO(File->fullFilename()).ReadToData(&fileSize);
1 cycrow 7671
 
7672
		if ( fileData && fileSize)
7673
		{
7674
			size_t newFileSize;
7675
			unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);
7676
			if ( pckData )
7677
			{
7678
//				if ( !this->GetAddonDir().Empty() && CCatFile::IsAddonDir(filename) )
7679
//					filename = this->GetAddonDir() + "/" + filename;
197 cycrow 7680
				CFileIO pckFile(m_sCurrentDir + L"/" + filename);
121 cycrow 7681
				if ( !CDirIO(pckFile.dir()).exists() )
160 cycrow 7682
					CDirIO(pckFile.dir()).create();
1 cycrow 7683
				pckFile.WriteData((char *)pckData, newFileSize);
197 cycrow 7684
				const_cast<CPackages *>(this)->addCreatedFile(pckFile.fullFilename());
1 cycrow 7685
				return true;
7686
			}
7687
		}
7688
	}
7689
 
7690
	return false;
7691
}
7692
 
216 cycrow 7693
size_t CPackages::_createCockpits(Utils::WStringList &list)
1 cycrow 7694
{
7695
	// first check we have any ships
179 cycrow 7696
	if ( m_lGameShips.empty() || !this->countPackages(TYPE_XSP, true) )
1 cycrow 7697
		return NULL;
7698
 
7699
	// now extract the existing cockpits
7700
	int fileType = 51;
213 cycrow 7701
	int e = extractGameFile(L"types/TCockpits.pck", m_sTempDir + L"/TCockpits.txt");
1 cycrow 7702
	if ( e )
7703
	{
7704
		// read the dummies
7705
		CFileIO File;
213 cycrow 7706
		if ( File.open((e == -1) ? L"TCockpits.txt" : m_sTempDir + L"/TCockpits.txt") )
1 cycrow 7707
		{
216 cycrow 7708
			std::vector<Utils::WString> lines;
173 cycrow 7709
			if(File.readLines(lines))
1 cycrow 7710
			{
7711
				int count = -1;
173 cycrow 7712
				for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 7713
				{
216 cycrow 7714
					Utils::WString line(*itr);
173 cycrow 7715
					line.removeChar('\r');
7716
					line.removeChar(9);
7717
					line = line.removeFirstSpace();
7718
					line = line.removeEndSpace();
7719
					if ( line.empty() )
1 cycrow 7720
						continue;
7721
					if ( line[0] == '/' )
7722
						continue;
7723
 
7724
					if ( count == -1 )
7725
					{
216 cycrow 7726
						fileType = line.token(L";", 1).toInt();
7727
						count = line.token(L";", 2).toInt();
1 cycrow 7728
					}
7729
					else
7730
					{
173 cycrow 7731
						while ( !line.empty() )
1 cycrow 7732
						{
216 cycrow 7733
							Utils::WString data = line.tokens(L";", 1, 19);
7734
							list.pushBack(data + L";");
7735
							line = line.remTokens(L";", 1, 19);
1 cycrow 7736
 
7737
							--count;
7738
							if ( count < 1 )
7739
								break;
7740
						}
7741
					}
7742
				}
7743
			}
7744
 
52 cycrow 7745
			File.remove();
1 cycrow 7746
		}
7747
 
7748
		// now add the new ones
7749
		for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() )
7750
		{
7751
			SGameShip *s = node->Data();
7752
			if ( s->iType != WARETYPE_ADDED || !s->pPackage )
7753
				continue;
7754
 
7755
			if ( !s->pPackage->AnyCockpits() )
7756
				continue;
7757
 
7758
			for ( CListNode<SCockpit> *cn = s->pPackage->GetCockpits()->Front(); cn; cn = cn->next() )
7759
			{
7760
				bool foundEntry = false;
216 cycrow 7761
				Utils::WString cockpitStr = cn->Data()->sCockpit;
1 cycrow 7762
				// search for matching game entry
7763
				for ( CListNode<SWeaponMask> *wm = cn->Data()->lWeaponMask.Front(); wm; wm = wm->next() )
7764
				{
7765
					if ( wm->Data()->iGame == (m_iGame - 1) )
7766
					{
7767
						if ( wm->Data()->iMask != -1 )
216 cycrow 7768
							cockpitStr = cockpitStr.replaceToken(L";", 9, Utils::WString::Number(wm->Data()->iMask));
1 cycrow 7769
						foundEntry = true;
7770
						break;
7771
					}
7772
				}
39 cycrow 7773
 
7774
				bool found = false;
179 cycrow 7775
				for(auto itr = list.begin(); itr != list.end(); itr++)
1 cycrow 7776
				{
216 cycrow 7777
					if ((*itr)->str.token(L";", 19).Compare(cn->Data()->sCockpit.token(L";", 19)))
1 cycrow 7778
					{
7779
						// only replace existing entry if we have sepeperate weapon masks set
7780
						if ( foundEntry )
179 cycrow 7781
							(*itr)->str = cockpitStr;
1 cycrow 7782
						found = true;
7783
						break;
7784
					}
7785
				}
7786
 
7787
				if ( !found )
179 cycrow 7788
					list.pushBack(cockpitStr);
1 cycrow 7789
			}
7790
		}
7791
 
7792
		// finally, write the file
216 cycrow 7793
		list.pushFront(Utils::WString::Number(fileType) + L";" + Utils::WString::Number(list.size()) + L";");
7794
		list.pushFront(L"// TCockpits file, created by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2));
1 cycrow 7795
 
213 cycrow 7796
		CFileIO WriteFile(m_sTempDir + L"/TCockpits.txt");
179 cycrow 7797
		if ( WriteFile.writeFile(&list) )
1 cycrow 7798
		{
213 cycrow 7799
			this->packFile(&WriteFile, L"types\\TCockpits.pck");
52 cycrow 7800
			WriteFile.remove();
1 cycrow 7801
		}
7802
 
7803
		// remove those entrys
179 cycrow 7804
		list.popFront();
7805
		list.popFront();
1 cycrow 7806
	}
7807
 
179 cycrow 7808
	return list.size();
1 cycrow 7809
}
7810
 
221 cycrow 7811
CBaseFile *CPackages::findScriptByAuthor(const Utils::WString &author, CBaseFile *prev)
1 cycrow 7812
{
7813
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
7814
	{
7815
		CBaseFile *p = node->Data();
7816
		if ( prev )
7817
		{
7818
			if ( p == prev )
7819
				prev = NULL;
7820
			continue;
7821
		}
182 cycrow 7822
		if ( p->author().Compare(author) )
1 cycrow 7823
			return p;
7824
	}
7825
 
7826
	return NULL;
7827
}
7828
 
221 cycrow 7829
bool CPackages::extractAll(CBaseFile *baseFile, const Utils::WString &dir, int game, bool includedir, CProgressInfo *progress) const
129 cycrow 7830
{
7831
	if (!baseFile)
7832
		return false;
7833
 
210 cycrow 7834
	Utils::WStringList gameAddons;
129 cycrow 7835
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
7836
	{
197 cycrow 7837
		SGameExe *exe = m_gameExe.game(i);
129 cycrow 7838
		if (!exe->sAddon.empty())
210 cycrow 7839
			gameAddons.pushBack(Utils::WString::Number(i + 1), exe->sAddon);
129 cycrow 7840
	}
7841
 
7842
	return baseFile->extractAll(dir, game, gameAddons, includedir, progress);
7843
}
7844
 
210 cycrow 7845
bool CPackages::generatePackagerScript(CBaseFile *baseFile, bool wildcard, Utils::WStringList *list, int game, bool datafile) const
127 cycrow 7846
{	
7847
	if (!baseFile)
7848
		return false;
7849
 
210 cycrow 7850
	Utils::WStringList gameAddons;
127 cycrow 7851
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
7852
	{
197 cycrow 7853
		SGameExe *exe = m_gameExe.game(i);
127 cycrow 7854
		if (!exe->sAddon.empty())
210 cycrow 7855
			gameAddons.pushBack(Utils::WString::Number(i + 1), exe->sAddon);
127 cycrow 7856
	}
7857
 
7858
	return baseFile->GeneratePackagerScript(wildcard, list, game, gameAddons, datafile);
7859
}
7860
 
197 cycrow 7861
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 7862
{
7863
	// check the file exists
131 cycrow 7864
	if ( !CFileIO::Exists(filename) )
1 cycrow 7865
		return NULL;
7866
 
7867
	// read all the lines
7868
	CFileIO File(filename);
98 cycrow 7869
	if ( !File.startRead() ) 
1 cycrow 7870
		return NULL;
7871
 
197 cycrow 7872
	Utils::WStringList fileData;
98 cycrow 7873
 
7874
	int iLine = 0;
7875
 
1 cycrow 7876
	CBaseFile *package = NULL;
7877
 
98 cycrow 7878
	while(!File.atEnd()) {
7879
		// read the next line in the file
199 cycrow 7880
		Utils::WString line = File.readEndOfLine();
1 cycrow 7881
 
98 cycrow 7882
		// filter out any characters we dont really want
197 cycrow 7883
		line.removeChar(L"\t\r");
98 cycrow 7884
		line.removeFirstSpace();
1 cycrow 7885
 
98 cycrow 7886
		if ( line.empty() ) continue;
1 cycrow 7887
 
98 cycrow 7888
		// check for any comments (so we can ignore them)
197 cycrow 7889
		if ( line.left(2).Compare(L"//") || line[0] == L'#' ) continue;
1 cycrow 7890
 
98 cycrow 7891
		++iLine;
7892
 
1 cycrow 7893
		// all commands start with a keyword followed by a colon, if one doesn't exist, it cant be a valid line
197 cycrow 7894
		if ( !line.contains(L':') )
1 cycrow 7895
		{
7896
			// there are some exeptions, and these are one word entrys only
98 cycrow 7897
			line.removeEndSpace();
197 cycrow 7898
			if ( line.contains(L" ") )
1 cycrow 7899
			{
7900
				if ( malformedLines )
197 cycrow 7901
					malformedLines->pushBack(line, Utils::WString::Number(iLine));
1 cycrow 7902
				continue;
7903
			}
7904
		}
7905
 
7906
		// check for the type line
197 cycrow 7907
		if ( !package && line.token(L":", 1).Compare(L"FileType") )
1 cycrow 7908
		{
197 cycrow 7909
			Utils::WString sFileType = line.tokens(L":", 2).removeFirstSpace();
7910
			if ( sFileType.Compare(L"Ship") )
1 cycrow 7911
				package = new CXspFile();
197 cycrow 7912
			else if ( sFileType.Compare(L"Script") )
1 cycrow 7913
				package = new CSpkFile();
197 cycrow 7914
			else if ( sFileType.Compare(L"Base") )
1 cycrow 7915
				package = new CBaseFile();
98 cycrow 7916
			continue;
1 cycrow 7917
		}
7918
 
197 cycrow 7919
		fileData.pushBack(line, Utils::WString::Number(iLine));
1 cycrow 7920
	}
7921
 
7922
	// assume its a script if no type is set (all old versions are scripts)
7923
	if ( !package )
7924
		package = new CSpkFile();
7925
 
7926
	if ( compression != -1 )
7927
		package->SetDataCompression(compression);
7928
 
197 cycrow 7929
	Utils::WString ftpaddr;
7930
	Utils::WString ftpuser;
7931
	Utils::WString ftppass;
7932
	Utils::WString ftpdir;
7933
	Utils::WString sMainGame;
7934
	Utils::WStringList otherGames;
7935
	Utils::WStringList gameAddons;
127 cycrow 7936
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
7937
	{
197 cycrow 7938
		SGameExe *exe = m_gameExe.game(i);
127 cycrow 7939
		if (!exe->sAddon.empty())
197 cycrow 7940
			gameAddons.pushBack(Utils::WString::Number(i + 1), exe->sAddon);
127 cycrow 7941
	}
98 cycrow 7942
 
1 cycrow 7943
	// now lets read the rest of the day
197 cycrow 7944
	Utils::WStringList listVaribles;
7945
	for (Utils::WStringNode *line = fileData.first(); line; line = fileData.next())
1 cycrow 7946
	{
197 cycrow 7947
		Utils::WString cmd = line->str.token(L":", 1);
7948
		Utils::WString rest = line->str.tokens(L":", 2).removeFirstSpace();
1 cycrow 7949
 
197 cycrow 7950
		if (cmd.Compare(L"Varible") || cmd.Compare(L"Variable"))
131 cycrow 7951
		{
197 cycrow 7952
			Utils::WString s1 = rest.token(L" ", 1);
7953
			Utils::WString s2 = rest.tokens(L" ", 2);
131 cycrow 7954
			if(!listVaribles.changeData(s1, s2))
7955
				listVaribles.pushBack(s1, s2);
7956
		}
1 cycrow 7957
		else
7958
		{
7959
			// replace variables
197 cycrow 7960
			if ( rest.contains(L"$") )
1 cycrow 7961
			{
197 cycrow 7962
				for (Utils::WStringNode *strVar = listVaribles.first(); strVar; strVar = listVaribles.next())
1 cycrow 7963
				{
131 cycrow 7964
					if ( rest.contains(strVar->str) )
7965
						rest = rest.findReplace(strVar->str, strVar->data);
1 cycrow 7966
				}
7967
 
7968
				if ( variables )
7969
				{
197 cycrow 7970
					for (Utils::WStringNode *strVar = variables->first(); strVar; strVar = variables->next())
1 cycrow 7971
					{
131 cycrow 7972
						if ( rest.contains(strVar->str) )
7973
							rest = rest.findReplace(strVar->str, strVar->data);
1 cycrow 7974
					}
7975
				}
7976
			}
7977
 
7978
			//check for the built in varibles
197 cycrow 7979
			if ( rest.contains(L"$ASK") )
1 cycrow 7980
			{
197 cycrow 7981
				Utils::WString replace = L"$ASK";
7982
				Utils::WString result;
1 cycrow 7983
 
7984
				if ( askFunc )
127 cycrow 7985
					result = askFunc(cmd);
1 cycrow 7986
 
197 cycrow 7987
				if ( rest.contains(L"$ASK(") )
1 cycrow 7988
				{
197 cycrow 7989
					replace = rest.tokens(L"$ASK(", 2).token(L")", 1);
98 cycrow 7990
					if ( result.empty() )
1 cycrow 7991
						result = replace;
197 cycrow 7992
					replace = L"$ASK(" + replace + L")";
1 cycrow 7993
				}
7994
 
98 cycrow 7995
				if ( !result.empty() )
7996
					rest = rest.findReplace(replace, result);
1 cycrow 7997
			}
7998
			// todays date
197 cycrow 7999
			if ( rest.contains(L"$DATE") )
1 cycrow 8000
			{
8001
				time_t now;
8002
				time(&now);
8003
				struct tm *timeinfo = localtime(&now);
197 cycrow 8004
				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 8005
				if ( !result.empty() )
197 cycrow 8006
					rest = rest.findReplace(L"$DATE", result);
1 cycrow 8007
			}
8008
			// mydocuments
197 cycrow 8009
			if ( rest.contains(L"$MYDOCUMENTS") )
1 cycrow 8010
			{
127 cycrow 8011
				if ( !m_sMyDoc.empty() )
197 cycrow 8012
					rest = rest.findReplace(L"$MYDOCUMENTS", m_sMyDoc);
1 cycrow 8013
			}
8014
 
8015
			// current path
197 cycrow 8016
			if ( rest.contains(L"$PATH") )
1 cycrow 8017
			{
196 cycrow 8018
				Utils::WString currentDir = CFileIO(filename).dir();
98 cycrow 8019
				if ( !currentDir.empty() )
197 cycrow 8020
					rest = rest.findReplace(L"$PATH", currentDir);
1 cycrow 8021
			}
8022
 
8023
			// now parse the rest of the values
197 cycrow 8024
			if ( cmd.Compare(L"FtpUpload") )
8025
				ftpaddr = rest.token(L" ", 1) + L":" + rest.token(L" ", 2);
8026
			else if ( cmd.Compare(L"FtpUser") )
1 cycrow 8027
				ftpuser = rest;
197 cycrow 8028
			else if ( cmd.Compare(L"FtpPass") )
1 cycrow 8029
				ftppass = rest;
197 cycrow 8030
			else if ( cmd.Compare(L"FtpDir") )
1 cycrow 8031
				ftpdir = rest;
197 cycrow 8032
			else if ( cmd.Compare(L"MultiGames") ) {
8033
				sMainGame = rest.token(L" ", 1);
8034
				otherGames.tokenise(rest.tokens(L" ", 2), L" ");
98 cycrow 8035
			}
197 cycrow 8036
			else if ( !package->loadPackageData(cmd, rest, sMainGame, otherGames, gameAddons, progress))
1 cycrow 8037
			{
8038
				if ( unknownCommands )
131 cycrow 8039
					unknownCommands->pushBack(cmd, rest);
1 cycrow 8040
			}
8041
		}
8042
	}
8043
 
50 cycrow 8044
	if ( package->filename().empty() )
197 cycrow 8045
		package->loadPackageData(L"AutoSave", L"$AUTOSAVE", sMainGame, otherGames, gameAddons, progress);
1 cycrow 8046
 
131 cycrow 8047
	if (package->autoExtraction())
8048
	{
8049
		for (auto itr = package->autoExtraction()->begin(); itr != package->autoExtraction()->end(); itr++)
8050
		{
8051
			unsigned int game = itr->first;
170 cycrow 8052
			for (auto node = package->fileList().Front(); node; node = node->next())
131 cycrow 8053
			{
8054
				C_File *f = node->Data();
8055
				if (f->game() && f->game() != GAME_ALLNEW && !(f->game() & (1 << game)))
8056
					continue;
221 cycrow 8057
				package->extractFile(f, itr->second, game, gameAddons);
131 cycrow 8058
			}
8059
		}
8060
	}
8061
 
8062
	if (package->autoExporter())
8063
	{
8064
		for (auto itr = package->autoExporter()->begin(); itr != package->autoExporter()->end(); itr++)
221 cycrow 8065
			package->saveToArchive(itr->second, itr->first, &m_gameExe);
131 cycrow 8066
	}
8067
 
185 cycrow 8068
	if ( !ftpaddr.empty() )
1 cycrow 8069
	{
185 cycrow 8070
		if ( !ftpuser.empty() )
1 cycrow 8071
		{
185 cycrow 8072
			if ( !ftppass.empty() )
221 cycrow 8073
				ftpaddr = ftpuser + L":" + ftppass + L"@" + ftpaddr;
1 cycrow 8074
			else
221 cycrow 8075
				ftpaddr = ftpuser + L"@" + ftpaddr;
1 cycrow 8076
		}
8077
 
185 cycrow 8078
		if ( !ftpdir.empty() )
1 cycrow 8079
			ftpaddr += ftpdir;
8080
 
221 cycrow 8081
		package->setFtpAddr(ftpaddr);
1 cycrow 8082
	}
8083
 
8084
	return package;
8085
}
8086
 
220 cycrow 8087
Utils::WString CPackages::getLanguageName() const
1 cycrow 8088
{
8089
	return CPackages::ConvertLanguage(m_iLanguage);
8090
}
8091
 
197 cycrow 8092
size_t CPackages::updateFoundPackages(const Utils::WString& dir)
164 cycrow 8093
{
8094
	m_lFoundPackages.MemoryClear();
8095
	if (!m_sCurrentDir.empty())
8096
		return findAllPackages(m_lFoundPackages, dir);
8097
 
8098
	return 0;
8099
}
8100
 
197 cycrow 8101
size_t CPackages::addFoundPackages(const Utils::WString& dir)
164 cycrow 8102
{
8103
	return findPackageDirectories(m_lFoundPackages, dir);
8104
}
8105
 
197 cycrow 8106
int CPackages::findAllPackages(CLinkList<CBaseFile> &packages, const Utils::WString &dir)
133 cycrow 8107
{
8108
	int count = 0;
8109
	if (!dir.empty())
8110
	{
197 cycrow 8111
		count += findPackageDirectories(packages, dir + L"/Addons");
8112
		count += findPackageDirectories(packages, dir + L"/Downloads");
133 cycrow 8113
	}
8114
 
197 cycrow 8115
	count += findPackageDirectories(packages, L"./Addons");
8116
	count += findPackageDirectories(packages, L"./Downloads");
8117
	count += findPackageDirectories(packages, m_sMyDoc + L"/Egosoft/PluginManager/Addons");
8118
	count += findPackageDirectories(packages, m_sMyDoc + L"/Egosoft/PluginManager/Downloads");
162 cycrow 8119
 
133 cycrow 8120
	if (_pCurrentDir)
8121
	{
197 cycrow 8122
		count += findPackageDirectories(packages, _pCurrentDir->dir + L"/Addons");
8123
		count += findPackageDirectories(packages, _pCurrentDir->dir + L"/Downloads");
8124
		count += findPackageDirectories(packages, _pCurrentDir->dir + L"/ExtraContent");
133 cycrow 8125
	}
8126
 
8127
	return count;
8128
}
197 cycrow 8129
int CPackages::findPackageDirectories(CLinkList<CBaseFile> &packages, const Utils::WString &dir)
133 cycrow 8130
{
8131
	CDirIO Dir(dir);
8132
	int count = 0;
196 cycrow 8133
	Utils::WStringList files;
133 cycrow 8134
	if (Dir.dirList(files))
8135
	{
8136
		for (auto itr = files.begin(); itr != files.end(); itr++)
8137
		{
196 cycrow 8138
			Utils::WString d = Dir.file((*itr)->str);
133 cycrow 8139
			if (CDirIO(d).isDir())
221 cycrow 8140
				count += findPackageDirectories(packages, d);
133 cycrow 8141
		}
8142
	}
8143
 
8144
	count += findPackageFiles(packages, dir);
8145
	return count;
8146
}
197 cycrow 8147
int CPackages::findPackageFiles(CLinkList<CBaseFile> &packages, const Utils::WString &dir)
133 cycrow 8148
{
8149
	CDirIO Dir(dir);
8150
	int count = 0;
8151
	for (int type = 0; type < 2; type++)
8152
	{
196 cycrow 8153
		Utils::WStringList files;
133 cycrow 8154
		if (type == 0)
196 cycrow 8155
			Dir.dirList(files, Utils::WString::Null(), L"*.spk");
133 cycrow 8156
		else if(type == 1)
196 cycrow 8157
			Dir.dirList(files, Utils::WString::Null(), L"*.xsp");
133 cycrow 8158
		else
8159
			break;
8160
 
8161
		for(auto itr = files.begin(); itr != files.end(); itr++)
8162
		{
197 cycrow 8163
			Utils::WString f = Dir.file((*itr)->str);
133 cycrow 8164
			int error = 0;
182 cycrow 8165
			CBaseFile *p = this->openPackage(f, &error, 0, SPKREAD_NODATA, READFLAG_NOUNCOMPRESS);
133 cycrow 8166
			if (!p)
8167
				continue;
182 cycrow 8168
			if (p->IsMod() || this->findSpkPackage(p->name(), p->author()))
133 cycrow 8169
			{
8170
				delete p;
8171
				continue;
8172
			}
8173
 
8174
			// check its for the correct game
8175
			if (!p->CheckGameCompatability(this->GetGame()))
8176
			{
8177
				delete p;
8178
				continue;
8179
			}
8180
 
8181
			// check if its already on the list
8182
			bool found = false;
8183
			for (CBaseFile *checkp = packages.First(); checkp; checkp = packages.Next())
8184
			{
8185
				if (p->name().Compare(checkp->name()) && p->author().Compare(checkp->author()))
8186
				{
8187
					found = true;
8188
					break;
8189
				}
8190
			}
8191
 
8192
			if (found)
8193
			{
8194
				delete p;
8195
				continue;
8196
			}
8197
 
170 cycrow 8198
			if (p->icon())
133 cycrow 8199
			{
8200
				bool addedIcon = false;
8201
				p->ReadIconFileToMemory();
203 cycrow 8202
				p->icon()->setFilename(this->tempDirectory().findReplace(L"\\", L"/") + L"/" + p->author() + L"_" + p->name() + L"." + p->iconExt());
170 cycrow 8203
				p->icon()->setFullDir(this->tempDirectory());
8204
				if (p->icon()->UncompressData())
133 cycrow 8205
				{
170 cycrow 8206
					if (p->icon()->writeFilePointer())
133 cycrow 8207
						addedIcon = true;
8208
				}
8209
 
8210
				if (!addedIcon)
213 cycrow 8211
					p->setIcon(NULL, L"");
133 cycrow 8212
			}
8213
 
8214
			// get an advert to display
8215
			if (p->GetFirstFile(FILETYPE_ADVERT))
8216
			{
8217
				bool done = false;
8218
				C_File *f = p->GetFirstFile(FILETYPE_ADVERT);
8219
				if (p->ReadFileToMemory(f))
8220
				{
178 cycrow 8221
					f->setFullDir(this->tempDirectory());
133 cycrow 8222
					if (f->UncompressData())
8223
					{
8224
						if (f->writeFilePointer())
8225
							done = true;
8226
					}
8227
				}
8228
 
8229
				if (!done)
8230
					f->DeleteData();
8231
			}
8232
 
8233
			packages.push_back(p);
8234
			++count;
8235
		}
8236
	}
8237
 
8238
	return count;
8239
}
8240
 
220 cycrow 8241
Utils::WString CPackages::ConvertLanguage(int lang)
1 cycrow 8242
{
8243
	switch ( lang )
8244
	{
8245
		case 44:
220 cycrow 8246
			return L"English";
1 cycrow 8247
		case 49:
220 cycrow 8248
			return L"German";
1 cycrow 8249
		case 7:
220 cycrow 8250
			return L"Russian";
1 cycrow 8251
		case 33:
220 cycrow 8252
			return L"French";
1 cycrow 8253
		case 30:
220 cycrow 8254
			return L"Greek";
1 cycrow 8255
		case 31:
220 cycrow 8256
			return L"Dutch";
1 cycrow 8257
		case 32:
220 cycrow 8258
			return L"Belgian";
1 cycrow 8259
		case 34:
220 cycrow 8260
			return L"Spanish";
1 cycrow 8261
		case 36:
220 cycrow 8262
			return L"Hungarian";
1 cycrow 8263
		case 39:
220 cycrow 8264
			return L"Italian";
1 cycrow 8265
		case 40:
220 cycrow 8266
			return L"Romanian";
1 cycrow 8267
		case 41:
220 cycrow 8268
			return L"Swiss";
1 cycrow 8269
		case 42:
220 cycrow 8270
			return L"Czech";
1 cycrow 8271
		case 43:
220 cycrow 8272
			return L"Austrian";
1 cycrow 8273
		case 45:
220 cycrow 8274
			return L"Danish";
1 cycrow 8275
		case 46:
220 cycrow 8276
			return L"Swedish";
1 cycrow 8277
		case 47:
220 cycrow 8278
			return L"Norweigen";
1 cycrow 8279
		case 48:
220 cycrow 8280
			return L"Polish";
1 cycrow 8281
	}
8282
 
220 cycrow 8283
	return Utils::WString::Number(lang);
1 cycrow 8284
}
8285
 
197 cycrow 8286
bool CPackages::checkAccessRights(const Utils::WString &aDir) const
1 cycrow 8287
{
197 cycrow 8288
	Utils::WString dir = aDir;
182 cycrow 8289
	if (dir.empty())
1 cycrow 8290
		dir = m_sCurrentDir;
8291
 
8292
	// write a file, then read the contents
197 cycrow 8293
	CFileIO File(dir + L"/accessrightscheck.dat");
1 cycrow 8294
 
8295
	// check if file exists and remove it
52 cycrow 8296
	if ( File.exists() )
1 cycrow 8297
	{
8298
		// if we cant remove it, we dont have enough rights
52 cycrow 8299
		if ( !File.remove() )
1 cycrow 8300
			return false;
8301
 
8302
		// if its still there, we dont have enough rights
52 cycrow 8303
		if ( File.exists() )
1 cycrow 8304
			return false;
8305
	}
8306
 
8307
	// now create the file
82 cycrow 8308
	if ( !File.writeString("testing access rights") )
1 cycrow 8309
		return false;
8310
 
8311
	// now check it exists
52 cycrow 8312
	if ( !File.exists() )
1 cycrow 8313
		return false;
8314
 
8315
	// now read the file for the correct contents
197 cycrow 8316
	std::vector<Utils::WString> lines;
173 cycrow 8317
	if (!File.readLines(lines))
1 cycrow 8318
		return false;
8319
 
8320
	// check that one of the lines is correct
173 cycrow 8321
	for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 8322
	{
197 cycrow 8323
		if ( *itr == L"testing access rights" )
1 cycrow 8324
			return true;
8325
	}
8326
 
8327
	return false;
8328
}
8329
 
217 cycrow 8330
size_t CPackages::loadShipData(const Utils::WString &file, Utils::WStringList &list) const
1 cycrow 8331
{
8332
	CFileIO File;
8333
	bool deleteFile = false;
8334
 
8335
	// load from cat file
196 cycrow 8336
	if (CFileIO(file).isFileExtension(L"cat"))
1 cycrow 8337
	{
8338
		CCatFile cat;
217 cycrow 8339
		if (cat.open(file, this->getAddonDir(), CATREAD_CATDECRYPT, false) != CATERR_NONE)
1 cycrow 8340
			return false;
8341
 
213 cycrow 8342
		if (!cat.extractFile(L"types\\TShips.pck", m_sTempDir + L"/tships.txt"))
1 cycrow 8343
			return false;
8344
 
213 cycrow 8345
		File.open(m_sTempDir + L"/tships.txt");
1 cycrow 8346
		deleteFile = true;
8347
	}
8348
	// otherwise its a normal file
196 cycrow 8349
	else if (CFileIO(file).isFileExtension(L"pck"))
1 cycrow 8350
	{
182 cycrow 8351
		C_File f(file);
8352
		if (!f.ReadFromFile())
1 cycrow 8353
			return false;
8354
		f.UnPCKFile();
8355
 
213 cycrow 8356
		f.setFilename(m_sTempDir + L"/tships.txt");
182 cycrow 8357
		if (!f.writeFilePointer())
1 cycrow 8358
			return false;
8359
 
213 cycrow 8360
		File.open(m_sTempDir + L"/tships.txt");
1 cycrow 8361
		deleteFile = true;
8362
	}
8363
	else
182 cycrow 8364
		File.open(file);
1 cycrow 8365
 
182 cycrow 8366
	if (!File.exists())
1 cycrow 8367
		return false;
8368
 
8369
	bool ret = false;
217 cycrow 8370
	std::vector<Utils::WString> lines;
182 cycrow 8371
	if (File.readLines(lines))
1 cycrow 8372
	{
8373
		bool readFirst = false;
182 cycrow 8374
		for (auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 8375
		{
182 cycrow 8376
			if (itr->empty())
1 cycrow 8377
				continue;
217 cycrow 8378
			Utils::WString str = itr->remove('\r').remove(9);
173 cycrow 8379
			str = str.removeFirstSpace();
182 cycrow 8380
			if (str.empty())
1 cycrow 8381
				continue;
182 cycrow 8382
			if (str[0] == '/' || str[0] == '#')
1 cycrow 8383
				continue;
8384
 
182 cycrow 8385
			if (!readFirst)
1 cycrow 8386
				readFirst = true;
8387
			else
8388
			{
217 cycrow 8389
				Utils::WString t = str.tokens(L";", -2);
226 cycrow 8390
				while (t.right(1) == L";")
173 cycrow 8391
					t.truncate((int)t.length() - 1);
182 cycrow 8392
				list.pushBack(t, str);
1 cycrow 8393
			}
8394
		}
8395
 
8396
		ret = true;
8397
	}
8398
 
182 cycrow 8399
	if (deleteFile)
52 cycrow 8400
		File.remove();
1 cycrow 8401
 
8402
	return ret;
8403
}
8404
 
217 cycrow 8405
Utils::WString CPackages::readShipData(const Utils::WString &file, const Utils::WString &id) const
1 cycrow 8406
{
217 cycrow 8407
	Utils::WStringList list;
182 cycrow 8408
	if(!this->loadShipData(file, list))
217 cycrow 8409
		return Utils::WString::Null();
1 cycrow 8410
 
8411
	CShipData data;
182 cycrow 8412
	for(auto itr = list.begin(); itr != list.end(); itr++)
1 cycrow 8413
	{
182 cycrow 8414
		if ((*itr)->str.Compare(id))
8415
			return (*itr)->data;
1 cycrow 8416
	}
8417
 
217 cycrow 8418
	return Utils::WString::Null();
1 cycrow 8419
}
8420
 
197 cycrow 8421
bool CPackages::readTextPage(const Utils::WString &file, Utils::WStringList &list, bool search, int page) const
1 cycrow 8422
{
8423
	CFileIO File;
8424
	bool deleteFile = false;
8425
 
8426
	// read all text files from mod
196 cycrow 8427
	if ( CFileIO(file).isFileExtension(L"cat") )
1 cycrow 8428
	{
8429
		bool done = false;
8430
 
8431
		CCatFile cat;
221 cycrow 8432
		if ( cat.open(file, this->getAddonDir(), CATREAD_CATDECRYPT, false) != CATERR_NONE)
1 cycrow 8433
			return false;
8434
 
8435
		// extract 1 at a time
124 cycrow 8436
		for (unsigned int i = 0; i < cat.GetNumFiles(); i++ )
1 cycrow 8437
		{
8438
			SInCatFile *f = cat.GetFile(i);
197 cycrow 8439
			Utils::WString sF = f->sFile;
1 cycrow 8440
			// is a text file
197 cycrow 8441
			sF = sF.findReplace(L"\\", L"/");
8442
			if ( !sF.token(L"/", 1).Compare(L"t") )
1 cycrow 8443
				continue;
8444
 
196 cycrow 8445
			Utils::WString baseFile = CFileIO(sF).baseName();
1 cycrow 8446
			// check language
8447
			int lang = 0;
197 cycrow 8448
			if ( baseFile.findPos(L"-L") != -1 ) // new language file
182 cycrow 8449
				lang = baseFile.right(3).toInt();
1 cycrow 8450
			else
8451
			{
182 cycrow 8452
				baseFile.truncate((int)baseFile.length() - 4);
8453
				lang = baseFile.toInt();
1 cycrow 8454
			}
8455
 
8456
			if ( lang != m_iLanguage )
8457
				continue;
8458
 
8459
			// now extract and parse
197 cycrow 8460
			if ( cat.extractFile(f->sFile, m_sTempDir + L"/" + CFileIO(f->sFile).baseName() + L".xml"))
1 cycrow 8461
			{
197 cycrow 8462
				if ( this->readTextPage(m_sTempDir + L"/" + CFileIO(f->sFile).baseName() + L".xml", list, search, page))
1 cycrow 8463
					done = true;
8464
			}
8465
		}
8466
 
8467
		return done;
8468
	}
8469
	// otherwise its a normal file
196 cycrow 8470
	else if ( CFileIO(file).isFileExtension(L"pck") )
1 cycrow 8471
	{
182 cycrow 8472
		C_File f(file);
1 cycrow 8473
		if ( !f.ReadFromFile() )
8474
			return false;
8475
		f.UnPCKFile();
8476
 
197 cycrow 8477
		f.setFilename(m_sTempDir + L"/textfile.xml");
129 cycrow 8478
		if ( !f.writeFilePointer() )
1 cycrow 8479
			return false;
8480
 
197 cycrow 8481
		File.open(m_sTempDir + L"/textfile.xml");
1 cycrow 8482
		deleteFile = true;
8483
	}
8484
	else
182 cycrow 8485
		File.open(file);
1 cycrow 8486
 
52 cycrow 8487
	if ( !File.exists() )
1 cycrow 8488
		return false;
8489
 
8490
	// open and read file
197 cycrow 8491
	std::vector<Utils::WString> lines;
173 cycrow 8492
	if(!File.readLines(lines))
1 cycrow 8493
		return false;
8494
 
8495
	bool inPage = false;
173 cycrow 8496
	for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 8497
	{
8498
		// search for page
8499
		if ( !inPage )
8500
		{
197 cycrow 8501
			if (itr->findPos(L"<page") > -1 )
1 cycrow 8502
			{
8503
				// find the page id
197 cycrow 8504
				int pos = itr->findPos(L"\"");
1 cycrow 8505
				if ( pos > -1 )
8506
				{
197 cycrow 8507
					int endpos = itr->findPos(L"\"", pos + 1);
1 cycrow 8508
					if ( endpos > -1 )
8509
					{
197 cycrow 8510
						Utils::WString p = itr->mid(pos + 2, endpos - pos - 1);
173 cycrow 8511
						if ( p.length() > 4 )
8512
							p = p.right(4);
8513
						int checkPage = p.toInt();
1 cycrow 8514
						if ( checkPage == page )
8515
							inPage = true;
8516
					}
8517
				}
8518
			}
8519
 
8520
		}
8521
		// add each id
8522
		else
8523
		{
197 cycrow 8524
			if (itr->findPos(L"</page") > -1 )
1 cycrow 8525
				break;
8526
 
197 cycrow 8527
			if (itr->findPos(L"<t id") > -1 )
1 cycrow 8528
			{
197 cycrow 8529
				int pos = itr->findPos(L"\"");
1 cycrow 8530
				if ( pos > -1 )
8531
				{
197 cycrow 8532
					int endpos = itr->findPos(L"\"", pos + 1);
1 cycrow 8533
					if ( endpos > -1 )
8534
					{
173 cycrow 8535
						int id = itr->mid(pos + 2, endpos - pos - 1).toInt();
213 cycrow 8536
						pos = itr->findPos(L">", endpos);
1 cycrow 8537
						if ( pos > -1 )
8538
						{
8539
							++pos;
197 cycrow 8540
							endpos = itr->findPos(L"</", pos);
1 cycrow 8541
							if ( endpos > -1 )
8542
							{
197 cycrow 8543
								Utils::WString text = itr->mid(pos + 1, endpos - pos);
8544
								while ( text.findPos(L'(') != -1 && text.findPos(L')') != -1 )
1 cycrow 8545
								{
197 cycrow 8546
									int s = text.findPos(L'(');
8547
									text = text.erase(s, text.findPos(L')') - s + 1);
1 cycrow 8548
								}
197 cycrow 8549
								if(!search || !list.contains(Utils::WString::Number(id)))
8550
									list.pushBack(Utils::WString::Number(id), text);
1 cycrow 8551
							}
8552
						}
8553
					}
8554
				}
8555
			}
8556
		}
8557
	}
8558
 
8559
	return true;
8560
}
8561
 
8562
 
197 cycrow 8563
FileType CPackages::adjustFileType(const Utils::WString &file, FileType filetype) const
1 cycrow 8564
{
8565
	CFileIO File(file);
196 cycrow 8566
	Utils::WString dir = File.GetDirIO().topDir();
8567
	Utils::WString basename = File.baseName();
1 cycrow 8568
 
196 cycrow 8569
	Utils::WString ext = File.extension();
160 cycrow 8570
 
1 cycrow 8571
	// mod files
196 cycrow 8572
	if (ext.Compare(L"cat") || ext.Compare(L"dat"))
1 cycrow 8573
		return FILETYPE_MOD;
8574
	// check for text files
196 cycrow 8575
	if ( File.filename().contains(L"-L") && File.filename().left(4).isNumber() )
1 cycrow 8576
		return FILETYPE_TEXT;
196 cycrow 8577
	if ( File.baseName().Compare(L"conversations") )
43 cycrow 8578
		return FILETYPE_TEXT;
196 cycrow 8579
	if ( basename.length() <= 4 && basename.isNumber() && (File.isFileExtension(L"xml") || File.isFileExtension(L"pck")) )
1 cycrow 8580
		return FILETYPE_TEXT;
8581
	// X2/X3 text file
185 cycrow 8582
	if ( basename.length() >= 5 && basename.length() <= 8 && ((int)File.baseName()) )
1 cycrow 8583
		return FILETYPE_TEXT;
8584
	if ( filetype == FILETYPE_TEXT ) // should no longer be anything text
8585
		return FILETYPE_SCRIPT;
196 cycrow 8586
	if ( File.isFileExtension(L"wav") || File.isFileExtension(L"mp3") )
1 cycrow 8587
		return FILETYPE_SOUND;
8588
	return filetype;
8589
}
8590
 
8591
void CPackages::RemoveFailedFiles()
8592
{
197 cycrow 8593
	Utils::WStringList removed;
8594
	for (auto itr = _lNonRemovedFiles.begin(); itr != _lNonRemovedFiles.end(); itr++)
1 cycrow 8595
	{
160 cycrow 8596
		if (CFileIO::Remove((*itr)->str))
8597
			removed.pushBack((*itr)->str);
1 cycrow 8598
	}
160 cycrow 8599
	for (auto itr = removed.begin(); itr != removed.end(); itr++)
197 cycrow 8600
		_lNonRemovedFiles.remove((*itr)->str);
1 cycrow 8601
}
8602
 
221 cycrow 8603
CXspFile *CPackages::extractShip(const Utils::WString &sCatFile, const Utils::WString &sId, CProgressInfo *progress)
1 cycrow 8604
{
35 cycrow 8605
	CVirtualFileSystem *pVfs = new CVirtualFileSystem();
8606
	if ( !pVfs->addMod(sCatFile) ) {
8607
		delete pVfs;
1 cycrow 8608
		return NULL;
35 cycrow 8609
	}
1 cycrow 8610
 
8611
	CXspFile *newShip = new CXspFile;
35 cycrow 8612
	if ( !newShip->extractShip(pVfs, sId, progress) ) {
1 cycrow 8613
		delete newShip;
35 cycrow 8614
		newShip = NULL;
1 cycrow 8615
	}
8616
 
35 cycrow 8617
	delete pVfs;
8618
 
1 cycrow 8619
	return newShip;
8620
}
8621
 
197 cycrow 8622
void CPackages::getMergedFiles(Utils::WStringList &list, CCatFile *cat1, CCatFile *cat2) const
1 cycrow 8623
{
8624
	// first add all files from the "primary" mod
124 cycrow 8625
	for (auto itr = cat1->GetFiles()->cbegin(); itr != cat1->GetFiles()->cend(); itr++)
197 cycrow 8626
		list.pushBack((*itr)->sFile.findReplace(L"\\", L"/"), L"1");
1 cycrow 8627
 
8628
	// now add the ones from the secondary
124 cycrow 8629
	for (auto itr = cat2->GetFiles()->cbegin(); itr != cat2->GetFiles()->cend(); itr++)
1 cycrow 8630
	{
197 cycrow 8631
		Utils::WString sFile = (*itr)->sFile.findReplace(L"\\", L"/");
1 cycrow 8632
		// if its found on the 2nd list, dont add, just adjust the type
197 cycrow 8633
		if(!list.changeData(sFile, L"-1"))
8634
			list.pushBack(sFile, L"2");
1 cycrow 8635
	}
8636
}
8637
 
197 cycrow 8638
bool CPackages::canWeMerge(const Utils::WString &file) const
1 cycrow 8639
{
8640
	return CModDiff::CanBeDiffed(file);
8641
}
8642
 
197 cycrow 8643
bool CPackages::needToMerge(const Utils::WString &file) const
1 cycrow 8644
{
197 cycrow 8645
	Utils::WString firstDir = file.token(L"/", 1);
8646
	if ( firstDir.Compare(L"t") )
1 cycrow 8647
		return true;
197 cycrow 8648
	if ( firstDir.Compare(L"types") )
1 cycrow 8649
		return true;
197 cycrow 8650
	if ( firstDir.Compare(L"maps") )
1 cycrow 8651
		return true;
8652
 
8653
	return false;
8654
}
8655
 
197 cycrow 8656
bool CPackages::mergeMods(CCatFile *mod1, CCatFile *mod2, const Utils::WString &outFile, Utils::WStringList *cantMerge) const
1 cycrow 8657
{
8658
	CCatFile newCat;
182 cycrow 8659
	if ( newCat.open(outFile, this->getAddonDir()) != CATERR_CREATED )
1 cycrow 8660
		return false;
8661
 
197 cycrow 8662
	Utils::WStringList list;
124 cycrow 8663
	this->getMergedFiles(list, mod1, mod2);
8664
	if (list.empty())
8665
		return false;
8666
 
1 cycrow 8667
	// add all the files to the new mod first
197 cycrow 8668
	Utils::WStringList conflicts;
124 cycrow 8669
	for(auto itr = list.begin(); itr != list.end(); itr++)
8670
	{		
8671
		int status = (*itr)->data.toInt();
1 cycrow 8672
		if ( status == 1 )
8673
		{
181 cycrow 8674
			if ( !newCat.writeFromCat(mod1, (*itr)->str) )
1 cycrow 8675
			{
8676
				if ( cantMerge )
197 cycrow 8677
					cantMerge->pushBack((*itr)->str, L"1");
1 cycrow 8678
			}
8679
		}
8680
		else if ( status == 2 )
8681
		{
181 cycrow 8682
			if ( !newCat.writeFromCat(mod2, (*itr)->str) )
1 cycrow 8683
			{
8684
				if ( cantMerge )
197 cycrow 8685
					cantMerge->pushBack((*itr)->str, L"2");
1 cycrow 8686
			}
8687
		}
8688
		else if ( status == -1 )
8689
		{
182 cycrow 8690
			if ( this->needToMerge((*itr)->str) )
1 cycrow 8691
			{
182 cycrow 8692
				if ( this->canWeMerge((*itr)->str) )
124 cycrow 8693
					conflicts.pushBack((*itr)->str);
1 cycrow 8694
				else if ( cantMerge )
197 cycrow 8695
					cantMerge->pushBack((*itr)->str, L"-1");
1 cycrow 8696
			}
8697
			else
8698
			{
181 cycrow 8699
				if ( !newCat.writeFromCat(mod1, (*itr)->str) )
1 cycrow 8700
				{
8701
					if ( cantMerge )
197 cycrow 8702
						cantMerge->pushBack((*itr)->str, L"1");
1 cycrow 8703
				}
8704
			}
8705
		}
8706
	}
8707
 
8708
	/* 
8709
		Merging Files
8710
 
8711
		* Text Files: Join all text entries into a single file (excluding page 17)
8712
		* Weapons: TBullets and TLaser (grab matching entrys from text files and adjust ids)
8713
	*/
8714
	// new merge the conflicting files
8715
	// first the text files
222 cycrow 8716
//	Utils::WStringList *text = this->MergeTextFiles(conflicts, mod1, mod2);
1 cycrow 8717
//	delete text;
8718
 
8719
	// write the cat file when we're done
8720
	if ( !newCat.WriteCatFile() )
8721
		return false;
8722
 
8723
	return true;
8724
}
8725
 
8726
/**
8727
 * Gets the file list from a mod that might have compatability problems
8728
 *
8729
 * This includes all types and text files
8730
 *
8731
 * Returns true if it finds any files
8732
 */
197 cycrow 8733
bool CPackages::getModCompatabilityList(C_File *file, Utils::WStringList *list) const
1 cycrow 8734
{
8735
	// not a valid file
8736
	if ( !file ) return false;
8737
	if ( file->GetFileType() != FILETYPE_MOD ) return false;
197 cycrow 8738
	if ( !file->fileExt().Compare(L"cat") ) return false;
1 cycrow 8739
 
8740
	// we need to read the file list for the mod
8741
	CCatFile cat;
221 cycrow 8742
	if ( cat.open(file->filePointer(), this->getAddonDir(), CATREAD_JUSTCONTENTS, false) == CATERR_NONE)
1 cycrow 8743
	{
124 cycrow 8744
		for (unsigned int i = 0; i < cat.GetNumFiles(); i++ )
1 cycrow 8745
		{
8746
			SInCatFile *f = cat.GetFile(i);
197 cycrow 8747
			Utils::WString filename = f->sFile;
8748
			filename = filename.findReplace(L"\\", L"/");
50 cycrow 8749
			bool found = false;
178 cycrow 8750
			//TODO: rework this
197 cycrow 8751
			if ( filename.left(2).Compare(L"t/") || filename.left(6).Compare(L"types/") )
50 cycrow 8752
				found = true;
197 cycrow 8753
			else if (filename.left(8).Compare(L"addon/t/") || filename.left(12).Compare(L"addon/types/"))
50 cycrow 8754
				found = true;
197 cycrow 8755
			else if (filename.left(9).Compare(L"addon2/t/") || filename.left(13).Compare(L"addon2/types/"))
178 cycrow 8756
				found = true;
50 cycrow 8757
 
8758
			if ( found ) {
1 cycrow 8759
				if ( list )
197 cycrow 8760
					list->pushBack(filename, Utils::WString::Number(f->lSize));
1 cycrow 8761
				else
8762
					return true;
8763
			}
8764
		}
8765
	}
8766
 
178 cycrow 8767
	if ( list && !list->empty() )
1 cycrow 8768
		return true;
8769
 
8770
	return false;
8771
}
8772
 
8773
/**
8774
 * Gets the files that are not compatable with each other
8775
 *
8776
 * Returns true if theres any files that are not compatable
8777
 *
8778
 * If list is specified, fills up with all files that were found
8779
 */
197 cycrow 8780
bool CPackages::checkCompatabilityBetweenModFiles(C_File *from, C_File *to, Utils::WStringList *list) const
1 cycrow 8781
{
8782
	// not a valid file
8783
	if ( !from || !to ) return false;
8784
	if ( from->GetFileType() != FILETYPE_MOD ) return false;
8785
	if ( to->GetFileType() != FILETYPE_MOD ) return false;
197 cycrow 8786
	if (!from->fileExt().Compare(L"cat")) return false;
8787
	if (!to->fileExt().Compare(L"cat")) return false;
1 cycrow 8788
 
8789
	// get file lists from each file
197 cycrow 8790
	Utils::WStringList fromList;
178 cycrow 8791
	if (getModCompatabilityList(from, &fromList))
1 cycrow 8792
	{
197 cycrow 8793
		Utils::WStringList toList;
178 cycrow 8794
		if (getModCompatabilityList(to, &toList))
1 cycrow 8795
		{
8796
			// both have files we need to check, compare them
178 cycrow 8797
			for(auto itr = fromList.begin(); itr != fromList.end(); itr++)
1 cycrow 8798
			{
197 cycrow 8799
				Utils::WString fromFile = (*itr)->str;
8800
				fromFile = fromFile.findReplace(L"\\", L"/");
8801
				fromFile = fromFile.findReplace(L"//", L"/");
184 cycrow 8802
				for (auto toItr = toList.begin(); toItr != toList.end(); toItr++)
1 cycrow 8803
				{
197 cycrow 8804
					Utils::WString toFile = (*toItr)->str;
8805
					toFile = toFile.findReplace(L"\\", L"/");
8806
					toFile = toFile.findReplace(L"//", L"/");
1 cycrow 8807
					if ( fromFile.Compare(toFile) )
8808
					{
8809
						if ( list )
197 cycrow 8810
							list->pushBack(from->filename() + L"::" + fromFile, to->filename() + L"::" + toFile);
1 cycrow 8811
						else
8812
							return true;
8813
					}
8814
				}
8815
			}
8816
		}
8817
	}
8818
 
182 cycrow 8819
	if ( list && !list->empty() )
1 cycrow 8820
		return true;
8821
 
8822
	return false;
8823
}
8824
 
197 cycrow 8825
bool CPackages::checkCompatabilityBetweenMods(CBaseFile *from, CBaseFile *to, Utils::WStringList *list) const
1 cycrow 8826
{
8827
	if ( !from || !to ) return false;
8828
	if ( !from->IsEnabled() || !to->IsEnabled() ) return false;
8829
	if ( !from->AnyFileType(FILETYPE_MOD) ) return false;
8830
	if ( !to->AnyFileType(FILETYPE_MOD) ) return false;
8831
 
8832
	if ( from == to ) return false; // cant have incompatabilities to itself
8833
 
184 cycrow 8834
	// check if one is a depencacy of the other
203 cycrow 8835
	if (from->isPackageNeeded(to->name(), to->author())) return false;
8836
	if (to->isPackageNeeded(from->name(), from->author())) return false;
184 cycrow 8837
	// check if one is directly connected
8838
	if (from->type() == BaseFileType::TYPE_SPK)
8839
	{
8840
		CSpkFile* fromSpk = dynamic_cast<CSpkFile*>(from);
8841
		if (fromSpk->isAnotherMod())
8842
		{
214 cycrow 8843
			if (fromSpk->otherName().Compare(to->name()) && fromSpk->otherAuthor().Compare(to->author()))
184 cycrow 8844
				return false;
8845
		}
8846
	}
8847
	if (to->type() == BaseFileType::TYPE_SPK)
8848
	{
8849
		CSpkFile* toSpk = dynamic_cast<CSpkFile*>(to);
8850
		if (toSpk->isAnotherMod())
8851
		{
214 cycrow 8852
			if (toSpk->otherName().Compare(from->name()) && toSpk->otherAuthor().Compare(from->author()))
184 cycrow 8853
				return false;
8854
		}
8855
	}
8856
 
1 cycrow 8857
	int count = 0;
8858
	for ( C_File *f = from->GetFirstFile(FILETYPE_MOD); f; f = from->GetNextFile(f) )
8859
	{
8860
		if ( !f->IsFakePatch() ) continue;
197 cycrow 8861
		if ( f->fileExt().Compare(L"dat") ) continue;
1 cycrow 8862
 
8863
		for ( C_File *compareFile = to->GetFirstFile(FILETYPE_MOD); compareFile; compareFile = to->GetNextFile(compareFile) )
8864
		{
8865
			if ( compareFile == f ) continue; // same file we're checking against
8866
			if ( !compareFile->IsFakePatch() ) continue;
197 cycrow 8867
			if ( compareFile->fileExt().Compare(L"dat") ) continue;
1 cycrow 8868
 
8869
			// now we have to files to compare
182 cycrow 8870
			if (checkCompatabilityBetweenModFiles(f, compareFile, list))
1 cycrow 8871
				++count;
8872
		}
8873
	}
8874
 
8875
	if ( count )
8876
		return true;
8877
 
8878
	return false;
8879
}
8880
 
197 cycrow 8881
int CPackages::checkCompatabilityAgainstPackages(CBaseFile *newFile, Utils::WStringList *list, CLinkList<CBaseFile> *packages) const
1 cycrow 8882
{
8883
	if ( !newFile->IsEnabled() ) return 0;
8884
	if ( !newFile->AnyFileType(FILETYPE_MOD) ) return 0;
8885
 
8886
	// we need to extract all mod files
8887
	for ( CListNode<C_File> *fNode = newFile->GetFileList()->Front(); fNode; fNode = fNode->next() )
8888
	{
8889
		C_File *f = fNode->Data();
8890
		if ( f->GetFileType() != FILETYPE_MOD ) continue;
8891
		if ( !f->IsFakePatch() ) continue;
197 cycrow 8892
		if (!f->checkFileExt(L"cat")) continue;
1 cycrow 8893
 
221 cycrow 8894
		if (newFile->extractFile(f, m_sTempDir) )
175 cycrow 8895
			f->setFullDir(m_sTempDir);
1 cycrow 8896
	}
8897
 
8898
	// compare mod files against all installed packages
8899
	int count = 0;
8900
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
8901
	{
8902
		if ( !node->Data() ) continue;
8903
		CBaseFile *p = node->Data();
8904
		if ( !p->IsEnabled() ) continue;
8905
		if ( !p->AnyFileType(FILETYPE_MOD) ) continue;
8906
 
182 cycrow 8907
		if ( this->isSamePackage(p, newFile) ) continue; // dont include self
1 cycrow 8908
 
182 cycrow 8909
		if (checkCompatabilityBetweenMods(newFile, p, list))
1 cycrow 8910
		{
8911
			++count;
8912
			if ( packages && !packages->FindData(p) )
8913
				packages->push_back(p);
8914
		}
8915
	}
8916
 
8917
	for ( CListNode<C_File> *fNode = newFile->GetFileList()->Front(); fNode; fNode = fNode->next() )
8918
	{
8919
		C_File *f = fNode->Data();
129 cycrow 8920
		CFileIO::Remove(f->filePointer());
197 cycrow 8921
		f->setFullDir(L"");
1 cycrow 8922
	}
8923
 
8924
	return count;
8925
}
8926
 
182 cycrow 8927
bool CPackages::isSamePackage(CBaseFile *p1, CBaseFile *p2) const
1 cycrow 8928
{
8929
	if ( !p1 || !p2 ) return false;
8930
	if ( p1 == p2 ) return true;
8931
 
50 cycrow 8932
	if ( p1->name().Compare(p2->name()) && p1->author().Compare(p2->author()) )
1 cycrow 8933
		return true;
8934
	return false;
8935
}
8936
 
203 cycrow 8937
void CPackages::applyFakePatchOrder(const Utils::WStringList &list)
1 cycrow 8938
{
197 cycrow 8939
	_lFakePatchOrder.clear();
203 cycrow 8940
	for(auto itr = list.begin(); itr != list.end(); itr++)
197 cycrow 8941
		_lFakePatchOrder.pushBack((*itr)->str, (*itr)->data);
1 cycrow 8942
}
8943
 
8944
SAvailablePackage *CPackages::CreateAvailablePackageData(CBaseFile *package)
8945
{
8946
	if ( !package ) return NULL;
8947
 
8948
	SAvailablePackage *p = new SAvailablePackage;
8949
 
8950
	for ( CListNode<SGameCompat> *node = package->GetGameCompatabilityList()->Front(); node; node = node->next() ) {
8951
		SGameCompat *gc = new SGameCompat;
8952
		gc->iGame = node->Data()->iGame;
8953
		gc->iVersion = node->Data()->iVersion;
8954
		gc->sVersion = node->Data()->sVersion;
8955
		p->lGames.push_back(gc);
8956
	}
8957
	p->bSigned = package->IsSigned();
46 cycrow 8958
	p->iChanging = package->gameChanging();
8959
	p->iEase = package->easeOfUse();
48 cycrow 8960
	p->iPluginType = package->pluginType();
46 cycrow 8961
	p->iRec = package->recommended();
1 cycrow 8962
	p->iScriptType = -1;
8963
	if ( package->GetType() == TYPE_XSP )
8964
		p->iType = PACKAGETYPE_SHIP;
8965
	else if ( package->IsMod() )
8966
		p->iType = PACKAGETYPE_MOD;
8967
	else 
8968
	{
8969
		p->iType = ((CSpkFile *)package)->GetPackageType();
8970
		p->iScriptType = ((CSpkFile *)package)->GetScriptType();
8971
	}
203 cycrow 8972
	p->sAuthor = package->author();
206 cycrow 8973
	p->sDesc = package->description().findReplace(L"\n", L"::newline::");
203 cycrow 8974
	p->sName = package->name();
204 cycrow 8975
	p->sUpdated = package->creationDate();
8976
	p->sVersion = package->version();
197 cycrow 8977
	p->sFilename = CFileIO(package->filename()).filename();
1 cycrow 8978
 
8979
	return p;
8980
}
8981
 
197 cycrow 8982
Utils::WString CPackages::FormatAvailablePackageData(CBaseFile *package)
1 cycrow 8983
{
8984
	SAvailablePackage *p = CPackages::CreateAvailablePackageData(package);
197 cycrow 8985
	Utils::WString ret = CPackages::FormatAvailablePackageData(p);
1 cycrow 8986
	delete p;
8987
	return ret;
8988
}
8989
 
197 cycrow 8990
Utils::WString CPackages::FormatAvailablePackageData(SAvailablePackage *package)
1 cycrow 8991
{
197 cycrow 8992
	Utils::WString ret = (long)package->iType;
1 cycrow 8993
 
197 cycrow 8994
	Utils::WString gameCompat;
1 cycrow 8995
	for ( CListNode<SGameCompat> *node = package->lGames.Front(); node; node = node->next() ) {
126 cycrow 8996
		if ( !gameCompat.empty() )
197 cycrow 8997
			gameCompat += L"!";
8998
		gameCompat += Utils::WString::Number(node->Data()->iGame);
1 cycrow 8999
	}
9000
 
126 cycrow 9001
	if ( gameCompat.empty() )
197 cycrow 9002
		gameCompat = L"0";
1 cycrow 9003
 
197 cycrow 9004
	ret = ret.addToken(L"::", gameCompat);
9005
	ret = ret.addToken(L"::", package->sName);
9006
	ret = ret.addToken(L"::", package->sAuthor);
9007
	ret = ret.addToken(L"::", package->sVersion);
9008
	ret = ret.addToken(L"::", package->sUpdated);
9009
	ret = ret.addToken(L"::", package->sFilename);
9010
	ret = ret.addToken(L"::", Utils::WString::Number(package->iEase));
9011
	ret = ret.addToken(L"::", Utils::WString::Number(package->iChanging));
9012
	ret = ret.addToken(L"::", Utils::WString::Number(package->iRec));
9013
	ret = ret.addToken(L"::", Utils::WString::Number(package->iPluginType));
9014
	ret = ret.addToken(L"::", Utils::WString::Number(package->iScriptType));
9015
	ret = ret.addToken(L"::", (package->bSigned) ? L"1" : L"0");
9016
	ret = ret.addToken(L"::", package->sDesc);
1 cycrow 9017
 
9018
	return ret;
9019
}
9020
 
197 cycrow 9021
void CPackages::parseAvailablePackage(const Utils::WString &str, const Utils::WString &webaddress)
1 cycrow 9022
{
9023
	// first check game
197 cycrow 9024
	std::vector<Utils::WString> tok;
9025
	if (!str.tokenise(L"::", tok))
9026
		return;
100 cycrow 9027
	// invalid number of entries?
205 cycrow 9028
	if (tok.size() < 7 ) return;
1 cycrow 9029
 
9030
	SAvailablePackage *p = new SAvailablePackage;
100 cycrow 9031
	p->iType = tok[0].toLong();
1 cycrow 9032
	p->bSigned = false;
9033
 
100 cycrow 9034
	// theres multiple games, so we need to split it
9035
	if ( m_iGame ) {
197 cycrow 9036
		Utils::WString sGame = tok[1];
9037
		if ( sGame.contains(L"!") ) {
9038
			for(int i = 1; i <= sGame.countToken(L"!"); i++) {
1 cycrow 9039
				SGameCompat *gc = new SGameCompat;
9040
				gc->iVersion = 0;
197 cycrow 9041
				gc->iGame = sGame.token(L"!", i).toLong();
1 cycrow 9042
				p->lGames.push_back(gc);
9043
			}
9044
		}
100 cycrow 9045
		else {
9046
			SGameCompat *gc = new SGameCompat;
9047
			gc->iVersion = 0;
9048
			gc->iGame = sGame.toLong();
9049
			p->lGames.push_back(gc);
9050
		}
1 cycrow 9051
	}
100 cycrow 9052
 
1 cycrow 9053
	p->sName = tok[2];
9054
	p->sAuthor = tok[3];
9055
	p->sVersion = tok[4];
9056
	p->sUpdated = tok[5];
9057
	p->sFilename = tok[6];
9058
 
161 cycrow 9059
	if ( !webaddress.empty() )
197 cycrow 9060
		p->sFilename = webaddress + L"/" + p->sFilename;
1 cycrow 9061
 
9062
	p->iChanging = p->iEase = p->iPluginType = p->iRec = p->iScriptType = -1;
9063
 
100 cycrow 9064
	// check if we have the extra values
205 cycrow 9065
	if (tok.size() >= 12 )
1 cycrow 9066
	{
100 cycrow 9067
		p->iEase = tok[7].toLong();
9068
		p->iChanging = tok[8].toLong();
9069
		p->iRec = tok[9].toLong();
9070
		p->iPluginType = tok[10].toLong();
9071
		p->iScriptType = tok[11].toLong();
205 cycrow 9072
		if (tok.size()> 13 ) {
9073
			p->sDesc = tok[13];
9074
			p->bSigned = tok[12].toBool();
1 cycrow 9075
		}
205 cycrow 9076
		else
9077
			p->sDesc = tok[12];
1 cycrow 9078
	}
205 cycrow 9079
	else if (tok.size() > 7 )
100 cycrow 9080
		p->sDesc = tok[8];
1 cycrow 9081
 
126 cycrow 9082
	if ( !p->sDesc.empty() )
197 cycrow 9083
		p->sDesc = p->sDesc.findReplace(L"::newline::", L"\\n");
1 cycrow 9084
 
161 cycrow 9085
	addAvailablePackage(p);
1 cycrow 9086
}
9087
 
197 cycrow 9088
const SAvailablePackage* CPackages::findAvailablePackage(const Utils::WString& filename) const
1 cycrow 9089
{
161 cycrow 9090
	for (CListNode<SAvailablePackage>* node = m_lAvailablePackages.Front(); node; node = node->next())
1 cycrow 9091
	{
161 cycrow 9092
		if (node->Data()->sFilename.Compare(filename))
1 cycrow 9093
			return node->Data();
9094
	}
9095
	return NULL;
9096
}
197 cycrow 9097
const SAvailablePackage* CPackages::findAvailablePackage(const Utils::WString& name, const Utils::WString& author) const
161 cycrow 9098
{
9099
	for (CListNode<SAvailablePackage>* node = m_lAvailablePackages.Front(); node; node = node->next())
9100
	{
9101
		if (node->Data()->sName.Compare(name) && node->Data()->sAuthor.Compare(author))
9102
			return node->Data();
9103
	}
9104
	return NULL;
9105
}
1 cycrow 9106
 
197 cycrow 9107
CBaseFile* CPackages::findFoundPackage(const Utils::WString& name, const Utils::WString& author) const
164 cycrow 9108
{
9109
	for (CListNode<CBaseFile>* node = m_lFoundPackages.Front(); node; node = node->next())
9110
	{
203 cycrow 9111
		if (node->Data()->name().Compare(name) && node->Data()->author().Compare(author))
164 cycrow 9112
			return node->Data();
9113
	}
9114
	return NULL;
9115
}
9116
 
9117
 
161 cycrow 9118
bool CPackages::addAvailablePackage(SAvailablePackage *package)	
1 cycrow 9119
{ 
9120
	if ( !package->lGames.empty() ) {
9121
		bool found = false;
9122
		for ( CListNode<SGameCompat> *node = package->lGames.Front(); node; node = node->next() ) {
9123
			if ( !node->Data()->iGame || node->Data()->iGame == m_iGame ) {
9124
				found = true;
9125
				break;
9126
			}
9127
		}
9128
 
9129
		if ( !found )
9130
			return false;
9131
	}
9132
 
164 cycrow 9133
	// check if a matching package is already found
9134
	const CBaseFile* bf = findFoundPackage(package->sName, package->sAuthor);
9135
	if (bf)
9136
	{
204 cycrow 9137
		if (bf->version().compareVersion(package->sVersion) <= 0)
164 cycrow 9138
			return true;		
9139
	}
9140
 
161 cycrow 9141
	const SAvailablePackage *p = findAvailablePackage(package->sFilename);
9142
	if(p)
9143
	{
9144
		if (p->sVersion.compareVersion(package->sVersion) <= 0)
9145
			return true;
1 cycrow 9146
		m_lAvailablePackages.remove(p);
161 cycrow 9147
	}
9148
 
9149
	p = findAvailablePackage(package->sName, package->sAuthor);
9150
	if (p)
9151
	{
9152
		if (p->sVersion.compareVersion(package->sVersion) <= 0)
9153
			return true;
9154
		m_lAvailablePackages.remove(p);
9155
	}
9156
 
1 cycrow 9157
	m_lAvailablePackages.push_back(package); 
166 cycrow 9158
	saveAvailablePackages();
1 cycrow 9159
	return true;
9160
}
9161
 
166 cycrow 9162
void CPackages::saveAvailablePackages()
9163
{
197 cycrow 9164
	std::vector<Utils::WString> lines;
166 cycrow 9165
 
197 cycrow 9166
	lines.push_back(L"Version;1;" + Utils::WString::Number(m_lAvailablePackages.size()));
166 cycrow 9167
 
9168
	for (auto itr = m_lAvailablePackages.First(); itr; itr = m_lAvailablePackages.Next())
9169
	{
197 cycrow 9170
		Utils::WString l = L"Package";
9171
		l += L";" + itr->sName.findReplace(L";", L":&COL&:");
9172
		l += L";" + itr->sAuthor.findReplace(L";", L":&COL&:");
9173
		l += L";" + itr->sVersion.findReplace(L";", L":&COL&:");
9174
		l += L";" + itr->sFilename;
9175
		l += L";" + itr->sDesc.findReplace(L";", L":&COL&:");
9176
		l += L";" + itr->sUpdated;
166 cycrow 9177
 
197 cycrow 9178
		l += L";" + Utils::WString::Number(itr->lGames.size());
166 cycrow 9179
 
9180
		for (auto g = itr->lGames.First(); g; g = itr->lGames.Next())
197 cycrow 9181
			l += L";" + Utils::WString::Number(g->iGame) + L";" + Utils::WString::Number(g->iVersion) + L";" + g->sVersion;
166 cycrow 9182
 
197 cycrow 9183
		l += L";" + Utils::WString::Number(itr->iType);
9184
		l += L";" + Utils::WString::Number(itr->iPluginType);
9185
		l += L";" + Utils::WString::Number(itr->iScriptType);
9186
		l += L";" + Utils::WString::Number(itr->iChanging);
9187
		l += L";" + Utils::WString::Number(itr->iEase);
9188
		l += L";" + Utils::WString::Number(itr->iRec);
9189
		l += itr->bSigned ? L";1" : L";0";
166 cycrow 9190
 
9191
		lines.push_back(l);
9192
	}
9193
 
9194
	// write out the file
197 cycrow 9195
	CDirIO dir(m_sCurrentDir + L"/PluginManager");
166 cycrow 9196
	if (!dir.exists())
9197
		dir.create();
197 cycrow 9198
	CFileIO file(dir.file(L"packagecache.new"));
9199
	if (file.writeFile(lines))
166 cycrow 9200
	{
197 cycrow 9201
		if (CFileIO::Exists(dir.file(L"packagecache.new")))
166 cycrow 9202
		{
197 cycrow 9203
			if (CFileIO::Exists(dir.file(L"packagecache.dat")))
9204
				CFileIO::Remove(dir.file(L"packagecache.dat"));
9205
			file.Rename(dir.file(L"packagecache.dat"));
166 cycrow 9206
		}
9207
	}
9208
}
9209
 
9210
void CPackages::readAvailablePackages()
9211
{
9212
	m_lAvailablePackages.MemoryClear();
9213
 
197 cycrow 9214
	CDirIO dir(m_sCurrentDir + L"/PluginManager");
9215
	CFileIO file(dir.file(L"packagecache.dat"));
166 cycrow 9216
 
9217
	if (file.exists())
9218
	{
9219
		size_t version = 0;
9220
		size_t count = 0;
197 cycrow 9221
		std::vector<Utils::WString> lines;
166 cycrow 9222
		if (file.readLines(lines))
9223
		{
9224
			for (auto itr = lines.begin(); itr != lines.end(); itr++)
9225
			{
197 cycrow 9226
				Utils::WString cmd = itr->token(L";", 1);
9227
				if (cmd == L"Version")
166 cycrow 9228
				{
197 cycrow 9229
					version = itr->token(L";", 2).toInt();
9230
					count = itr->token(L";", 3).toInt();
166 cycrow 9231
				}
197 cycrow 9232
				else if (cmd == L"Package")
166 cycrow 9233
				{
9234
					int max = 0;
197 cycrow 9235
					std::vector<Utils::WString> str;
9236
					itr->tokenise(L";", str);
166 cycrow 9237
 
9238
					SAvailablePackage* package = new SAvailablePackage;
9239
					int pos = 1;
197 cycrow 9240
					package->sName = str[pos++].findReplace(L":&COL&:", L";");
9241
					package->sAuthor = str[pos++].findReplace(L":&COL&:", L";");
9242
					package->sVersion = str[pos++].findReplace(L":&COL&:", L";");
9243
					package->sFilename = str[pos++].findReplace(L":&COL&:", L";");
9244
					package->sDesc = str[pos++].findReplace(L":&COL&:", L";");
9245
					package->sUpdated = str[pos++].findReplace(L":&COL&:", L";");
166 cycrow 9246
 
9247
					size_t games = str[pos++].toInt();
9248
					for (size_t i = 0; i < games; i++)
9249
					{
9250
						SGameCompat* g = new SGameCompat;
9251
						g->iGame = str[pos++].toInt();
9252
						g->iVersion = str[pos++].toInt();
9253
						g->sVersion = str[pos++];
9254
						package->lGames.push_back(g);
9255
					}
9256
 
9257
					package->iType = str[pos++].toInt();
9258
					package->iPluginType = str[pos++].toInt();
9259
					package->iScriptType = str[pos++].toInt();
9260
					package->iChanging = str[pos++].toInt();
9261
					package->iEase = str[pos++].toInt();
9262
					package->iRec = str[pos++].toInt();
197 cycrow 9263
					package->bSigned = (str[pos] == L"1");
166 cycrow 9264
 
9265
					addAvailablePackage(package);
9266
				}
9267
			}
9268
		}
9269
	}
9270
}
9271
 
1 cycrow 9272
bool CPackages::AnyAvailablePackages(int type)
9273
{
9274
	if ( type == -1 ) return !m_lAvailablePackages.empty();
9275
 
9276
	for ( CListNode<SAvailablePackage> *node = m_lAvailablePackages.Front(); node; node = node->next() )
9277
	{
9278
		if ( node->Data()->iType == type )
9279
			return true;
9280
	}
9281
 
9282
	return false;
9283
}
9284
 
205 cycrow 9285
int CPackages::findAllServers(Utils::WStringList *list) const
1 cycrow 9286
{
9287
	for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )
9288
	{
162 cycrow 9289
		if (!node->Data()->webAddress().empty())
1 cycrow 9290
		{
162 cycrow 9291
			if(!list->contains(node->Data()->webAddress()))
9292
				list->pushBack(node->Data()->webAddress());
1 cycrow 9293
		}
162 cycrow 9294
		if ( node->Data()->anyWebMirrors() )
9295
		{
170 cycrow 9296
			auto &l = node->Data()->webMirrors();
9297
			for (auto itr = l.begin(); itr != l.end(); itr++)
162 cycrow 9298
			{
9299
				if(!list->contains((*itr)->str))
9300
					list->pushBack((*itr)->str);
9301
			}
9302
		}
1 cycrow 9303
	}
9304
 
197 cycrow 9305
	CFileIO File(L"data\\web");
76 cycrow 9306
 
9307
	if ( File.startRead() ) {
9308
		while(!File.atEnd()) {
205 cycrow 9309
			Utils::WString line = File.readEndOfLine();
9310
			line.removeChar(L"\n\r\t ");
162 cycrow 9311
			if (!line.empty())
9312
			{
9313
				if(!list->contains(line))
9314
					list->pushBack(line);
9315
			}
76 cycrow 9316
		}
9317
		File.close();
9318
	}
9319
 
205 cycrow 9320
	if (!list->contains(L"http://xpluginmanager.co.uk/tcscripts"))
9321
		list->pushBack(L"http://xpluginmanager.co.uk/tcscripts");
9322
	if (!list->contains(L"http://xpluginmanager.co.uk/acscripts"))
9323
		list->pushBack(L"http://xpluginmanager.co.uk/apscripts");
9324
	if (!list->contains(L"http://xpluginmanager.co.uk/fcscripts"))
9325
		list->pushBack(L"http://xpluginmanager.co.uk/flscripts");
76 cycrow 9326
 
162 cycrow 9327
	return list->size();
1 cycrow 9328
}
9329
 
221 cycrow 9330
void CPackages::readArchiveData(const Utils::WString &filename, CBaseFile *archive) const
1 cycrow 9331
{
9332
	size_t size;
9333
	char *data = CFileIO(filename).ReadToData(&size);
9334
	if ( size && data )
182 cycrow 9335
		readArchiveData(data, size, archive);
1 cycrow 9336
}
9337
 
182 cycrow 9338
void CPackages::readArchiveData(const char *buf, size_t len, CBaseFile *archive) const
1 cycrow 9339
{
197 cycrow 9340
	Utils::WStringList otherGames;
9341
	Utils::WStringList gameAddons;
127 cycrow 9342
	for (unsigned int i = 0; i < m_gameExe.gameCount(); ++i)
9343
	{
197 cycrow 9344
		SGameExe *exe = m_gameExe.game(i);
127 cycrow 9345
		if (!exe->sAddon.empty())
197 cycrow 9346
			gameAddons.pushBack(Utils::WString::Number(i + 1), exe->sAddon);
127 cycrow 9347
	}
98 cycrow 9348
 
197 cycrow 9349
	Utils::WString data(buf);
9350
	std::vector<Utils::WString> str;
9351
	if(data.tokenise(L"\n", str))
1 cycrow 9352
	{
197 cycrow 9353
		for(size_t i = 0; i < str.size(); i++ )
1 cycrow 9354
		{
197 cycrow 9355
			Utils::WString line = str[i];
155 cycrow 9356
			if ( line.empty() )
1 cycrow 9357
				continue;
9358
 
9359
			// filter out any spaces, tabs in front
155 cycrow 9360
			line.removeChar('\t');
9361
			line.removeChar('\r');
197 cycrow 9362
			Utils::WString linenospace = line;
155 cycrow 9363
			linenospace.removeFirstSpace();
9364
			if ( linenospace.empty() )
1 cycrow 9365
				continue;
9366
 
9367
			// check for any comments
197 cycrow 9368
			if ( linenospace.left(2) == L"//" )
1 cycrow 9369
				continue;
197 cycrow 9370
			if ( linenospace[0] == L'#' )
1 cycrow 9371
				continue;
9372
 
9373
			// all commands start with a keyword followed by a colon, if one doesn't exist, it cant be a valid line
155 cycrow 9374
			if ( !line.contains(':'))
1 cycrow 9375
				continue;
9376
 
197 cycrow 9377
			Utils::WString first = line.token(L":", 1);
9378
			Utils::WString rest = line.tokens(L":", 2).removeFirstSpace();
1 cycrow 9379
 
197 cycrow 9380
			Utils::WString checkType = first;
1 cycrow 9381
			bool shared = false;
197 cycrow 9382
			if ( checkType.left(6).Compare(L"Shared") )
1 cycrow 9383
			{
155 cycrow 9384
				checkType = first.right(-6);
1 cycrow 9385
				shared = true;
9386
			}
155 cycrow 9387
			bool packed = false;
285 cycrow 9388
			if (checkType.right(3).toStdWString().compare(L"PCK"))
155 cycrow 9389
			{
9390
				checkType = checkType.left(-3);
9391
				packed = true;
9392
			}
1 cycrow 9393
 
9394
			// now check type name
9395
			int filetype = GetFileTypeFromString(checkType);
155 cycrow 9396
			if (filetype == -1)
9397
			{
197 cycrow 9398
				archive->loadPackageData(first, rest, Utils::WString::Null(), otherGames, gameAddons, NULL);
155 cycrow 9399
			}
1 cycrow 9400
		}
9401
	}
9402
}
9403
 
221 cycrow 9404
CBaseFile *CPackages::_archive_fromRar(const Utils::WString &filename, bool toInstall) const
1 cycrow 9405
{
9406
	// make sure we can open the zip file
9407
	CBaseFile *archive = NULL;
9408
#ifdef _RAR
43 cycrow 9409
	HANDLE hArcData;
9410
	int RHCode,PFCode;
248 cycrow 9411
	wchar_t CmtBuf[16384];
43 cycrow 9412
	struct RARHeaderDataEx HeaderData;
9413
	struct RAROpenArchiveDataEx OpenArchiveData;
1 cycrow 9414
 
43 cycrow 9415
	// find the pluginmanager text to covnert to spkfile
9416
	if ( toInstall ) {
1 cycrow 9417
		memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
248 cycrow 9418
		OpenArchiveData.ArcNameW=(wchar_t *)filename.c_str();
9419
		OpenArchiveData.CmtBufW=CmtBuf;
9420
		OpenArchiveData.CmtBufSize = sizeof(CmtBuf) / sizeof(CmtBuf[0]);
43 cycrow 9421
		OpenArchiveData.OpenMode=RAR_OM_LIST;
1 cycrow 9422
		hArcData=RAROpenArchiveEx(&OpenArchiveData);
9423
 
43 cycrow 9424
		if (OpenArchiveData.OpenResult!=0) return NULL;
1 cycrow 9425
 
9426
		HeaderData.CmtBuf=NULL;
9427
		memset(&OpenArchiveData.Reserved,0,sizeof(OpenArchiveData.Reserved));
9428
 
43 cycrow 9429
		while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0) {
221 cycrow 9430
			if ( Utils::WString(HeaderData.FileName).Compare(L"pluginmanager.txt") ) {
43 cycrow 9431
				toInstall = false;
1 cycrow 9432
				break;
9433
			}
43 cycrow 9434
		}
9435
		RARCloseArchive(hArcData);
9436
	}
1 cycrow 9437
 
43 cycrow 9438
	memset(&OpenArchiveData,0,sizeof(OpenArchiveData));
248 cycrow 9439
	OpenArchiveData.ArcNameW = (wchar_t*)filename.c_str();
9440
	OpenArchiveData.CmtBufW = CmtBuf;
9441
	OpenArchiveData.CmtBufSize = sizeof(CmtBuf) / sizeof(CmtBuf[0]);
43 cycrow 9442
	OpenArchiveData.OpenMode=RAR_OM_EXTRACT;
9443
	OpenArchiveData.UserData=EXTRACT;
9444
	hArcData=RAROpenArchiveEx(&OpenArchiveData);
9445
 
9446
	if (OpenArchiveData.OpenResult!=0) return NULL;
9447
 
248 cycrow 9448
	if (toInstall)
9449
		archive = new CArchiveFile(); // just installing an archive file
9450
	else
9451
		archive = new CSpkFile(); // converting to a spk file
9452
 
9453
 
43 cycrow 9454
	HeaderData.CmtBuf=NULL;
9455
	memset(&OpenArchiveData.Reserved,0,sizeof(OpenArchiveData.Reserved));
9456
 
266 cycrow 9457
	CDirIO outputDir(m_sTempDir + L"/Extract");
9458
	if (!outputDir.exists())
9459
		outputDir.create();
9460
 
43 cycrow 9461
	bool error = false;
9462
	while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0)
9463
	{
248 cycrow 9464
		Utils::WString fileName(HeaderData.FileNameW);
43 cycrow 9465
 
9466
		if ( HeaderData.FileAttr == 16 )
9467
			continue;
266 cycrow 9468
		PFCode = RARProcessFileW(hArcData, RAR_EXTRACT, outputDir.dir(), NULL);
43 cycrow 9469
		if (PFCode!=0)
9470
		{
9471
			error = true;
9472
			break;
9473
		}
9474
 
266 cycrow 9475
		CFileIO File(outputDir.file(fileName));
52 cycrow 9476
		if ( File.exists() )
43 cycrow 9477
		{
197 cycrow 9478
			if ( fileName.Compare(L"pluginmanager.txt") )
223 cycrow 9479
				this->readArchiveData(File.fullFilename(), archive);
43 cycrow 9480
			else
1 cycrow 9481
			{
197 cycrow 9482
				Utils::WString extradir;
43 cycrow 9483
				int type = SPK::GetAutomaticFiletype(fileName, &extradir, true);
9484
				// check for special file types
9485
				C_File *f = NULL;
1 cycrow 9486
 
43 cycrow 9487
				if ( type == FILETYPE_SCRIPT_UNINSTALL ) {
197 cycrow 9488
					f = archive->addFile(CFileIO(fileName).filename(), L"", FILETYPE_SCRIPT);
43 cycrow 9489
					if ( f ) {
197 cycrow 9490
						f->readFromFile(File.fullFilename());
17 cycrow 9491
					}
43 cycrow 9492
					type = FILETYPE_UNINSTALL;
1 cycrow 9493
				}
9494
 
43 cycrow 9495
				if ( type == -1 )
197 cycrow 9496
					f = archive->addFile(CFileIO(fileName).filename(), CFileIO(fileName).dir(), FILETYPE_EXTRA);
43 cycrow 9497
				else
197 cycrow 9498
					f = archive->addFile(CFileIO(fileName).filename(), extradir, static_cast<FileType>(type));
202 cycrow 9499
				f->readFromFile(File.fullFilename());
1 cycrow 9500
			}
43 cycrow 9501
 
52 cycrow 9502
			File.remove();
1 cycrow 9503
		}
43 cycrow 9504
	}
1 cycrow 9505
 
43 cycrow 9506
	RARCloseArchive(hArcData);
1 cycrow 9507
 
266 cycrow 9508
	if (outputDir.exists())
9509
		outputDir.removeDir(L".", true, true);
9510
 
43 cycrow 9511
	if ( error )
9512
	{
9513
		delete archive;
9514
		archive = NULL;
9515
	}
1 cycrow 9516
#endif
9517
 
43 cycrow 9518
	return archive;
9519
}
1 cycrow 9520
 
271 cycrow 9521
bool CPackages::_check_archive_fromZip(const Utils::WString& filename) const
43 cycrow 9522
{
271 cycrow 9523
	HZIP hz = OpenZip(filename.c_str(), 0);
9524
	if (!hz)
9525
		return false;
9526
 
9527
	bool found = false;
9528
 
9529
	int index;
9530
	// move the files from the zip to the package
9531
	ZIPENTRY ze;
9532
	if (FindZipItem(hz, L"pluginmanager.txt", true, &index, &ze) == Z_OK)
9533
		found = true;
9534
	CloseZip(hz);
9535
 
9536
	return found;
9537
}
9538
 
9539
CBaseFile* CPackages::_archive_fromZip(const Utils::WString& filename, bool toInstall) const
9540
{
43 cycrow 9541
	CBaseFile *archive = NULL;
1 cycrow 9542
 
241 cycrow 9543
	HZIP hz = OpenZip(filename.c_str(), 0);
43 cycrow 9544
	if ( !hz ) 
9545
		return NULL;
1 cycrow 9546
 
43 cycrow 9547
	int index;
9548
	// move the files from the zip to the package
9549
	ZIPENTRY ze;
9550
	if ( FindZipItem(hz, L"pluginmanager.txt", true, &index, &ze) == Z_OK )
9551
		toInstall = false;
9552
	CloseZip(hz);
1 cycrow 9553
 
241 cycrow 9554
	hz = OpenZip(filename.c_str(), 0);
43 cycrow 9555
	if ( !hz ) 
9556
		return NULL;
9557
 
9558
	// create the correct package
9559
	if ( toInstall )
9560
		archive = new CArchiveFile(); // just installing an archive file
9561
	else
9562
		archive = new CSpkFile(); // converting to a spk file
9563
 
9564
	GetZipItem(hz, -1, &ze);
9565
	int numitems = ze.index;
9566
 
281 cycrow 9567
	std::set<unsigned int> games;
9568
 
43 cycrow 9569
	bool error = false;
9570
	for ( int zi = 0; zi < numitems; zi++ )
9571
	{
9572
		ZIPENTRY ze;
9573
		if ( GetZipItem(hz, zi, &ze) != Z_OK )
1 cycrow 9574
		{
43 cycrow 9575
			error = true;
9576
			break;
9577
		}
1 cycrow 9578
 
43 cycrow 9579
		if ( ze.attr & FILE_ATTRIBUTE_DIRECTORY )
9580
			continue; // dont do directories
1 cycrow 9581
 
9582
 
43 cycrow 9583
		char *iBuf = new char[ze.unc_size];
9584
		UnzipItem(hz, zi, iBuf, ze.unc_size);
1 cycrow 9585
 
221 cycrow 9586
		Utils::WString Name(ze.name);
1 cycrow 9587
 
43 cycrow 9588
		// if its the data file, dont add it, but extract to get settings from
226 cycrow 9589
		if ( Name.Compare(L"pluginmanager.txt") )
43 cycrow 9590
		{
182 cycrow 9591
			this->readArchiveData(iBuf, ze.unc_size, archive);
43 cycrow 9592
			delete[] iBuf;
9593
		}
9594
		else
9595
		{
197 cycrow 9596
			Utils::WString extradir;
43 cycrow 9597
			int type = SPK::GetAutomaticFiletype(Name, &extradir, true);
1 cycrow 9598
 
43 cycrow 9599
			C_File *f = NULL;
17 cycrow 9600
 
197 cycrow 9601
			Utils::WString filename = CFileIO(Name).filename();
9602
			Utils::WString dir = CFileIO(Name).dir();
126 cycrow 9603
 
43 cycrow 9604
			// check for special file types
9605
			if ( type == FILETYPE_SCRIPT_UNINSTALL ) {
170 cycrow 9606
				f = archive->addFile(filename, dir, FILETYPE_SCRIPT);
43 cycrow 9607
				if ( f ) {
9608
					f->copyData((const unsigned char *)iBuf, ze.unc_size);
17 cycrow 9609
				}
43 cycrow 9610
				type = FILETYPE_UNINSTALL;
9611
			}
17 cycrow 9612
 
126 cycrow 9613
			int game = 0;
9614
			// check for addons
279 cycrow 9615
			if (!dir.empty())
126 cycrow 9616
			{
197 cycrow 9617
				Utils::WString first = dir.token(L"/", 1);
126 cycrow 9618
				int g = m_gameExe.findAddonType(first);
9619
				if (g != -1)
281 cycrow 9620
				{
126 cycrow 9621
					game = g + 1;
281 cycrow 9622
					games.insert(game);
9623
				}
126 cycrow 9624
			}
9625
 
281 cycrow 9626
			// TODO: Check if an existing file exists with a different game
43 cycrow 9627
			if ( type == -1 )
281 cycrow 9628
				f = archive->addFile(filename, dir, FILETYPE_EXTRA, game > 0 ? 1 << game : 0);
43 cycrow 9629
			else
281 cycrow 9630
				f = archive->addFile(filename, extradir, static_cast<FileType>(type), game > 0 ? 1 << game : 0);
1 cycrow 9631
 
281 cycrow 9632
			if (f)
9633
			{
9634
				if (!game && f->isFileInAddon())
9635
					games.insert(1);
9636
 
9637
				f->SetData((const unsigned char*)iBuf, ze.unc_size);
9638
			}
43 cycrow 9639
			else
9640
				delete[] iBuf;
1 cycrow 9641
		}
43 cycrow 9642
	}
1 cycrow 9643
 
43 cycrow 9644
	CloseZip(hz);
1 cycrow 9645
 
43 cycrow 9646
	if ( error )
9647
	{
9648
		delete archive;
9649
		archive = NULL;
1 cycrow 9650
	}
281 cycrow 9651
 
9652
	// if there is only one game, then set all the files to "All Games"
9653
	//if (games.size() <= 1)
9654
	{
9655
		for (auto itr = archive->fileList().Front(); itr; itr = itr->next())
9656
			itr->Data()->setGame(0);
9657
	}
9658
 
43 cycrow 9659
	return archive;
9660
}
1 cycrow 9661
 
221 cycrow 9662
CBaseFile *CPackages::createFromArchive(const Utils::WString &filename, bool toInstall) const
43 cycrow 9663
{
9664
	// make sure we can open the zip file
9665
	CBaseFile *archive = NULL;
196 cycrow 9666
	if ( CFileIO(filename).isFileExtension(L"rar") )
43 cycrow 9667
		archive = this->_archive_fromRar(filename, toInstall);
196 cycrow 9668
	else if ( CFileIO(filename).isFileExtension(L"zip") )
43 cycrow 9669
		archive = this->_archive_fromZip(filename, toInstall);
271 cycrow 9670
	else
9671
		archive = this->_archive_fromZip(filename, false);
43 cycrow 9672
 
9673
	if ( archive ) {
221 cycrow 9674
		archive->setFilename(CFileIO(filename).changeFileExtension(L"spk"));
278 cycrow 9675
		if (archive->name().empty())
9676
		{
9677
			if (toInstall)
9678
				archive->setName(CFileIO(filename).filename());
9679
			else
9680
				archive->setName(CFileIO(filename).baseName());
9681
		}
1 cycrow 9682
	}
9683
 
9684
	return archive;
9685
}
9686
 
197 cycrow 9687
Utils::WString CPackages::CreateFromPackagerScript(CPackages *packages, const Utils::WString &filename)
1 cycrow 9688
{
197 cycrow 9689
	Utils::WString curDir = CFileIO(filename).dir();
9690
	Utils::WStringList variables;
9691
	variables.pushBack(L"$PATH", curDir);
9692
	CBaseFile *package = packages->loadPackagerScript(filename, NULL, NULL, NULL, &variables);
1 cycrow 9693
 
9694
	if ( !package )
221 cycrow 9695
		return Utils::WString::Null();
1 cycrow 9696
 
197 cycrow 9697
	Utils::WString saveto = package->filename();
9698
	saveto = saveto.findReplace(L"$DEFAULTDIR", curDir + L"/");
9699
	saveto = saveto.findReplace(L"$PATH", curDir);
9700
	saveto = saveto.findReplace(L"\\", L"/");
9701
	saveto = saveto.findReplace(L"//", L"/");
9702
	if ( !saveto.right(4).Compare(L".spk") && package->GetType() != TYPE_XSP )
9703
		saveto += L".spk";
9704
	else if ( !saveto.right(4).Compare(L".xsp") && package->GetType() == TYPE_XSP )
9705
		saveto += L".xsp";
1 cycrow 9706
 
9707
	// write script
221 cycrow 9708
	if ( package->writeFile(saveto) )
1 cycrow 9709
	{
9710
		if ( package->AutoGenerateUpdateFile() )
134 cycrow 9711
			package->createUpdateFile(CFileIO(saveto).dir());
1 cycrow 9712
		return saveto;
9713
	}
9714
 
221 cycrow 9715
	return Utils::WString::Null();
1 cycrow 9716
}
9717
 
197 cycrow 9718
int CPackages::GeneratePackageUpdateData(const Utils::WString &dir, bool includeSingle)
1 cycrow 9719
{
197 cycrow 9720
	Utils::WStringList filedata;
1 cycrow 9721
 
9722
	CPackages packages;
9723
 
9724
	CDirIO Dir(dir);
9725
	for ( int i = 0; i < 2; i++ )
9726
	{
197 cycrow 9727
		Utils::WString pattern;
9728
		if ( i == 0 ) pattern = L"*.spk";
9729
		else if ( i == 1 ) pattern = L".xsp";
1 cycrow 9730
		else break;
9731
 
197 cycrow 9732
		Utils::WStringList files;
9733
		if(Dir.dirList(files, L"", pattern))
1 cycrow 9734
		{
126 cycrow 9735
			for(auto itr = files.begin(); itr != files.end(); itr++)
1 cycrow 9736
			{
9737
				int error = 0;
197 cycrow 9738
				CBaseFile *p = packages.openPackage(Dir.file((*itr)->str), &error, 0, SPKREAD_NODATA);
1 cycrow 9739
				if ( !p )
9740
					continue;
9741
 
9742
				if ( includeSingle )
160 cycrow 9743
					p->createUpdateFile(dir);
126 cycrow 9744
				filedata.pushBack(CPackages::FormatAvailablePackageData(p));
1 cycrow 9745
				delete p;
9746
			}
9747
		}
9748
	}
9749
 
126 cycrow 9750
	if ( !filedata.empty() )
1 cycrow 9751
	{
197 cycrow 9752
		CFileIO File(dir + L"/xpackagedata.dat");
126 cycrow 9753
		if ( File.writeFile(&filedata) )
9754
			return filedata.size();
1 cycrow 9755
	}
9756
 
9757
	return 0;
9758
}
9759
 
197 cycrow 9760
size_t CPackages::verifyInstalledFiles(Utils::WStringList *missingFiles, bool getPackages) const
1 cycrow 9761
{
9762
	int count = 0;
9763
	for ( CListNode<C_File> *fn = m_lFiles.Front(); fn; fn = fn->next() )
9764
	{
9765
		C_File *f = fn->Data();
9766
		bool exists = false;
197 cycrow 9767
		if ( f->filePointer().contains(L"::") ) {
9768
			Utils::WString modFile = f->filePointer().token(L"::", 1);
9769
			Utils::WString file = f->filePointer().token(L"::", 2);
1 cycrow 9770
 
170 cycrow 9771
			if ( CFileIO::Exists(modFile)) {
1 cycrow 9772
				CCatFile catFile;
197 cycrow 9773
				if ( catFile.open(modFile, L"", CATREAD_CATDECRYPT, false) == CATERR_NONE ) {
181 cycrow 9774
					if ( catFile.findData(file) )
1 cycrow 9775
						exists = true;
9776
				}
9777
			}
9778
		}
9779
		else {
170 cycrow 9780
			exists = CFileIO::Exists(f->filePointer());
1 cycrow 9781
		}
9782
 
9783
		if ( !exists )
9784
		{
9785
			++count;
9786
			if ( missingFiles )
9787
			{
197 cycrow 9788
				Utils::WString packages;
1 cycrow 9789
				if ( getPackages )
9790
				{
9791
					for ( CListNode<CBaseFile> *p = m_lPackages.Front(); p; p = p->next() )
9792
					{
9793
						CBaseFile *package = p->Data();
9794
						if ( package->IsFileAdded(f) )
9795
						{
170 cycrow 9796
							if ( !packages.empty() )
197 cycrow 9797
								packages += L"\n";
203 cycrow 9798
							packages += package->getFullPackageName(m_iLanguage);
1 cycrow 9799
						}
9800
					}
9801
				}
197 cycrow 9802
				Utils::WString filename = f->filePointer();
170 cycrow 9803
				filename = filename.findRemove(m_sCurrentDir);
182 cycrow 9804
				missingFiles->pushBack(filename, packages);
1 cycrow 9805
			}
9806
		}
9807
	}
9808
	return count;
35 cycrow 9809
}