Subversion Repositories spk

Rev

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