Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
/*
2
 SPKInstall V1.00 Created by Cycrow (Matthew Gravestock)
3
*/
4
 
5
// Main Spk File Library Include
6
#ifdef _WIN32
7
#include <spk.h>
218 cycrow 8
#include <StringList.h>
1 cycrow 9
#else
10
#include "../spk/spk.h"
11
#endif
12
#include <time.h>
13
 
14
#ifdef _WIN32
15
#include <windows.h>
16
#include <direct.h>
17
#include <shlobj.h>
18
#endif
19
 
46 cycrow 20
#include <Package/InstallText.h>
329 cycrow 21
#include "Utils/CommandLine.h"	
46 cycrow 22
 
1 cycrow 23
#define BETA 1
24
 
25
class CProgressConsole : public CProgressInfo
26
{
27
public:
28
	CProgressConsole() : CProgressInfo()
29
	{
30
		m_iCount = 0;
31
		m_fNextPercent = 0.0f;
32
	}
33
 
34
	void Finish(bool newline = true)
35
	{
36
		for ( int i = m_iCount; i < 20; i++ )
37
			printf ( "*" );
38
		if ( newline )
39
			printf ( "\n");
40
		m_fNextPercent = 0.0f;
41
		m_iCount = 0;
42
	}
43
 
44
protected:
45
	virtual void ProgressUpdated ( const long cur, const long max )
46
	{
47
		float percent = ((float)cur / (float)max) * 100.0f;
48
		if ( m_bDoHalf )
49
		{
50
			percent /= 2.0f;
51
			if ( m_bSecondHalf )
52
				percent += 50.0f;
53
			else if ( percent > 50.0f )
54
				percent = 50.0f;
55
		}
56
		if ( (percent - m_fNextPercent) >= 5.0f )
57
		{
58
			printf ( "*" );
59
			m_fNextPercent += 5.0f;
60
			++m_iCount;
61
		}
62
	}
63
	virtual void DoingFile ( C_File *file )
64
	{
65
	}
66
 
67
private:
68
	float m_fNextPercent;
69
	int   m_iCount;
70
};
71
 
329 cycrow 72
#define FLAGS L"[-voctm][--dir:destination][--lang:langid]"
1 cycrow 73
 
298 cycrow 74
Utils::WString	g_dir;
1 cycrow 75
bool	g_debug = false;
76
bool	g_force = false;
77
int		g_indent = 0;
78
/*
79
	Func:	GetInput
80
	Desc:	Gets an input from the user, ie, any settings required to be typed in
81
*/
206 cycrow 82
Utils::WString GetInput ()
1 cycrow 83
{
84
//	g_read = true;
85
 
206 cycrow 86
	Utils::WString line;
1 cycrow 87
	char c = getchar();
88
 
89
	while ( (c != '\n') && (c != '\0') )
90
	{
206 cycrow 91
		line += Utils::WString(c);
1 cycrow 92
		c = getchar();
93
	}
94
 
95
	return line;
96
}
97
 
298 cycrow 98
void PrintSyntax(const Utils::WString &cmd)
1 cycrow 99
{
329 cycrow 100
	wprintf(L"Syntax: %s %s <command> [arguments]\n", cmd.c_str(), FLAGS );
298 cycrow 101
	wprintf(L"\nCommands:\n" );
329 cycrow 102
	wprintf(L"   list\n\t- Lists installed packages\n");
103
	wprintf(L"   info <package#>\n\t- Info about an installed package, use id number from list\n");
104
	wprintf(L"   install <file>\n\t- Installs a package file\n" );
105
	wprintf(L"   uninstall <package#>\n\t- Uninstalls a package, use id number from list\n" );
106
	wprintf(L"   enable <package#>\n\t- Enables an installed package\n" );
107
	wprintf(L"   disable <package#>\n\t- Disables an installed package\n" );
108
	wprintf(L"   removeuninstall\n\t- Removes uninstall scripts\n" );
109
	wprintf(L"   removeshared\n\t- Removes unused sharded files\n" );
110
	wprintf(L"\nSwitchs:\n");
111
	wprintf(L"   --dir:<directory>\n\tChange destination directory, otherwise uses current\n\n" );
112
	wprintf(L"   --lang:<language>\n\tSets the language id for text file renaming\n\totheriwse reads game lang.dat\n\n");
113
	wprintf(L"\nFlags:\n");
114
	wprintf(L"   -v (--verbose)\n\tTurns on verbose mode\n\n");
115
	wprintf(L"   -o (--override)\n\tOverride install warnings\n\tIE. allows you to install older scripts\n\n");
116
	wprintf(L"   -t (--textrename)\n\tForces text file renaming for installed packages\n\n");
117
	wprintf(L"   -c (enablechild)\n\tAuto Enabled all children when parent is enabled\n\n");
118
	wprintf(L"   -m (forcemod)\n\tForces a mod enabled even if theres one already enabled\n\n");
1 cycrow 119
}
120
 
