Subversion Repositories spk

Rev

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