Subversion Repositories spk

Rev

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