Subversion Repositories spk

Rev

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

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