Subversion Repositories spk

Rev

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