Subversion Repositories spk

Rev

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

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