Subversion Repositories spk

Rev

Rev 76 | Rev 82 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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