Subversion Repositories spk

Rev

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