121
void DisplayPackage(CBaseFile *p, int indent, int language)
122
{
204 cycrow 123
	Utils::WString version = p->version();
1 cycrow 124
	if ( version.lower()[0] != 'v' )
204 cycrow 125
		version.prepend(L"v");
1 cycrow 126
 
127
	printf ( "  [%5d] ", p->GetNum() + 1 );
128
 
129
	if ( indent > g_indent )
130
	{
131
		printf (" \\->");
132
	}
133
	for ( int i = 0; i < indent; i++ )
134
		printf("\t");
135
 
136
	g_indent = indent;
137
 
138
	if ( !p->IsEnabled() )
139
		printf("[D] ");
140
 
329 cycrow 141
	wprintf(L"%s %s by %s", p->name(language).c_str(), version.c_str(), p->author().c_str());
142
 
143
	switch (p->GetType())
144
	{
145
	case TYPE_XSP:
146
		wprintf(L" (Ship)");
147
		break;
148
	case TYPE_SPK:
149
	{
150
		CSpkFile* spk = dynamic_cast<CSpkFile*>(p);
151
		wprintf(L" (%s)", spk->scriptTypeString(language).c_str());
152
		break;
153
	}
154
	}
155
 
156
	wprintf(L"\n");
1 cycrow 157
}
158
 
159
void DoAllChildren(CPackages *packages, CBaseFile *p, CLinkList<CBaseFile> *doneList, int indent)
160
{
161
	CLinkList<CBaseFile> children;
162
	if ( packages->GetChildPackages(p, &children) )
163
	{
164
		for ( CBaseFile *child = children.First(); p; p = children.Next() )
165
		{
166
			DisplayPackage(child, indent, packages->GetLanguage());
167
			doneList->push_back(child);
168
 
169
			DoAllChildren(packages, child, doneList, indent + 1);
170
		}
171
	}
172
}
173
 
174
void ListPackages(CPackages *packages)
175
{
176
	CProgressConsole progress;
177
 
178
	CLinkList<CBaseFile> doneList;
179
 
180
	g_indent = 0;
329 cycrow 181
	wprintf(L"\nPackages:\n");
1 cycrow 182
	for ( CBaseFile *p = packages->PackageList()->First(); p; p = packages->PackageList()->Next() )
183
	{
184
		// already done?
185
		if ( doneList.FindData(p) )
186
			continue;
187
 
188
		if ( p->GetType() != TYPE_SPK )
189
			continue;
190
 
191
		DisplayPackage(p, 0, packages->GetLanguage());
192
		doneList.push_back(p);
193
 
194
		// find all children
195
		DoAllChildren(packages, p, &doneList, 1);
196
	}
329 cycrow 197
	wprintf(L"\n");
1 cycrow 198
}
199
 
222 cycrow 200
size_t SplitArguments(char **argv, int argc, int start, Utils::WStringList *argList)
1 cycrow 201
{
202
	for ( int i = start; i < argc; i++ )
203
	{
222 cycrow 204
		Utils::WString arg = argv[i];
205
		if (!arg.empty())
206
			argList->pushBack(arg);
1 cycrow 207
	}
208
 
222 cycrow 209
	return argList->size();
1 cycrow 210
}
211
 
