Subversion Repositories spk

Rev

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