Subversion Repositories spk

Rev

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