Subversion Repositories spk

Rev

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