Subversion Repositories spk

Rev

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