222 cycrow 212
Utils::WString InstallPackage(const Utils::WStringList &lArguments, Utils::WStringList *errors, CPackages *packages, bool disabled)
1 cycrow 213
{
214
	CProgressConsole progress;
215
 
216
	int error;
217
 
222 cycrow 218
	if (lArguments.empty())
203 cycrow 219
		return Utils::WString::Null();
1 cycrow 220
 
221
	// append spk on the end
222 cycrow 222
	for (auto itr = lArguments.begin(); itr != lArguments.end(); itr++)
1 cycrow 223
	{
222 cycrow 224
		if (!CFileIO::Exists((*itr)->str))
1 cycrow 225
		{
222 cycrow 226
			if (CFileIO((*itr)->str).extension().lower() != L"spk")
226 cycrow 227
				(*itr)->str += L".spk";
1 cycrow 228
		}
229
	}
230
 
231
	CLinkList<CBaseFile> lPackages;
232
 
233
	// open the package file
234
	printf ( "  - Opening Package                \n" );
222 cycrow 235
	for (auto itr = lArguments.begin(); itr != lArguments.end(); itr++)
1 cycrow 236
	{
222 cycrow 237
		Utils::WString spkFilename = (*itr)->str;
1 cycrow 238
 
182 cycrow 239
		if ( spkFilename.length() > 30 )
222 cycrow 240
			wprintf(L"    ..%28s ", spkFilename.right(28).c_str() );
1 cycrow 241
		else
222 cycrow 242
			wprintf(L"    %30s ", spkFilename.right(30).c_str() );
1 cycrow 243
 
244
		CLinkList<CBaseFile> lPackageList;
182 cycrow 245
		CBaseFile *package = packages->openPackage(spkFilename, &error, &progress);
1 cycrow 246
 
247
		// multi packages
248
		if ( !package && error == INSTALLERR_NOMULTI )
249
		{
182 cycrow 250
			if ( !packages->openMultiPackage(spkFilename, &lPackageList, &error, &progress) )
1 cycrow 251
			{
252
				printf ( "Error!\n");
253
				continue;
254
			}
255
			progress.Finish();
256
		}
257
 
258
		else if ( package )
259
		{
260
			progress.Finish();
261
			lPackageList.push_back(package);
262
		}
263
		else
264
		{
265
			printf ( "ERROR!  " );
266
			switch ( error )
267
			{
268
				case INSTALLERR_OLD:
269
					printf ( "File is in old format no longer supported" );
270
					break;
271
				case INSTALLERR_NOEXIST:
272
					printf ( "file doesn't exist" );
273
					break;
274
				case INSTALLERR_INVALID:
275
					printf ( "Invalid package file" );
276
					break;
277
				case INSTALLERR_NOSHIP:
278
					printf ( "Ship Packages are currently not supported" );
279
					break;
280
				case INSTALLERR_VERSION:
281
					printf ( "Package file was created in a newer version, unable to open" );
282
					break;
283
			}
284
			printf ( "\n");
285
			continue;
286
		}
287
 
288
		for ( CListNode<CBaseFile> *pNode = lPackageList.Front(); pNode; pNode = pNode->next() )
289
		{
290
			CBaseFile *package = pNode->Data();
291
 
292
			// compare versions
203 cycrow 293
			Utils::WString packageName = package->getFullPackageName(packages->GetLanguage());
1 cycrow 294
 
295
			int checkFlags = IC_ALL;
296
			int check = packages->PrepareInstallPackage(package, (disabled) ? true : !package->IsEnabled(), false, checkFlags);
297
 
298
			switch (check)
299
			{
300
				case INSTALLCHECK_OLDVERSION:
203 cycrow 301
					wprintf(L"Newer version of \"%s\" already installed", packageName.c_str() );
1 cycrow 302
					if ( !g_force )
303
					{
304
						printf ( ", Unable to install older, use -o to force installation\n" );
305
						continue;
306
					}
307
					else
308
					{
309
						printf ( ", Overriding install\n" );
310
						if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
311
							continue;
312
						break;
313
					}
314
					break;
315
					// wait for the rest to be added
316
				case INSTALLCHECK_WRONGGAME:
203 cycrow 317
					wprintf ( L"ERROR! \"%s\" Wrong Game (Requires: %s)", packageName.c_str(), packages->getGameTypesString(package, false).c_str() );
1 cycrow 318
					if ( g_force )
319
					{
320
						printf ( " [FORCED]\n" );
321
						if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
322
							continue;
323
					}
324
					else
325
					{
326
						printf("\n");
327
						continue;
328
					}
329
					break;
330
 
331
				case INSTALLCHECK_WRONGVERSION:
203 cycrow 332
					wprintf ( L"ERROR! \"%s\" Wrong Game Version (Requires: %s)\n", packageName.c_str(), packages->getGameVersionString(package).c_str() );
1 cycrow 333
					if ( g_force )
334
					{
335
						printf ( " [FORCED]\n" );
336
						if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
337
							continue;
338
					}
339
					else
340
					{
341
						printf("\n");
342
						continue;
343
					}
344
					break;
345
			}
346
 
46 cycrow 347
			if ( package->installText()->any() )
1 cycrow 348
			{
206 cycrow 349
				Utils::WString installtext = packages->getInstallBeforeText(package);
182 cycrow 350
				if ( !installtext.empty() )
1 cycrow 351
				{
182 cycrow 352
					installtext = installtext.stripHtml();
206 cycrow 353
					wprintf(L"Installing %s: %s\n", packageName.c_str(), installtext.c_str() );
1 cycrow 354
					printf ( "Do you want to continue with the install? " );
355
 
356
					if ( g_force )
357
						printf ( "(FORCED)\n" );
358
					else
359
					{
206 cycrow 360
						Utils::WString input = GetInput().lower();
1 cycrow 361
 
362
						if ( input != "y" && input != "yes" )
363
						{
364
							printf ( "\nInstallion aborted!!\n\n" );
365
							packages->RemovePreparedInstall(package);
366
							continue;
367
						}
368
					}
369
				}
370
			}
371
 
372
			lPackages.push_back(package);
373
		}
374
	}
375
 
376
	// is there any that couldn't install
377
	CLinkList<CBaseFile> lCheckPackages;
378
	if ( packages->CheckPreparedInstallRequired(&lCheckPackages) )
379
	{
380
		printf ( "\nError! Some packages are missing dependacies:\n" );
381
		for ( CListNode<CBaseFile> *pNode = lCheckPackages.Front(); pNode; pNode = pNode->next() )
382
		{
383
			CSpkFile *spk = (CSpkFile *)pNode->Data();
214 cycrow 384
			wprintf(L"\t%s V%s by %s (Requires: %s by %s)\n", spk->name(packages->GetLanguage()).c_str(), spk->version().c_str(), spk->author().c_str(), spk->otherName().c_str(), spk->otherAuthor().c_str());
1 cycrow 385
		}
386
	}
387
 
388
	// no packages will be installed
389
	if ( packages->GetNumPackagesInQueue() < 1 )
203 cycrow 390
		return Utils::WString::Null();
1 cycrow 391
 
392
	// install the package file
393
	printf ( "  - Installing                     " );
394
	CLinkList<CBaseFile> erroredPackages;
183 cycrow 395
	if ( packages->installPreparedPackages(errors, &progress, &erroredPackages) )
1 cycrow 396
		progress.Finish();
397
	else
398
	{
399
		printf ( "ERROR!\n" );
203 cycrow 400
		return Utils::WString::Null();
1 cycrow 401
	}
402
 
403
	// delete any errored packages
404
	for ( CListNode<CBaseFile> *pNode = erroredPackages.Front(); pNode; pNode = pNode->next() )
405
	{
406
		lPackages.remove(pNode->Data());
407
		pNode->DeleteData();
408
	}
409
 
410
	// now display the packages
203 cycrow 411
	Utils::WString retStr = L"Packages Installed:\n";
1 cycrow 412
	for ( CListNode<CBaseFile> *pNode = lPackages.Front(); pNode; pNode = pNode->next() )
413
	{
414
		CBaseFile *package = pNode->Data();
415
 
203 cycrow 416
		retStr += L"  <> ";
170 cycrow 417
		retStr += package->getFullPackageName(packages->GetLanguage());
203 cycrow 418
		retStr += L"\n";
1 cycrow 419
 
182 cycrow 420
		if ( !packages->getInstallAfterText(package).empty() )
1 cycrow 421
		{
206 cycrow 422
			Utils::WString afterText = packages->getInstallAfterText(package).stripHtml();
423
			afterText = afterText.findReplace(L"\n", L"\n\t");
203 cycrow 424
			retStr += L"\t";
206 cycrow 425
			retStr += afterText;
203 cycrow 426
			retStr += L"\n";
1 cycrow 427
		}
428
	}
429
 
430
	return retStr;
431
}
432
 
