Subversion Repositories spk

Rev

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