Subversion Repositories spk

Rev

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