433
CBaseFile *FindPackage(int packageNum, CPackages *packages)
434
{
435
	for ( CBaseFile *p = packages->PackageList()->First(); p; p = packages->PackageList()->Next() )
436
	{
437
		if ( p->GetNum() == (packageNum - 1) )
438
			return p;
439
	}
440
 
441
	return 0;
442
}
443
 
206 cycrow 444
bool UninstallPackage(int uninstallNum, Utils::WStringList *errors, CPackages *packages, Utils::WString &endMessage)
1 cycrow 445
{
446
	CBaseFile *p = FindPackage(uninstallNum, packages);
447
	if ( !p )
448
		return false;
449
 
450
	// lets check for the uninstall text
206 cycrow 451
	Utils::WString uText = packages->getUninstallBeforeText(p).stripHtml();
182 cycrow 452
	if (!uText.empty())
1 cycrow 453
	{
206 cycrow 454
		wprintf(L"Uninstalling: %s\n", uText.c_str() );
1 cycrow 455
		printf ( "Do you wish to continue with the uninstall? " );
456
		if ( g_force )
457
			printf ( "(FORCED)\n" );
458
		else
459
		{
206 cycrow 460
			Utils::WString input = GetInput().lower();
1 cycrow 461
			if ( input != "y" && input != "yes" )
462
			{
463
				printf ( "\nUninstallation has been aborted!!\n" );
464
				return false;
465
			}
466
		}
467
	}
468
 
469
	CProgressConsole progress;
470
 
206 cycrow 471
	endMessage = L"Uninstalled: " + p->getFullPackageName(packages->GetLanguage());
1 cycrow 472
	// add the uninstall after text
182 cycrow 473
	uText = packages->getUninstallAfterText(p).stripHtml();
474
	if (!uText.empty())
1 cycrow 475
	{
206 cycrow 476
		endMessage += L"\n\n";
182 cycrow 477
		endMessage += uText;
206 cycrow 478
		endMessage += L"\n";
1 cycrow 479
	}
480
 
481
	printf ( "  - Unistalling                    " );
482
	packages->PrepareUninstallPackage(p);
183 cycrow 483
	if ( packages->uninstallPreparedPackages(errors, &progress) )
1 cycrow 484
	{
485
		progress.Finish();
486
	}
487
	else
488
	{
206 cycrow 489
		endMessage = L"";
1 cycrow 490
		printf ( "ERROR!\n" );
491
		return false;
492
	}
493
 
494
 
495
	return true;
496
}
497
 
