Subversion Repositories spk

Rev

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