Subversion Repositories spk

Rev

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

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