206 cycrow 498
bool EnablePackage(int uninstallNum, Utils::WStringList *errors, CPackages *packages, Utils::WString &endMessage)
1 cycrow 499
{
500
	CBaseFile *p = FindPackage(uninstallNum, packages);
501
	if ( !p )
502
		return false;
503
 
504
	CProgressConsole progress;
505
 
206 cycrow 506
	endMessage = L"Enabled: " + p->getFullPackageName(packages->GetLanguage());
1 cycrow 507
 
508
	printf ( "  - Enabling                       " );
183 cycrow 509
	if ( packages->enablePackage(p, errors, &progress) )
1 cycrow 510
	{
511
		progress.Finish();
512
	}
513
	else
514
	{
515
		int error = packages->GetError();
182 cycrow 516
		endMessage = "";
1 cycrow 517
		printf ( "ERROR! " );
518
		if ( error == PKERR_NOPARENT )
519
			printf ( "Parent package is disabled" );
520
		printf ( "\n" );
521
		return false;
522
	}
523
	return true;
524
}
525
 
206 cycrow 526
bool DisablePackage(int uninstallNum, Utils::WStringList *errors, CPackages *packages, Utils::WString &endMessage)
1 cycrow 527
{
528
	CBaseFile *p = FindPackage(uninstallNum, packages);
529
	if ( !p )
530
		return false;
531
 
532
	CProgressConsole progress;
533
 
206 cycrow 534
	endMessage = L"Disabled: " + p->getFullPackageName(packages->GetLanguage());
1 cycrow 535
 
536
	printf ( "  - Disabling                      " );
183 cycrow 537
	if ( packages->disablePackage(p, errors, &progress) )
1 cycrow 538
	{
539
		progress.Finish();
540
	}
541
	else
542
	{
206 cycrow 543
		endMessage = L"";
1 cycrow 544
		printf ( "ERROR!\n" );
545
		return false;
546
	}
547
	return true;
548
}
549
 
197 cycrow 550
void RemoveUninstallScripts(CPackages *packages, Utils::WStringList *errors)
1 cycrow 551
{
552
	CProgressConsole progress;
553
	printf ( "  - Removing uninstall scripts     " );
183 cycrow 554
	packages->removeUninstallScripts(errors, &progress);
1 cycrow 555
	progress.Finish();
556
}
557
 
197 cycrow 558
void RemoveUnusedShared(CPackages *packages, Utils::WStringList *errors)
1 cycrow 559
{
560
	CProgressConsole progress;
561
	printf ( "  - Removing unused shared files   " );
183 cycrow 562
	packages->removeUnusedSharedFiles(errors, &progress);
1 cycrow 563
	progress.Finish();
564
}
565
 
566
 
222 cycrow 567
void PrintDebug(Utils::WStringList *errors)
1 cycrow 568
{
569
	if ( !g_debug )
570
		return;
571
 
222 cycrow 572
	if (errors && errors->size())
1 cycrow 573
		printf ( "\n");
574
 
222 cycrow 575
	for(auto itr = errors->begin(); itr != errors->end(); itr++)
1 cycrow 576
	{
222 cycrow 577
		int errornum = (*itr)->data.toInt();
578
		Utils::WString rest = (*itr)->str.tokens(L" ", 2);
1 cycrow 579
 
222 cycrow 580
		Utils::WString err = FormatErrorString(errornum, rest);
200 cycrow 581
		wprintf(L"  * %s\n", err.c_str());
1 cycrow 582
	}
583
 
222 cycrow 584
	if (errors && errors->size())
1 cycrow 585
		printf ( "\n");
586
}
587
 
588
 
589
 
590
 
591
void Pause()
592
{
593
#ifdef _DEBUG
594
	char pause;
595
	scanf ( "%s", &pause );
596
#endif
597
}
598
 
599
 
