Subversion Repositories spk

Rev

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