Subversion Repositories spk

Rev

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