Subversion Repositories spk

Rev

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

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