Subversion Repositories spk

Rev

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