Subversion Repositories spk

Rev

Rev 98 | Rev 101 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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