298 cycrow 600
int ParseCommandSwitchs(wchar_t c, Utils::WString &destination, CPackages *packages, int start, int *arg, char **argv)
1 cycrow 601
{
602
	switch ( c )
603
	{
298 cycrow 604
		case L'o':
1 cycrow 605
			g_force = true;
606
			break;
298 cycrow 607
		case L'v':
1 cycrow 608
			g_debug = true;
609
			break;
298 cycrow 610
		case L'd':
182 cycrow 611
			destination = argv[*arg];
612
			destination = destination.findReplace("\\", "/");
1 cycrow 613
			++(*arg);
614
			++start;
615
			break;
298 cycrow 616
		case L't':
1 cycrow 617
			packages->SetRenameText(true);
618
			break;
298 cycrow 619
		case L'l':
620
			packages->SetLanguage(Utils::WString(argv[*arg]).toInt());
1 cycrow 621
			++(*arg);
622
			++start;
623
			break;
298 cycrow 624
		case L'c':
1 cycrow 625
			packages->SetAutoEnable(true);
626
			break;
298 cycrow 627
		case L'm':
1 cycrow 628
			packages->SetForceModInstall(true);
629
			break;
630
	}
631
 
632
	return start;
633
}
634
 
329 cycrow 635
 
636
bool OpenDestination(Utils::CommandLine &cmd, const Utils::WString& destination)
637
{
638
	Utils::WString endMessage;
639
 
640
	wprintf(L"                                   |0              100|\n\n");
641
	wprintf(L"  - Reading game directory         ");
642
 
643
	CProgressConsole progress;
644
 
645
	auto& packages = cmd.packages();
646
	if (packages.read(destination, &progress))
647
	{
648
		packages.UpdatePackages();
649
		packages.ReadGameLanguage(false);
650
		progress.Finish(false);
651
 
652
		Utils::WString gameName = packages.getGameName();
653
		if (packages.GetLanguage() || !gameName.empty())
654
		{
655
			wprintf(L"\n\t");
656
			if (!gameName.empty())
657
				wprintf(L"Game: %s ", gameName.c_str());
658
			if (packages.GetLanguage())
659
				wprintf(L"(Language: %d)", packages.GetLanguage());
660
		}
661
		wprintf(L"\n");
662
		packages.AssignPackageNumbers();
663
		return true;
664
	}
665
	else
666
	{
667
		wprintf(L"ERROR!\n");
668
		wprintf(L"\nFailed to open destination directory: %s\n", destination.c_str());
669
		exit(1);
670
	}
671
 
672
	return false;
673
}
674
 
675
bool CloseDestination(Utils::CommandLine& cmd, bool isPrepare)
676
{
677
	CProgressConsole progress;
678
	Utils::WStringList lErrors;
679
 
680
	if (isPrepare)
681
		wprintf(L"  - Preparing game directory       ");
682
	else
683
		wprintf(L"  - Closing game directory         ");
684
 
685
	if (cmd.packages().closeDir(&lErrors, &progress, true))
686
		progress.Finish();
687
	else
688
	{
689
		wprintf(L"ERROR!\n");
690
		exit(1);
691
	}
692
 
693
	cmd.packages().RestoreFakePatch();
694
 
695
	wprintf(L"\nDone!\n");
696
 
697
	return true;
698
}
699
 
1 cycrow 700
/*
701
TODO:
702
Additional Features
703
	Patch Mods
704
	Update Packages
705
*/
706
 
