Subversion Repositories spk

Rev

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