707
/*
708
	Main entry point to program
709
*/
710
int main ( int argc, char **argv )
711
{
712
 	// display program header to command prompt
329 cycrow 713
	printf ( "\nSPKInstall V1.00 (SPK Library Version %.2f) 31/05/2025 Created by Cycrow\n\n", GetLibraryVersion() );
1 cycrow 714
 
329 cycrow 715
	Utils::CommandLine cmd(argc, argv, true);
1 cycrow 716
 
717
	// not enough arguments, display the syntax and exit
329 cycrow 718
	if (cmd.argCount() < 1 )
1 cycrow 719
	{
329 cycrow 720
		PrintSyntax(cmd.cmdName());
1 cycrow 721
		Pause();
722
		exit ( 1 );
723
	}
724
 
329 cycrow 725
	Utils::WString destination = cmd.cmdDir();
197 cycrow 726
	Utils::WStringList lErrors;
1 cycrow 727
 
329 cycrow 728
	// do the flags and switchs
729
	// get the destination directory
730
	if(cmd.hasSwitch(L"dir"))
731
		destination = cmd.switchData(L"dir").findReplace("\\", "/");
732
	else if (cmd.hasSwitch(L"directory"))
733
		destination = cmd.switchData(L"directory").findReplace("\\", "/");
734
	else if (cmd.hasSwitch(L"destination"))
735
		destination = cmd.switchData(L"destination").findReplace("\\", "/");
1 cycrow 736
 
329 cycrow 737
	// get the game language
738
	auto& packages = cmd.packages();
739
	if (cmd.hasSwitch(L"lang"))
740
		packages.SetLanguage(cmd.switchData(L"lang").toInt());
741
	else if (cmd.hasSwitch(L"language"))
742
		packages.SetLanguage(cmd.switchData(L"language").toInt());
1 cycrow 743
 
329 cycrow 744
	// check for verbose mode
745
	if (cmd.hasSwitch(L"verbose"))
746
		g_debug = true;
747
	else if (cmd.hasFlag('v'))
748
		g_debug = true;
749
 
1 cycrow 750
	int start = 2;
329 cycrow 751
	/*
1 cycrow 752
	// check for switchs
753
	while ( command[0] == '-' )
754
	{
755
		if ( argc < (start + 1) )
756
		{
757
			PrintSyntax(cmd);
758
			Pause();
759
			exit ( 1 );
760
		}
761
		++start;
762
 
763
		// single long commands
764
		int arg = 2;
298 cycrow 765
		if ( command.left(2) == L"--" )
1 cycrow 766
		{
298 cycrow 767
			Utils::WString cmd = command.right(-2);
768
			cmd.toLower();
1 cycrow 769
 
770
			char c = 0;
298 cycrow 771
			if ( cmd == L"override" )
1 cycrow 772
				c = 'o';
298 cycrow 773
			else if ( cmd == L"verbose" )
1 cycrow 774
				c = 'v';
298 cycrow 775
			else if ( cmd == L"directory" )
1 cycrow 776
				c = 'd';
298 cycrow 777
			else if ( cmd == L"textrename" )
1 cycrow 778
				c = 't';
298 cycrow 779
			else if ( cmd == L"enablechild" )
1 cycrow 780
				c = 'c';
298 cycrow 781
			else if ( cmd == L"language" )
1 cycrow 782
				c = 'l';
298 cycrow 783
			else if ( cmd == L"forcemod" )
1 cycrow 784
				c = 'm';
785
 
786
			if ( c )
182 cycrow 787
				start = ParseCommandSwitchs(c, destination, &packages, start, &arg, argv);
1 cycrow 788
		}
789
		else
790
		{
791
			// now parse arguments
298 cycrow 792
			for ( int i = 1; i < (int)command.length(); i++ )
182 cycrow 793
				start = ParseCommandSwitchs(command[i], destination, &packages, start, &arg, argv);
1 cycrow 794
		}
795
 
796
		if ( argc < start )
797
		{
798
			PrintSyntax(cmd);
799
			exit( 1 );
800
		}
801
		command = argv[start - 1];
802
	}
329 cycrow 803
	*/
1 cycrow 804
 
329 cycrow 805
	// check for valid command
806
	Utils::WString command = cmd.arg(0).toLower();
807
	if (command.Compare(L"list"))
808
	{
809
		if (OpenDestination(cmd, destination))
810
		{
811
			ListPackages(&packages);
812
			CloseDestination(cmd, false);
813
		}
814
	}
815
 
1 cycrow 816
	if ( command[0] == '/' )
817
	{
298 cycrow 818
		wchar_t c = command[1];
1 cycrow 819
 
820
		bool disabled = false;
821
 
298 cycrow 822
		Utils::WString checkCmd = command.lower();
823
		if ( checkCmd == L"/install" )
824
			c = L'i';
825
		else if ( checkCmd == L"/installdisable" )
1 cycrow 826
		{
298 cycrow 827
			c = L'i';
1 cycrow 828
			disabled = true;
829
		}
298 cycrow 830
		else if ( checkCmd == L"/uninstall" )
831
			c = L'u';
832
		else if ( checkCmd == L"/enable" )
833
			c = L'e';
834
		else if ( checkCmd == L"/disable" )
835
			c = L'd';
836
		else if ( checkCmd == L"/list" )
837
			c = L'l';
838
		else if ( checkCmd == L"/removeshared" )
839
			c = L's';
840
		else if ( checkCmd == L"/removeunisntall" )
841
			c = L'r';
1 cycrow 842
 
298 cycrow 843
		if ( c == L'i' || c == L'l' || c == L'u' || c == L'e' || c == L'd' || c == L'r' || c == L's' )
1 cycrow 844
		{
206 cycrow 845
			Utils::WString endMessage;
1 cycrow 846
 
298 cycrow 847
			wprintf(L"                                   |0              100|\n\n");
848
			wprintf(L"  - Reading game directory         ");
1 cycrow 849
 
850
			CProgressConsole progress;
851
 
182 cycrow 852
			if ( packages.read(destination, &progress) )
1 cycrow 853
			{
854
				packages.UpdatePackages();
855
				packages.ReadGameLanguage(false);
856
				progress.Finish(false);
857
 
197 cycrow 858
				Utils::WString gameName = packages.getGameName();
182 cycrow 859
				if ( packages.GetLanguage() || !gameName.empty())
1 cycrow 860
				{
861
					printf ( "\n\t" );
182 cycrow 862
					if ( !gameName.empty() )
197 cycrow 863
						wprintf ( L"Game: %s ", gameName.c_str());
1 cycrow 864
					if ( packages.GetLanguage() )
865
						printf ( "(Language: %d)", packages.GetLanguage() );
866
				}
867
				printf ( "\n" );
868
			}
869
			else
870
			{
871
				printf ( "ERROR!\n" );
872
				exit(1);
873
			}
874
 
875
			bool prepare = false;
876
 
877
			packages.AssignPackageNumbers();
878
 
222 cycrow 879
			Utils::WStringList lArguments;
1 cycrow 880
			SplitArguments(argv, argc, start, &lArguments);
881
 
882
			switch ( c )
883
			{
884
				case 'i':
885
					if ( argc <= start )
329 cycrow 886
						wprintf(L"Syntax: %s [flags] /i <file>\n\tInstalls a package to the destination\n", cmd.cmdName().c_str() );
1 cycrow 887
					else
888
					{
222 cycrow 889
						Utils::WString aftertext = InstallPackage(lArguments, &lErrors, &packages, disabled);
182 cycrow 890
						if(!aftertext.empty())
1 cycrow 891
						{
892
							prepare = true;
206 cycrow 893
							endMessage = aftertext;
1 cycrow 894
						}
222 cycrow 895
						PrintDebug(&lErrors);
1 cycrow 896
					}
897
					break;
898
 
899
				case 'u':
900
					if ( argc <= start )
329 cycrow 901
						wprintf(L"Syntax: %s [flags] /u <package#>\n\tUninstalls a package, package# is from the /l list command\n", cmd.cmdName().c_str() );
1 cycrow 902
					else
903
					{
298 cycrow 904
						prepare = UninstallPackage(Utils::WString(argv[start]).toInt(), &lErrors, &packages, endMessage);
222 cycrow 905
						PrintDebug(&lErrors);
1 cycrow 906
					}
907
					break;
908
 
909
				case 'e':
910
					if ( argc <= start )
329 cycrow 911
						wprintf(L"Syntax: %s [flags] /u <package#>\n\tEnabled an installed package thats been disabled\n", cmd.cmdName().c_str() );
1 cycrow 912
					else
913
					{
298 cycrow 914
						prepare = EnablePackage(Utils::WString(argv[start]).toInt(), &lErrors, &packages, endMessage);
222 cycrow 915
						PrintDebug(&lErrors);
1 cycrow 916
					}
917
					break;
918
 
919
				case 'd':
920
					if ( argc <= start )
329 cycrow 921
						wprintf(L"Syntax: %s [flags] /u <package#>\n\tDisabled an installed package\n", cmd.cmdName().c_str() );
1 cycrow 922
					else
923
					{
298 cycrow 924
						prepare = DisablePackage(Utils::WString(argv[start]).toInt(), &lErrors, &packages, endMessage);
222 cycrow 925
						PrintDebug(&lErrors);
1 cycrow 926
					}
927
					break;
928
 
929
				case 'l':
930
					ListPackages(&packages);
931
					break;
932
 
933
				case 'r':
183 cycrow 934
					RemoveUninstallScripts(&packages, &lErrors);
1 cycrow 935
					endMessage = "Removed all unused uninstall scripts";
936
					break;
937
 
938
				case 's':
183 cycrow 939
					RemoveUnusedShared(&packages, &lErrors);
1 cycrow 940
					endMessage = "Removed all unused shared files";
941
					break;
942
			}
943
 
944
			if ( prepare )
945
			{
183 cycrow 946
				lErrors.clear();
1 cycrow 947
				printf ( "  - Preparing game directory       " );
183 cycrow 948
				if ( packages.closeDir(&lErrors, &progress, true) )
1 cycrow 949
					progress.Finish();
950
				else
951
				{
952
					printf ( "ERROR!\n" );
953
					Pause();
954
					exit(1);
955
				}
956
 
222 cycrow 957
				PrintDebug(&lErrors);
1 cycrow 958
			}
959
			else
960
				packages.RestoreFakePatch();
961
 
962
			printf ( "\nDone!\n" );
182 cycrow 963
			if ( !endMessage.empty() )
206 cycrow 964
				wprintf(L"\n%s\n", endMessage.c_str() );
1 cycrow 965
		}
966
		else
967
			printf ( "Unknown Command: %c\n", c );
968
	}
969
 
970
	Pause();
971
 
972
	return 0;
973
}