Subversion Repositories spk

Rev

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

Rev Author Line No. Line
6 cycrow 1
// SpkFile.cpp: implementation of the CSpkFile class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
 
5
#include "BaseFile.h"
6
 
7
//////////////////////////////////////////////////////////////////////
8
// Construction/Destruction
9
//////////////////////////////////////////////////////////////////////
10
 
11
#include "spk.h"
12
 
13
#include "DirIO.h"
14
#include "File_IO.h"
15
#include "CatFile.h"
16
#include "Packages.h"
88 cycrow 17
#include "TextDB.h"
6 cycrow 18
 
46 cycrow 19
#include <Package/InstallText.h>
6 cycrow 20
 
46 cycrow 21
// remove these eventually
22
using namespace SPK;
23
using namespace Package;
6 cycrow 24
 
25
CArchiveFile::~CArchiveFile()
26
{
27
	Delete ();
28
}
29
 
30
CArchiveFile::CArchiveFile() : CBaseFile ()
31
{
32
	SetDefaults ();
33
}
34
 
35
void CBaseFile::SetDefaults ()
36
{
46 cycrow 37
	_setDefaults();
38
 
6 cycrow 39
	m_pIconFile = NULL;
40
 
41
	m_bAutoGenerateUpdateFile = false;
42
	m_SHeader.iValueCompression = SPKCOMPRESS_ZLIB;
43
	m_SHeader2.iFileCompression = SPKCOMPRESS_ZLIB;
44
	m_SHeader2.iDataCompression = SPKCOMPRESS_LZMA;
45
	m_pParent = NULL;
50 cycrow 46
	_changed();
6 cycrow 47
	m_bUpdate = false;
48
 
49
	ClearError();
50
 
51
	m_iLoadError = 0;
52
 
53
	m_bFullyLoaded = false;
54
	m_bSigned = false;
55
	m_bEnable = m_bGlobal = m_bProfile = m_bModifiedEnabled = true;
56
	m_bOverrideFiles = false;
57
}
58
 
88 cycrow 59
CBaseFile::CBaseFile() : _pTextDB(NULL)
6 cycrow 60
{
61
	SetDefaults ();
62
}
63
CBaseFile::~CBaseFile()
64
{
65
	Delete();
66
}
67
 
68
void CBaseFile::Delete ()
69
{
70
	m_lFiles.clear(true);
71
 
72
	if ( m_pIconFile )
73
	{
74
		delete m_pIconFile;
75
		m_pIconFile = NULL;
76
	}
77
 
88 cycrow 78
	if ( _pTextDB ) {
79
		delete _pTextDB;
80
		_pTextDB = NULL;
81
	}
82
 
6 cycrow 83
	m_lNames.clear(true);
84
}
85
 
121 cycrow 86
CyString CBaseFile::GetLanguageName ( int lang ) const
6 cycrow 87
{
88
	for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
89
	{
90
		SNames *n = node->Data();
91
		if ( n->iLanguage == lang )
92
			return n->sName;
93
	}
50 cycrow 94
	return this->name();
6 cycrow 95
}
96
 
97
 
98
/*
99
##########################################################################################
100
##################                Base Class Functions                  ##################
101
##########################################################################################
102
*/
103
 
53 cycrow 104
CLinkList<C_File> *CBaseFile::fileList(int type) const
6 cycrow 105
{
106
	CLinkList<C_File> *list = new CLinkList<C_File>;
107
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
108
	{
109
		C_File *f = node->Data();
110
		if ( f->GetFileType() == type )
111
			list->push_back(f);
112
	}
113
 
114
	return list;
115
}
116
 
13 cycrow 117
C_File *CBaseFile::GetNextFile(C_File *prev) const
6 cycrow 118
{
119
	int type = -1;
120
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
121
	{
122
		C_File *f = node->Data();
123
		if ( type == -1 )
124
		{
125
			if ( f == prev )
126
				type = f->GetFileType();
127
		}
128
		else
129
		{
130
			if ( f->GetFileType() == type )
131
				return f;
132
		}
133
	}
134
 
135
	return NULL;
136
}
137
 
13 cycrow 138
C_File *CBaseFile::GetPrevFile(C_File *next) const
6 cycrow 139
{
140
	if ( !next )
141
		return NULL;
142
 
143
	int type = -1;
144
	for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() )
145
	{
146
		C_File *f = node->Data();
147
		if ( type == -1 )
148
		{
149
			if ( f == next )
150
				type = f->GetFileType();
151
		}
152
		else
153
		{
154
			if ( f->GetFileType() == type )
155
				return f;
156
		}
157
	}
158
 
159
	return NULL;
160
}
161
 
13 cycrow 162
C_File *CBaseFile::GetFirstFile(int type) const
6 cycrow 163
{
164
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
165
	{
166
		C_File *f = node->Data();
167
		if ( f->GetFileType() == type )
168
			return f;
169
	}
170
 
171
	return NULL;
172
}
173
 
174
int CBaseFile::CheckFile ( CyString filename, float *version )
175
{
91 cycrow 176
	CFileIO File(filename);
177
	if ( !File.startRead() ) return 0;
178
	Utils::String line = File.readEndOfLine();
51 cycrow 179
	Utils::String type = line.token(";", 1);
180
	File.close();
6 cycrow 181
 
182
	// check for old version
51 cycrow 183
	if ( line.left(3) == "HiP" ) return SPKFILE_OLD;
6 cycrow 184
 
185
	// check for format
51 cycrow 186
	if ( version ) *version = line.token(";", 2);
6 cycrow 187
 
51 cycrow 188
	if ( type == "BaseCycrow" )	return SPKFILE_BASE;
189
	if ( type == "SPKCycrow" )	return SPKFILE_SINGLE;
190
	if ( type == "XSPCycrow" )	return SPKFILE_SINGLESHIP;
191
	if ( type == "MSPKCycrow" )	return SPKFILE_MULTI;
6 cycrow 192
	return SPKFILE_INVALID;
193
}
194
 
195
void CBaseFile::ClearFileData()
196
{
88 cycrow 197
	for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
6 cycrow 198
	{
88 cycrow 199
		f->Data()->DeleteData();
6 cycrow 200
	}
201
}
202
 
203
CyString CBaseFile::GetNameValidFile ()
204
{
50 cycrow 205
	CyString name = this->name();
6 cycrow 206
	name.RemoveChar ( ':' );
207
	name.RemoveChar ( '/' );
208
	name.RemoveChar ( '\\' );
209
	name.RemoveChar ( '*' );
210
	name.RemoveChar ( '?' );
211
	name.RemoveChar ( '"' );
212
	name.RemoveChar ( '<' );
213
	name.RemoveChar ( '>' );
214
	name.RemoveChar ( '|' );
215
	return name;
216
}
217
 
218
void CBaseFile::SwitchFilePointer(C_File *oldFile, C_File *newFile)
219
{
220
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
221
	{
222
		C_File *f = node->Data();
223
		if ( f == oldFile )
224
		{
225
			node->ChangeData(newFile);
226
			break;
227
		}
228
	}
229
}
230
 
231
bool CBaseFile::AnyFileType ( int type )
232
{
233
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
234
	{
235
		C_File *f = node->Data();
236
		if ( f->GetFileType() == type )
237
			return true;
238
	}
239
 
240
	return false;
241
}
242
 
243
void CBaseFile::AddFile ( C_File *file )
244
{
245
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
246
	{
247
		C_File *f = node->Data();
248
		if ( f->GetFileType() != file->GetFileType() )
249
			continue;
250
		if ( f->GetName() != file->GetName () )
251
			continue;
252
		if ( f->GetDir() != file->GetDir() )
253
			continue;
127 cycrow 254
		if ( f->game() != file->game() )
6 cycrow 255
			continue;
256
 
257
		m_lFiles.remove(node, true);
258
		break;
259
	}
260
 
88 cycrow 261
	_addFile(file);
6 cycrow 262
}
263
 
127 cycrow 264
C_File *CBaseFile::AddFile(CyString file, CyString dir, int type, int game)
6 cycrow 265
{
127 cycrow 266
	return addFile(file.ToString(), dir.ToString(), (FileType)type, game);
267
}
268
C_File *CBaseFile::addFile(const Utils::String &file, const Utils::String &dir, FileType type, int game)
269
{
270
	C_File *newfile = new C_File(file);
271
	newfile->SetDir(dir);
272
	newfile->SetFileType(type);
273
	newfile->setGame(game);
6 cycrow 274
 
275
	// first check if the file already exists
276
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
277
	{
278
		C_File *f = node->Data();
279
		if ( f->GetFileType() != newfile->GetFileType() )
280
			continue;
281
		if ( f->GetName() != newfile->GetName () )
282
			continue;
283
		if ( f->GetDir() != newfile->GetDir() )
284
			continue;
127 cycrow 285
		if ( f->game() != newfile->game() )
6 cycrow 286
			continue;
287
 
288
		// must already exist, delete this one
289
		m_lFiles.remove(node, true);
290
		break;
291
	}
292
 
88 cycrow 293
	_addFile(newfile);
6 cycrow 294
 
295
	return newfile;
296
}
297
 
298
bool CBaseFile::AddFileNow ( CyString file, CyString dir, int type, CProgressInfo *progress )
299
{
300
	C_File *f = AddFile ( file, dir, type );
301
	if ( !f->ReadFromFile () )
302
		return false;
303
 
304
	// compress the file
305
	return f->CompressData ( m_SHeader2.iDataCompression, progress );
306
}
307
 
308
C_File *CBaseFile::AppendFile ( CyString file, int type, int game, CyString dir, CProgressInfo *progress )
309
{
310
	C_File *newfile = AddFile ( file, dir, type, game );
311
	if ( !newfile )
312
		return NULL;
313
 
314
 
315
	// read the file into memory
316
	if ( newfile->ReadFromFile () )
317
	{
318
		// now compress the file
319
		if ( newfile->CompressData ( m_SHeader2.iDataCompression, progress ) )
320
			return newfile;
321
	}
322
	else if ( newfile->GetLastError() == SPKERR_MALLOC )
323
	{
324
		if ( newfile->CompressFile ( progress ) )
325
			return newfile;
326
	}
327
 
328
	m_lFiles.pop_back ();
329
	delete newfile;
330
 
331
	return NULL;
332
}
333
 
334
C_File *CBaseFile::FindFileAt ( int filetype, int pos )
335
{
336
	int count = 0;
337
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
338
	{
339
		C_File *file = node->Data();
340
		if ( file->GetFileType() != filetype )
341
			continue;
342
 
343
		if ( count == pos )
344
			return file;
345
 
346
		++count;
347
	}
348
 
349
	return NULL;
350
}
351
 
352
C_File *CBaseFile::FindFile ( CyString filename, int type, CyString dir, int game )
353
{
354
	CyString lfile = filename.ToLower();
355
	lfile = lfile.FindReplace ( "\\", "/" );
356
 
357
	lfile = lfile.GetToken ( lfile.NumToken('/'), '/' );
358
 
359
	CListNode<C_File> *node = m_lFiles.Front();
360
	while ( node )
361
	{
362
		C_File *f = node->Data();
363
		node = node->next();
364
 
365
		if ( type != f->GetFileType() )
366
			continue;
367
		if ( dir != f->GetDir() )
368
			continue;
127 cycrow 369
		if ( game != f->game() )
6 cycrow 370
			continue;
371
		if ( f->GetName().ToLower() == lfile )
372
			return f;
373
	}
374
	return NULL;
375
}
376
 
377
bool CBaseFile::RemoveFile ( CyString file, int type, CyString dir, int game )
378
{
379
	C_File *f = FindFile (file, type, dir, game);
380
	if ( !f )
381
		return false;
382
	return RemoveFile ( f );
383
}
384
 
385
bool CBaseFile::RemoveFile ( C_File *file )
386
{
387
	int count = 0;
388
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
389
	{
390
		C_File *f = node->Data();
391
		if ( f == file )
392
			return RemoveFile ( count );
393
		++count;
394
	}
395
	return false;
396
}
397
 
398
bool CBaseFile::RemoveFile ( int pos )
399
{
400
	if ( (pos < 0) || (pos >= m_lFiles.size()) )
401
		return false;
402
 
403
	C_File *file = m_lFiles.Get ( pos );
404
	m_lFiles.erase ( pos + 1 );
405
 
406
	if ( file )
407
		delete file;
408
 
50 cycrow 409
	_changed();
6 cycrow 410
 
411
	return true;
412
}
413
 
414
 
415
void CBaseFile::RemoveAllFiles ( int type, int game )
416
{
417
	if ( m_lFiles.empty() )
418
		return;
419
 
420
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
421
	{
422
		if ( game > -1 ) {
423
			if ( node->Data()->GetGame() != game )
424
				continue;
425
		}
426
		if ( type == -1 || node->Data()->GetFileType() == type )
427
			node->DeleteData();
428
	}
429
 
430
	m_lFiles.RemoveEmpty();
431
 
50 cycrow 432
	_changed();
6 cycrow 433
}
434
 
435
void CBaseFile::RecompressAllFiles ( int type, CProgressInfo *progress )
436
{
437
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
438
	{
439
		C_File *file = node->Data();
440
		if ( progress )
441
			progress->UpdateFile(file);
442
 
443
		if ( file->GetCompressionType() == type )
444
			continue;
445
 
446
		if ( !file->GetData() )
447
			file->ReadFromFile();
448
 
449
		file->ChangeCompression ( type, progress );
450
	}
451
}
452
 
47 cycrow 453
void CBaseFile::CompressAllFiles ( int type, CProgressInfo *progress, CProgressInfo *overallProgress, int level )
6 cycrow 454
{
47 cycrow 455
	if ( overallProgress ) overallProgress->SetMax(m_lFiles.size());
456
 
457
	int iCount = 0;
6 cycrow 458
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
459
	{
460
		C_File *file = node->Data();
461
		if ( progress )
462
			progress->UpdateFile(file);
463
 
464
		if ( !file->GetData() )
465
			file->ReadFromFile();
466
 
467
		file->CompressData ( type, progress, level );
47 cycrow 468
 
469
		if ( overallProgress ) overallProgress->SetDone(++iCount);
6 cycrow 470
	}
471
}
472
 
473
bool CBaseFile::UncompressAllFiles ( CProgressInfo *progress )
474
{
475
	int countFile = 0;
476
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
477
	{
478
		C_File *fit = node->Data();
479
		if ( progress )
480
		{
481
			progress->UpdateFile ( fit );
482
			progress->UpdateProgress(countFile++, m_lFiles.size());
483
		}
484
 
485
		bool uncomprToFile = false;
486
 
487
		if ( progress )
488
			progress->SwitchSecond();
489
 
127 cycrow 490
		if(!fit->isExternalFile())
6 cycrow 491
		{
127 cycrow 492
			if (!fit->UncompressData(progress))
6 cycrow 493
			{
127 cycrow 494
				if (fit->GetCompressionType() == SPKCOMPRESS_7ZIP)
6 cycrow 495
				{
127 cycrow 496
					if (!fit->UncompressToFile("temp", this, false, progress))
497
						return false;
498
					else
499
					{
500
						uncomprToFile = true;
501
						fit->SetFullDir("temp");
502
					}
6 cycrow 503
				}
127 cycrow 504
 
505
				if (!uncomprToFile)
506
					return false;
6 cycrow 507
			}
508
		}
509
 
510
		if ( progress )
511
			progress->SwitchSecond();
512
	}
513
	return true;
514
}
515
 
516
long CBaseFile::GetFullFileSize()
517
{
518
	long fullsize = 1000;
519
 
520
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
521
		fullsize += node->Data()->GetUncompressedDataSize();
522
 
523
	if ( m_pIconFile )
524
		fullsize += m_pIconFile->GetUncompressedDataSize();
525
 
526
	return fullsize;
527
}
528
 
529
/*
530
	Func:   GetEndOfLine
531
	Input:  id - The file id for the current file to read from
532
	        line - Pointed to hold the line number thats read
533
			upper - true if it converts to uppercase
534
	Return: String - the string it has read
535
	Desc:   Reads a string from a file, simlar to readLine() classes, reads to the end of the line in a file
536
*/
537
CyString CBaseFile::GetEndOfLine ( FILE *id, int *line, bool upper )
538
{
539
	CyString word;
540
 
541
	char c = fgetc ( id );
542
	if ( c == -1 )
543
		return "";
544
 
545
	while ( (c != 13) && (!feof(id)) && (c != '\n') )
546
	{
547
		word += c;
548
		c = fgetc ( id );
549
	}
550
 
551
	if ( line )
552
		++(*line);
553
 
554
	if ( upper )
555
		return word.ToUpper();
556
 
557
	return word;
558
}
559
 
560
int CBaseFile::CountFiles ( int filetype )
561
{
562
	int i = 0;
563
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
564
	{
565
		C_File *file = node->Data();
566
		if ( file->GetFileType() != filetype )
567
			continue;
568
		++i;
569
	}
570
 
571
	return i;
572
}
573
 
574
void CBaseFile::ClearNames ()
575
{
576
	m_lNames.clear(true);
577
}
578
void CBaseFile::RemoveLanguageName ( int lang )
579
{
580
	SNames *n;
581
	for ( n = m_lNames.First(); n; n = m_lNames.Next() )
582
	{
583
		if ( n->iLanguage == lang )
584
		{
585
			m_lNames.RemoveCurrent();
586
			delete n;
50 cycrow 587
			_changed();
6 cycrow 588
		}
589
	}
590
}
591
 
46 cycrow 592
void CBaseFile::AddLanguageName ( int lang, const Utils::String &name )
6 cycrow 593
{
594
	// first check for an existing language
595
	SNames *n;
596
	for ( n = m_lNames.First(); n; n = m_lNames.Next() )
597
	{
598
		if ( n->iLanguage == lang )
599
		{
600
			n->sName = name;
601
			return;
602
		}
603
	}
604
 
605
	// not found, add a new entry
606
	n = new SNames;
607
	n->iLanguage = lang;
608
	n->sName = name;
609
	m_lNames.push_back ( n );
610
 
50 cycrow 611
	_changed();
6 cycrow 612
}
613
 
614
CyString CBaseFile::GetFullPackageName(CyString format, int lang)
615
{
616
	if ( format.Empty() )
617
		return GetFullPackageName(lang);
618
 
50 cycrow 619
	CyString args[3] = { this->GetLanguageName(lang), this->version(), this->author() };
6 cycrow 620
	return format.Args(args, 3);
621
}
622
 
623
/*
624
	Func:   CreateFilesLine
625
	Return: String - returns the full string for files list
626
	Desc:   Creates a signle line list of all the files
627
*/
628
CyString CBaseFile::CreateFilesLine ( bool updateheader, CProgressInfo *progress )
629
{
630
	CyString line;
631
 
632
	if ( progress )
633
	{
634
		progress->SetDone(0);
635
		progress->UpdateStatus(STATUS_COMPRESS);
636
	}
637
 
638
	if ( updateheader )
639
	{
640
		m_SHeader2.iNumFiles = 0;
641
		m_SHeader2.lFullSize = 0;
642
	}
643
 
644
	if ( m_pIconFile )
645
	{
646
		// no data, read it from file
647
		if ( !m_pIconFile->GetData() )
648
			m_pIconFile->ReadFromFile ();
649
 
650
		// compress the file
651
		if ( !m_pIconFile->CompressData ( m_SHeader2.iDataCompression, progress ) )
652
			m_pIconFile->SetDataCompression(SPKCOMPRESS_NONE);
653
 
654
		line += CyString("Icon:") + (m_pIconFile->GetDataSize() + (long)4) + ":" + m_pIconFile->GetUncompressedDataSize() + ":" + (long)m_pIconFile->GetCompressionType() + ":" + m_sIconExt + "\n";
655
		if ( updateheader )
656
		{
657
			++m_SHeader2.iNumFiles;
658
			m_SHeader2.lFullSize += (m_pIconFile->GetDataSize() + 4);
659
		}
660
	}
661
 
662
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
663
	{
664
		C_File *file = node->Data();
665
		if ( progress )
666
			progress->UpdateFile ( file );
667
 
668
		// no data, read it from file
669
		if ( !file->GetData() )
670
		{
671
			if ( !file->ReadFromFile () )
672
			{
673
				if ( file->GetLastError() == SPKERR_MALLOC )
674
				{
675
					if ( !file->CompressFile ( progress ) )
676
						continue;
677
				}
678
			}
679
		}
680
 
681
		if ( !file->GetData() )
682
			continue;
683
 
684
		// compress the file
685
		if ( !file->CompressData ( m_SHeader2.iDataCompression, progress ) )
686
		{
687
			file->SetDataCompression(SPKCOMPRESS_NONE);
688
			file->SetUncompressedDataSize(file->GetDataSize());
689
		}
690
 
691
		CyString command = GetFileTypeString ( file->GetFileType() );
692
		if ( command.Empty() )
693
			continue;
694
 
695
		if ( file->IsShared() )
696
			command = CyString("$") + command;
697
 
698
		if ( file->GetDir().Empty() )
699
			line += (command + ":" + (file->GetDataSize() + (long)4) + ":" + file->GetUncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->GetFilename() + ":GAME_" + (long)file->GetGame() + "\n");
700
		else
701
			line += (command + ":" + (file->GetDataSize() + (long)4) + ":" + file->GetUncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->GetFilename() + ":" + file->GetDir() + ":GAME_" + (long)file->GetGame() + "\n");
702
 
703
		if ( updateheader )
704
		{
705
			++m_SHeader2.iNumFiles;
706
			m_SHeader2.lFullSize += (file->GetDataSize() + 4);
707
		}
708
	}
709
 
710
	return line;
711
}
712
 
713
 
714
/*
715
######################################################################################
716
##########							Reading Functions			    		##########
717
######################################################################################
718
*/
719
 
720
void CBaseFile::ReadAllFilesToMemory ()
721
{
722
	// no file to read from
50 cycrow 723
	if ( this->filename().empty() ) return;
6 cycrow 724
 
725
	// now open the file
58 cycrow 726
	CFileIO File(this->filename());
727
	if ( !File.startRead() ) return;
6 cycrow 728
 
729
	// read the header
58 cycrow 730
	File.readEndOfLine();
6 cycrow 731
	// skip past values
58 cycrow 732
	File.seek(4 + m_SHeader.lValueCompressSize);
6 cycrow 733
 
734
	// read the next header
58 cycrow 735
	File.readEndOfLine();
6 cycrow 736
	// skip past files
58 cycrow 737
	File.seek(4 + m_SHeader2.lSize);
6 cycrow 738
 
739
	if ( m_pIconFile )
740
	{
741
		if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
51 cycrow 742
			m_pIconFile->readFromFile(File, m_pIconFile->GetDataSize());
6 cycrow 743
		else
58 cycrow 744
			File.seek(4 + m_pIconFile->GetDataSize());
6 cycrow 745
	}
746
 
747
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
748
	{
749
		C_File *fit = node->Data();
750
		if ( (!fit->GetData()) && (!fit->Skip()) )
51 cycrow 751
			fit->readFromFile(File, fit->GetDataSize());
6 cycrow 752
		else
58 cycrow 753
			File.seek(4 + fit->GetDataSize());
6 cycrow 754
	}
755
 
51 cycrow 756
	File.close();
6 cycrow 757
}
758
 
759
bool CBaseFile::ReadFileToMemory(C_File *f)
760
{
62 cycrow 761
	if ( this->filename().empty() || !f ) return false;		// no filename to load from
51 cycrow 762
	if ( f->GetData() && f->GetDataSize() ) return true;	// already loaded the data
763
	if ( !m_lFiles.FindData(f) ) return false;				// unable to find file entry
6 cycrow 764
 
765
	// now open the file
58 cycrow 766
	CFileIO *File = _startRead();
767
	if ( !File ) return false;
6 cycrow 768
 
58 cycrow 769
	if ( m_pIconFile ) File->seek(4 + m_pIconFile->GetDataSize());
51 cycrow 770
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
6 cycrow 771
		C_File *fit = node->Data();
51 cycrow 772
		if (fit == f ) {
58 cycrow 773
			fit->readFromFile(*File, fit->GetDataSize());
6 cycrow 774
			break;
775
		}
58 cycrow 776
		else File->seek(4 + fit->GetDataSize());
6 cycrow 777
	}
778
 
58 cycrow 779
	delete File;
6 cycrow 780
	return true;
781
}
782
 
58 cycrow 783
CFileIO *CBaseFile::_startRead()
6 cycrow 784
{
785
	// no file to read from
58 cycrow 786
	if ( this->filename().empty() ) return NULL;
6 cycrow 787
 
788
	// now open the file
58 cycrow 789
	CFileIO *File = new CFileIO(this->filename());
790
	if ( !File->startRead() ) return NULL;
6 cycrow 791
 
792
	// read the header
58 cycrow 793
	File->readEndOfLine();
6 cycrow 794
	// skip past values
58 cycrow 795
	File->seek(4 + m_SHeader.lValueCompressSize);
6 cycrow 796
 
797
	// read the next header
58 cycrow 798
	File->readEndOfLine();
6 cycrow 799
	// skip past files
58 cycrow 800
	File->seek(4 + m_SHeader2.lSize);
6 cycrow 801
 
58 cycrow 802
	return File;
803
}
6 cycrow 804
 
88 cycrow 805
void CBaseFile::_addFile(C_File *file, bool dontChange)
806
{
807
	if ( !dontChange ) {
808
		file->UpdateSigned();
809
		_changed();
810
	}
811
	m_lFiles.push_back(file);
812
 
813
	_updateTextDB(file);
814
}
815
 
816
void CBaseFile::_updateTextDB(C_File *file)
817
{
818
	if ( !_pTextDB ) _pTextDB = new CTextDB();
819
 
820
	if ( file->GetFileType() == FILETYPE_TEXT ) {
821
		Utils::String baseFile = CFileIO(file->filePointer()).baseName();
822
		int lang = (baseFile.isin("-L")) ? baseFile.right(3) : baseFile.truncate(-4);
823
 
824
		// read in the text file to the database
825
		_pTextDB->parseTextFile(0, 0, file->filePointer(), lang);
826
	}
827
}
828
 
829
void CBaseFile::_resetTextDB()
830
{
831
	if ( _pTextDB ) delete _pTextDB;
832
	_pTextDB = new CTextDB();
833
 
834
	for(CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next()) {
835
		_updateTextDB(node->Data());
836
	}
837
}
838
 
58 cycrow 839
void CBaseFile::ReadIconFileToMemory ()
840
{
841
	if ( !m_pIconFile )	return;
842
	CFileIO *File = _startRead();
843
	if ( !File ) return;
844
 
845
	if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
846
		m_pIconFile->readFromFile(*File, m_pIconFile->GetDataSize());
847
	else
848
		File->seek(4 + m_pIconFile->GetDataSize());
849
 
850
	delete File;
6 cycrow 851
}
852
 
14 cycrow 853
void CBaseFile::_install_adjustFakePatches(CPackages *pPackages)
6 cycrow 854
{
855
	CyStringList lPatches;
14 cycrow 856
	int startfake = pPackages->FindNextFakePatch();
6 cycrow 857
 
14 cycrow 858
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
859
	{
860
		C_File *fit = node->Data();
861
		// only do fake patchs
862
		if ( !fit->IsFakePatch() )
863
			continue;
864
 
865
		// we should only have cat and dat files, but lets check just incase they have been added incorrectly
866
		if ( !fit->CheckFileExt ("cat") && !fit->CheckFileExt("dat") )
867
			continue;
868
 
869
		// search for the name on the list
870
		SStringList *opposite = lPatches.FindString(fit->GetBaseName());
871
		CyString newname;
872
		if ( opposite )
873
			newname = opposite->data;
874
		else
875
		{
876
			newname = CyString::Number((long)startfake).PadNumber(2);
877
			lPatches.PushBack(fit->GetBaseName(), newname);
878
		}
879
 
880
		// rename the file
881
		fit->FixOriginalName();
50 cycrow 882
		CLog::logf(CLog::Log_Install, 2, "Adjusting fake patch number, %s => %s", fit->GetNameDirectory(this).c_str(), (newname + "." + fit->GetFileExt()).c_str());
14 cycrow 883
		fit->SetName ( newname + "." + fit->GetFileExt() );
884
 
885
		// find the next gap
886
		if ( !opposite ) {
887
			startfake = pPackages->FindNextFakePatch(startfake + 1);
888
		}
889
	}
890
 
891
}
892
 
43 cycrow 893
void CBaseFile::_install_renameText(CPackages *pPackages)
14 cycrow 894
{
43 cycrow 895
	int starttext = pPackages->FindNextTextFile();
896
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
897
		C_File *fit = node->Data();
898
		if ( !fit->IsAutoTextFile() )
899
			continue;
6 cycrow 900
 
43 cycrow 901
		CyString newname = SPK::FormatTextName(starttext, pPackages->GetLanguage(), (pPackages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));
902
		fit->FixOriginalName();
50 cycrow 903
		CLog::logf(CLog::Log_Install, 2, "Adjusting text file, %s => %s", fit->GetNameDirectory(this).c_str(), (newname + "." + fit->GetFileExt()).c_str());
43 cycrow 904
		fit->SetName ( newname + "." + fit->GetFileExt() );
6 cycrow 905
 
43 cycrow 906
		++starttext;
907
	}
908
}
6 cycrow 909
 
50 cycrow 910
bool CBaseFile::_install_setEnabled(bool bEnable, C_File *fit)
911
{
912
	if ( !bEnable )
913
	{
914
		if ( (fit->GetFileType() == FILETYPE_UNINSTALL) || (fit->GetFileType() == FILETYPE_README) || (fit->GetFileType() == FILETYPE_ADVERT) )
915
			bEnable = true;
916
		else if ( (fit->GetFileType() == FILETYPE_EXTRA) && (fit->GetDir().Left(7).ToLower() == "Extras/") )
917
			bEnable = true;
918
		else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )
919
			bEnable = true;
920
 
921
		if ( bEnable ) CLog::logf(CLog::Log_Install, 3, "Filetype(%d) is always enabled, setting enabled flag", fit->GetFileType());
922
	}
923
 
924
	return bEnable;
925
}
926
 
927
bool CBaseFile::_install_uncompress(C_File *fit, CProgressInfo *progress, CyStringList *errorStr, bool *uncomprToFile)
928
{
929
	*uncomprToFile = false;
930
	m_sLastError = fit->GetNameDirectory(this);
931
	m_iLastError = SPKERR_UNCOMPRESS;
96 cycrow 932
 
50 cycrow 933
	if ( !fit->UncompressData ( progress ) )
934
	{
935
		CLog::log(CLog::Log_Install, 2, "Failed to uncompress data, attempting file decompression");
936
		if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP )
937
		{
938
			if ( fit->UncompressToFile ( NullString, this, false, progress ) )
939
				*uncomprToFile = true;
940
		}
941
 
942
		if ( !uncomprToFile )
943
		{
944
			if ( errorStr )
945
				errorStr->PushBack(m_sLastError, ERRORLOG(SPKINSTALL_UNCOMPRESS_FAIL));
946
			CLog::log(CLog::Log_Install, 1, "Unable to decompress file, skipping");
947
			return false;
948
		}
949
	}
950
	ClearError ();
951
 
952
	return true;
953
}
954
 
955
bool CBaseFile::_install_checkVersion(C_File *pFile, const Utils::String &sDestination)
956
{
957
	// new check if we should install the file
958
	// first get the version
959
	if ( !m_bOverrideFiles && pFile->ReadScriptVersion() )
960
	{
961
		CLog::log(CLog::Log_Install, 2, "Checking for existing file version");
962
		C_File checkfile;
963
		CyString checkfilename = sDestination;
964
		if ( !checkfilename.Empty() ) checkfilename += "/";
965
		checkfilename += pFile->GetNameDirectory(this);
966
		checkfile.SetFilename ( checkfilename );
127 cycrow 967
		checkfile.setFileType(pFile->fileType());
50 cycrow 968
		if ( checkfile.CheckValidFilePointer() ) {
969
			if ( checkfile.ReadScriptVersion() > pFile->GetVersion() ) {
970
				CLog::log(CLog::Log_Install, 1, "Newer version of the file found in directory, skipping");
971
				return false;
972
			}
973
		}
974
	}
975
 
976
	return true;
977
}
978
 
979
Utils::String CBaseFile::_install_adjustFilepointer(C_File *pFile, bool bEnabled, const Utils::String &sDestination)
980
{
981
	CyString filename = sDestination;
982
	if ( !filename.Empty() ) filename += "/";
983
 
984
	if ( (IsPatch()) && (pFile->GetFileType() == FILETYPE_MOD) )
985
		pFile->SetDir ( CyString("Patch") );
986
 
987
	if ( pFile->IsInMod() )
988
	{
989
		if ( bEnabled )
990
			pFile->SetFilename(filename + pFile->GetInMod() + "::" + pFile->GetNameDirectory(this));
991
		else
992
			pFile->SetFilename(filename + "PluginManager/DisabledFiles.cat::" + pFile->GetNameDirectory(this));
993
	}
994
	else
995
		pFile->SetFilename ( filename + pFile->GetNameDirectory(this) );
996
 
997
	if ( !bEnabled )
998
	{
999
		if ( !pFile->IsInMod() )
1000
		{
1001
			if ( pFile->IsFakePatch() )
1002
				pFile->SetFilename ( filename + "PluginManager/Disabled/FakePatches/FakePatch_" + this->GetNameValidFile() + "_" + this->author() + "_" + pFile->GetName() );
1003
			else if ( pFile->IsAutoTextFile() )
1004
				pFile->SetFilename ( filename + "PluginManager/Disabled/TextFiles/Text_" + this->GetNameValidFile() + "_" + this->author() + "_" + pFile->GetName() );
1005
			else
1006
				pFile->SetFullDir ( filename + "PluginManager/Disabled/" + pFile->GetDirectory(this) );
1007
		}
1008
		pFile->SetDisabled(true);
1009
	}
1010
 
1011
	CLog::logf(CLog::Log_Install, 2, "Adjusting the file pointer to correct install destintation, %s", pFile->GetFilePointer().c_str());
1012
 
1013
	return filename.ToString();
1014
}
1015
 
1016
C_File *CBaseFile::_install_checkFile(C_File *pFile, CyStringList *errorStr, bool *bDoFile, CLinkList<C_File> *pFileList)
1017
{
1018
	if ( !pFile->IsFakePatch() && pFile->GetFileType() != FILETYPE_README )
1019
	{
1020
		C_File *cFile;
1021
		for ( cFile = pFileList->First(); cFile; cFile = pFileList->Next() )
1022
		{
1023
			if ( !cFile->MatchFile(pFile) ) continue;
1024
			if ( !m_bOverrideFiles && !cFile->CompareNew(pFile) ) {
1025
				if ( errorStr ) errorStr->PushBack(pFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_SKIPFILE));
1026
				CLog::log(CLog::Log_Install, 1, "Newer version of the file already installed, skipping");
1027
				*bDoFile = false;
1028
			}
1029
			break;
1030
		}
1031
 
1032
		return cFile;
1033
	}
1034
 
1035
	return NULL;
1036
}
1037
 
1038
bool CBaseFile::_install_checkFileEnable(C_File *pCheckFile, C_File *fit, const Utils::String &sDestination, bool bEnabled, CyStringList *errorStr)
1039
{
1040
	// found a file, check if its in the disabled directory
125 cycrow 1041
	Utils::String dir = CFileIO(pCheckFile->filePointer()).dir();
1042
	Utils::String lastDir = CDirIO(dir).topDir().lower();
50 cycrow 1043
 
1044
	// if its disabled, rename it so its enabled
125 cycrow 1045
	if ( ((pCheckFile->IsDisabled()) || (lastDir == "disabled") || (dir.lower().isin("/disabled/"))) && (bEnabled) )
50 cycrow 1046
	{
125 cycrow 1047
		CLog::logf(CLog::Log_Install, 2, "Existing file, %s, is disabled, re-enabling it", pCheckFile->filePointer().c_str());
50 cycrow 1048
		// first check if the directory exists
1049
		if ( pCheckFile->IsInMod() ) {
125 cycrow 1050
			CyString tofile = pCheckFile->filePointer().token("::", 2);
50 cycrow 1051
 
1052
			CCatFile tocat;
125 cycrow 1053
			int err = tocat.open(fit->filePointer().token("::", 1), "", CATREAD_CATDECRYPT, true);
50 cycrow 1054
			if ( (err == CATERR_NONE) || (err == CATERR_CREATED) ) {
52 cycrow 1055
				tocat.AppendFile(pCheckFile->GetFilePointer().ToString(), tofile.ToString());
125 cycrow 1056
				CLog::logf(CLog::Log_Install, 2, "Adding existing file into new mod File, %s => %s", fit->filePointer().token("::", 1).c_str(), tofile.c_str());
50 cycrow 1057
			}
1058
 
1059
			CCatFile fromcat;
125 cycrow 1060
			err = fromcat.open(pCheckFile->filePointer().token("::", 1), "", CATREAD_CATDECRYPT, false);
50 cycrow 1061
			if ( err == CATERR_NONE ) {
124 cycrow 1062
				fromcat.removeFile(tofile.ToString());
125 cycrow 1063
				CLog::logf(CLog::Log_Install, 2, "Removing file from existing mod, %s::%s", pCheckFile->filePointer().token("::", 1).c_str(), tofile.c_str());
50 cycrow 1064
			}
1065
 
125 cycrow 1066
			CLog::logf(CLog::Log_Install, 1, "Adjusting existing file name %s => %s", pCheckFile->filePointer().c_str(), fit->filePointer().c_str());
50 cycrow 1067
			pCheckFile->SetFilename ( fit->GetFilePointer() );
1068
			CLog::logf(CLog::Log_Install, 2, "Adjusting In Mod setting, %s => %s", pCheckFile->GetInMod().c_str(), fit->GetInMod().c_str());
1069
			pCheckFile->SetInMod(fit->GetInMod());
1070
		}
1071
		else {
1072
			CyString to = pCheckFile->GetDirectory(this);
1073
			CDirIO Dir(sDestination);
121 cycrow 1074
			if ( !Dir.exists(to.ToString()) ) {
50 cycrow 1075
				if ( !Dir.Create ( to ) ) {
1076
					if ( errorStr )	errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1077
					return false;
1078
				}
1079
				if ( errorStr )	errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1080
			}
1081
 
1082
			CyString destfile = CyString(sDestination) + "/" + pCheckFile->GetNameDirectory(this);
52 cycrow 1083
			if ( CFileIO(destfile).ExistsOld() ) CFileIO::Remove(destfile.ToString());
50 cycrow 1084
			CLog::logf(CLog::Log_Install, 1, "Adjusting existing filename, %s => %s", pCheckFile->GetFilePointer().c_str(), destfile.c_str());
1085
			rename ( pCheckFile->GetFilePointer().c_str(), destfile.c_str() );
1086
			pCheckFile->SetFilename ( CyString(sDestination) + "/" + pCheckFile->GetNameDirectory(this) );
1087
		}
1088
		pCheckFile->SetDisabled(false);
1089
 
1090
		if ( errorStr ) errorStr->PushBack(pCheckFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));
1091
	}
1092
 
1093
	return true;
1094
}
51 cycrow 1095
 
1096
bool CBaseFile::_install_createDirectory(CDirIO &Dir, const Utils::String &sTo, C_File *pFile, CyStringList *errorStr)
1097
{
1098
	m_sLastError = sTo;
1099
	if ( !sTo.isin ( "::" ) )
1100
	{
121 cycrow 1101
		if ( !Dir.exists(sTo) )
51 cycrow 1102
		{
1103
			CLog::logf(CLog::Log_Install, 2, "Creating directory to install file into, %s", sTo.c_str());
1104
			if ( !Dir.Create(sTo) )
1105
			{
1106
				if ( errorStr )
1107
					errorStr->PushBack(CyString(sTo), ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1108
				return false;
1109
			}
1110
			if ( errorStr )
1111
				errorStr->PushBack(CyString(sTo), ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1112
		}
1113
	}
1114
	else {
124 cycrow 1115
		CLog::logf(CLog::Log_Install, 2, "Adjusting file extension for file in mod, %s => %s", pFile->GetFilePointer().c_str(), CCatFile::PckChangeExtension(pFile->GetFilePointer().ToString()).c_str());
1116
		pFile->SetFilename(CCatFile::PckChangeExtension(pFile->GetFilePointer().ToString()));
51 cycrow 1117
	}
1118
 
1119
	return true;
1120
}
1121
 
1122
void CBaseFile::_install_writeFile(C_File *pFile, const Utils::String &sDestination, CyStringList *errorStr)
1123
{
1124
	m_iLastError = SPKERR_WRITEFILE;
1125
	m_sLastError = pFile->GetFilePointer();
1126
	CyString sInstalledFile = pFile->GetNameDirectory(this);
1127
	if ( pFile->IsDisabled() )
1128
	{
1129
		sInstalledFile = pFile->GetFilePointer().Remove(sDestination);
1130
		if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )
1131
			sInstalledFile.Erase(0, 1);
1132
	}
1133
 
1134
	if ( !pFile->WriteFilePointer() )
1135
	{
1136
		CLog::log(CLog::Log_Install, 1, "Failed to write the file");
1137
		if ( errorStr )
1138
			errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));
1139
	}
1140
	else
1141
	{
1142
		CLog::log(CLog::Log_Install, 1, "File written successfully");
1143
		CLog::log(CLog::Log_Install, 2, "Checking signed status of the file");
1144
		pFile->UpdateSigned();
1145
		if ( errorStr )
1146
			errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));
1147
 
1148
		switch(pFile->GetFileType())
1149
		{
1150
			case FILETYPE_SCRIPT:
1151
			case FILETYPE_UNINSTALL:
1152
				CLog::log(CLog::Log_Install, 2, "Updating file signature");
1153
				pFile->UpdateSignature();
1154
				break;
1155
		}
1156
	}
1157
}
1158
 
43 cycrow 1159
bool CBaseFile::InstallFiles ( CyString destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, CyStringList *errorStr, bool enabled, CPackages *packages )
1160
{
50 cycrow 1161
	//TODO: add errorStr and progress as member variables
43 cycrow 1162
	if ( enabled ) {
14 cycrow 1163
		this->_install_adjustFakePatches(packages);
43 cycrow 1164
		if ( packages ) this->_install_renameText(packages);
6 cycrow 1165
	}
1166
 
50 cycrow 1167
	bool bFailed = false;
1168
 
6 cycrow 1169
	CDirIO Dir(destdir);
1170
	int fileCount = 0;
1171
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1172
	{
1173
		C_File *fit = node->Data();
1174
 
50 cycrow 1175
		// start the install process, check if we need to the file enabled or disabled
1176
		CLog::logf(CLog::Log_Install, 1, "Preparing to install file: %s", fit->GetNameDirectory(this).c_str());
1177
		bool fileEnabled = _install_setEnabled(enabled, fit);
1178
 
1179
		// check if the file is for the correct game version
6 cycrow 1180
		if ( fit->GetGame() && packages->GetGame() ) {
50 cycrow 1181
			if ( fit->GetGame() != packages->GetGame() ) {
1182
				CLog::logf(CLog::Log_Install, 1, "File didn't match game version, skipping, %d != %d", fit->GetGame(), packages->GetGame());
6 cycrow 1183
				continue;
50 cycrow 1184
			}
6 cycrow 1185
		}
1186
 
50 cycrow 1187
		// update the progress display to show we are processing this file
1188
		if ( progress ) {
1189
			if ( progress->IsSecond() ) progress->SwitchSecond();
6 cycrow 1190
			progress->UpdateFile ( fit );
1191
			progress->UpdateProgress(fileCount++, m_lFiles.size());
1192
			progress->SwitchSecond();
1193
		}
1194
 
1195
		// first uncompress the file
50 cycrow 1196
		//TODO: add this flag to C_File
1197
		bool uncomprToFile;
1198
		if ( !this->_install_uncompress(fit, progress, errorStr, &uncomprToFile) ) {
1199
			bFailed = true;
1200
			continue;
6 cycrow 1201
		}
1202
 
50 cycrow 1203
		bool dofile = _install_checkVersion(fit, destdir.ToString());
6 cycrow 1204
 
1205
		// change file pointer
125 cycrow 1206
		Utils::String sInstallDir = _install_adjustFilepointer(fit, fileEnabled, destdir.ToString());
6 cycrow 1207
 
1208
		C_File *adjustPointer = NULL;
1209
 
50 cycrow 1210
		if ( filelist ) {
98 cycrow 1211
			C_File *cFile = _install_checkFile(fit, errorStr, &dofile, filelist);
6 cycrow 1212
 
1213
			// no matching file found, adding to main list
50 cycrow 1214
			if ( !cFile ) filelist->push_back ( fit );
6 cycrow 1215
			else
1216
			{
1217
				// if the file is not enabled, we need to check for any that might be enabled
51 cycrow 1218
				if ( !fileEnabled ) //_install_checkDisabled(cFile, destdir, errorStr);
6 cycrow 1219
				{
50 cycrow 1220
					//TODO: check what this is actually doing
6 cycrow 1221
					if ( !cFile->GetUsed() )
1222
					{
1223
						CFileIO rFile(cFile->GetFilePointer());
52 cycrow 1224
						if ( rFile.exists() )
6 cycrow 1225
						{
1226
							if ( errorStr )
1227
							{
52 cycrow 1228
								if ( rFile.remove() )
6 cycrow 1229
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));
1230
								else
1231
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));
1232
							}
1233
						}
1234
						cFile->SetFilename(fit->GetFilePointer());
1235
						cFile->SetDisabled(true);
1236
					}
1237
					else
1238
					{
125 cycrow 1239
						fit->SetFullDir ( CyString(sInstallDir) + fit->GetDirectory(this) );
51 cycrow 1240
						fit->SetDisabled(false);
6 cycrow 1241
					}
1242
				}
1243
				// move it to enabled
50 cycrow 1244
				else {
1245
					if ( !this->_install_checkFileEnable(cFile, fit, destdir.ToString(), fileEnabled, errorStr) ) {
1246
						bFailed = true;
1247
						continue;
6 cycrow 1248
					}
1249
				}
1250
 
1251
				adjustPointer = cFile;
50 cycrow 1252
				if ( dofile ) adjustPointer->SetCreationTime(fit->GetCreationTime());
6 cycrow 1253
			}
1254
		}
1255
 
1256
		if ( dofile )
1257
		{
1258
			// uncompressed to file, rename and move
1259
			if ( uncomprToFile )
1260
			{
1261
				m_iLastError = SPKERR_WRITEFILE;
1262
				CyString to = fit->GetDirectory(this);
51 cycrow 1263
				if ( !fileEnabled )	to = CyString("PluginManager/Disabled/") + to;
6 cycrow 1264
 
51 cycrow 1265
				if ( !_install_createDirectory(Dir, to.ToString(), fit, errorStr) ) {
1266
					bFailed = true;
1267
					continue;
6 cycrow 1268
				}
1269
 
1270
				int err = 1;
1271
				m_sLastError = to;
51 cycrow 1272
				if ( !fit->GetTempFile ().Empty() )	err = rename ( fit->GetTempFile().c_str(), to.c_str() );
1273
				if ( err ) {
1274
					bFailed = true;
1275
					continue;
1276
				}
6 cycrow 1277
			}
1278
			//otherwise, just extract the file
1279
			else
1280
			{
1281
				// old file is found in list, switch to using new one
50 cycrow 1282
				if ( (filelist) && (adjustPointer) ) {
6 cycrow 1283
					adjustPointer->CopyData(fit, false);
50 cycrow 1284
					CLog::log(CLog::Log_Install, 2, "Copying data into existing file");
1285
				}
6 cycrow 1286
 
1287
				CyString fpointer = fit->GetFilePointer();
1288
				m_iLastError = SPKERR_CREATEDIRECTORY;
1289
				CyString dir = fit->GetFilePointer().GetToken ( "/", 1, fit->GetFilePointer().NumToken("/") - 1 );
1290
 
1291
				dir = dir.Remove(destdir);
51 cycrow 1292
				if ( dir[0] == '/' || dir[0] == '\\' ) dir.Erase(0, 1);
6 cycrow 1293
 
51 cycrow 1294
				if ( !_install_createDirectory(Dir, dir.ToString(), fit, errorStr) ) {
1295
					bFailed = true;
1296
					continue;
6 cycrow 1297
				}
1298
 
51 cycrow 1299
				_install_writeFile(fit, destdir.ToString(), errorStr);
6 cycrow 1300
			}
1301
			ClearError ();
1302
		}
1303
 
1304
		if ( adjustPointer )
1305
		{
50 cycrow 1306
			CLog::log(CLog::Log_Install, 2, "Adjusting pointers to existing file and deleting new file pointer");
6 cycrow 1307
			node->ChangeData(adjustPointer);
1308
			delete fit;
1309
		}
50 cycrow 1310
 
1311
		CLog::log(CLog::Log_Install, 1, "File installation completed");
6 cycrow 1312
	}
1313
 
1314
	// now clear or data memory
50 cycrow 1315
	CLog::log(CLog::Log_Install, 2, "Delting temporary file data from memory");
51 cycrow 1316
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) node->Data()->DeleteData();
6 cycrow 1317
 
50 cycrow 1318
	return !bFailed;
6 cycrow 1319
}
1320
 
1321
/*######################################################################################################*/
1322
 
1323
 
1324
/*
1325
	Func:   ParseHeader
1326
	Input:  Header String - string formated directly from the file
1327
	Return: Boolean - If string is a valid header
1328
	Desc:   Splits up the main header string to get all required settings
1329
*/
1330
bool CBaseFile::ParseHeader ( CyString header )
1331
{
14 cycrow 1332
	if ( !this->CheckHeader(header.GetToken ( 1, ';' ).ToString()) )
6 cycrow 1333
		return false;
1334
 
1335
	m_SHeader.fVersion = header.GetToken ( 2, ';' ).ToFloat();
1336
	if ( m_SHeader.fVersion > FILEVERSION )
1337
		return false;
1338
 
1339
	m_SHeader.iValueCompression = header.GetToken ( 3, ';' ).ToInt();
1340
	m_SHeader.lValueCompressSize = header.GetToken ( 4, ';' ).ToLong();
1341
 
1342
	return true;
1343
}
1344
 
14 cycrow 1345
bool CBaseFile::CheckHeader(const Utils::String header) const
6 cycrow 1346
{
1347
	if ( header.Compare("BaseCycrow") )
1348
		return true;
1349
	return false;
1350
}
1351
 
1352
/*
1353
	Func:   ParseFileHeader
1354
	Input:  Header String - string formated directly from the file
1355
	Return: Boolean - If string is a valid header
1356
	Desc:   Splits up the file header string to get all required settings
1357
*/
1358
bool CBaseFile::ParseFileHeader ( CyString header )
1359
{
1360
	if ( header.GetToken ( 1, ';' ) != "FileHeader" )
1361
		return false;
1362
 
1363
	m_SHeader2.iNumFiles = header.GetToken ( 2, ';' ).ToInt();
1364
	m_SHeader2.lSize = header.GetToken ( 3, ';' ).ToInt();
1365
	m_SHeader2.lFullSize = header.GetToken ( 4, ';' ).ToInt();
1366
	m_SHeader2.iFileCompression = header.GetToken ( 5, ';' ).ToInt();
1367
	m_SHeader2.iDataCompression = header.GetToken ( 6, ';' ).ToInt();
1368
 
1369
	return true;
1370
}
1371
 
1372
 
1373
/*
1374
	Func:   ParseValueLine
1375
	Input:  String - single line from a file to set
1376
	Return: Boolean - returns true if value exists
1377
	Desc:   Reads the line and assigns the parameters for the file
1378
*/
14 cycrow 1379
bool CBaseFile::ParseValueLine(const Utils::String &sLine)
6 cycrow 1380
{
14 cycrow 1381
	Utils::String first = sLine.token(" ", 1);
1382
	Utils::String rest  = sLine.tokens(" ", 2);
6 cycrow 1383
 
50 cycrow 1384
	if ( first.Compare("Name:") )					this->setName(rest);
1385
	else if ( first.Compare("Author:") )			this->setAuthor(rest);
1386
	else if ( first.Compare("Version:") )			this->setVersion(rest);
14 cycrow 1387
	else if ( first.Compare("fGameVersion:") ) {
6 cycrow 1388
		if ( m_lGames.Back() ) {
1389
			m_lGames.Back()->Data()->sVersion = rest;
1390
		}
1391
	}
14 cycrow 1392
	else if ( first.Compare("GameVersion:") ) {
6 cycrow 1393
		if ( m_lGames.Back() ) {
14 cycrow 1394
			m_lGames.Back()->Data()->iVersion = rest;
6 cycrow 1395
		}
1396
	}
14 cycrow 1397
	else if ( first.Compare("Game:") )
46 cycrow 1398
		this->AddGameCompatability(rest, "");
14 cycrow 1399
	else if ( first.Compare("GameCompat:") )
1400
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
1401
	else if ( first.Compare("GameCompatExact:") )
1402
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
50 cycrow 1403
	else if ( first.Compare("Date:") )				this->setCreationDate(rest);
49 cycrow 1404
	else if ( first.Compare("WebAddress:") )		this->setWebAddress(rest);
1405
	else if ( first.Compare("WebSite:") )			this->setWebSite(rest);
1406
	else if ( first.Compare("Email:") )				this->setEmail(rest);
14 cycrow 1407
	else if ( first.Compare("WebMirror1:") || first.Compare("Mirror1:") || first.Compare("WebMirror:") )
6 cycrow 1408
		this->AddWebMirror(rest);
14 cycrow 1409
	else if ( first.Compare("WebMirror2:") || first.Compare("Mirror2:") )
6 cycrow 1410
		this->AddWebMirror(rest);
48 cycrow 1411
	else if ( first.Compare("PluginType:") )		this->setPluginType(rest);
1412
	else if ( first.Compare("Desc:") )				this->setDescription(rest);
1413
	else if ( first.Compare("UninstallAfter:") )	this->addUninstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));
1414
	else if ( first.Compare("UninstallBefore:") )	this->addUninstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));
1415
	else if ( first.Compare("InstallAfter:") )		this->addInstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));
1416
	else if ( first.Compare("InstallBefore:") )		this->addInstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));
14 cycrow 1417
	else if ( first.Compare("ScriptName:") )
1418
		AddLanguageName(ParseLanguage(rest.token(":", 1)), rest.token(":", 2));
48 cycrow 1419
	else if ( first.Compare("GameChanging:") )		this->setGameChanging(rest);
1420
	else if ( first.Compare("EaseOfUse:") )			this->setEaseOfUse(rest);
1421
	else if ( first.Compare("Recommended:") )		this->setRecommended(rest);
14 cycrow 1422
	else if ( first.Compare("NeededLibrary:") )
1423
		this->AddNeededLibrary(rest.token("||", 1), rest.token("||", 2), rest.token("||", 3));
1424
	else if ( first.Compare("FakePatchBefore:") )
1425
		this->AddFakePatchOrder(false, rest.token("||", 1), rest.token("||", 2));
1426
	else if ( first.Compare("FakePatchAfter:") )
1427
		this->AddFakePatchOrder(true, rest.token("||", 1), rest.token("||", 2));
49 cycrow 1428
	else if ( first.Compare("ForumLink:") )			this->setForumLink(rest);
6 cycrow 1429
	else
1430
		return false;
1431
 
1432
	return true;
1433
}
1434
 
48 cycrow 1435
int CBaseFile::ParseLanguage(const Utils::String &lang) const
6 cycrow 1436
{
48 cycrow 1437
	int langID = lang;
1438
	if ( !langID ) {
1439
		if ( lang.Compare("english") )		return 44;
1440
		else if ( lang.Compare("default") )	return 0;
1441
		else if ( lang.Compare("german") )	return 49;
1442
		else if ( lang.Compare("russian") )	return 7;
1443
		else if ( lang.Compare("spanish") )	return 34;
1444
		else if ( lang.Compare("french") )	return 33;
6 cycrow 1445
	}
1446
 
1447
	return langID;
1448
}
1449
 
1450
/*
1451
	Func:   ReadValues
1452
	Input:  String - values in one long line
1453
	Desc:   splits the values data into each line to read the data
1454
*/
1455
void CBaseFile::ReadValues ( CyString values )
1456
{
1457
	int num = 0;
1458
	CyString *lines = values.SplitToken ( '\n', &num );
1459
 
1460
	for ( int i = 0; i < num; i++ )
14 cycrow 1461
		ParseValueLine ( lines[i].ToString() );
6 cycrow 1462
 
1463
	CLEANSPLIT(lines, num)
1464
}
1465
 
1466
/*
1467
	Func:   ParseFilesLine
1468
	Input:  String - single line from a file to set
1469
	Return: Boolean - returns true if value exists
1470
	Desc:   Reads the line and assigns the parameters for the file
1471
*/
127 cycrow 1472
bool CBaseFile::ParseFilesLine ( CyString sLine )
6 cycrow 1473
{
127 cycrow 1474
	Utils::String line = sLine.ToString();
1475
 
1476
	if ( !line.contains(":") )
6 cycrow 1477
		return false;
1478
 
127 cycrow 1479
	Utils::String command = line.token(":", 1);
6 cycrow 1480
 
127 cycrow 1481
	long size = line.token(":", 2).toInt();
1482
	long usize = line.token(":", 3).toInt ();
1483
	long compression = line.token(":", 4).toInt ();
6 cycrow 1484
 
1485
	if ( command == "Icon" )
1486
	{
127 cycrow 1487
		m_sIconExt = line.token (":", 5);
6 cycrow 1488
		m_pIconFile = new C_File ();
1489
		m_pIconFile->SetDataSize ( size - 4 );
1490
		m_pIconFile->SetDataCompression ( compression );
1491
		m_pIconFile->SetUncompressedDataSize ( usize );
1492
 
1493
		return true;
1494
	}
1495
 
127 cycrow 1496
	time_t time = line.token(":", 5).toLong();
1497
	bool compressToFile = (line.token(":", 6).toInt() == 1) ? true : false;
1498
	Utils::String name  = line.token(":", 7);
1499
	Utils::String dir = line.token(":", 8);
6 cycrow 1500
 
127 cycrow 1501
	if ( name.empty() )
6 cycrow 1502
		return true;
1503
 
1504
	bool shared = false;
127 cycrow 1505
	if ( command.left(1) == "$" )
6 cycrow 1506
	{
1507
		shared = true;
127 cycrow 1508
		command.erase(0, 1);
6 cycrow 1509
	}
1510
 
127 cycrow 1511
	FileType type = FILETYPE_UNKNOWN;
6 cycrow 1512
	if ( command == "Script" )
1513
		type = FILETYPE_SCRIPT;
1514
	else if ( command == "Text" )
1515
		type = FILETYPE_TEXT;
1516
	else if ( command == "Readme" )
1517
		type = FILETYPE_README;
1518
	else if ( command == "Map" )
1519
		type = FILETYPE_MAP;
1520
	else if ( command == "Mod" )
1521
		type = FILETYPE_MOD;
1522
	else if ( command == "Uninstall" )
1523
		type = FILETYPE_UNINSTALL;
1524
	else if ( command == "Sound" )
1525
		type = FILETYPE_SOUND;
1526
	else if ( command == "Mission" )
1527
		type = FILETYPE_MISSION;
1528
	else if ( command == "Extra" )
1529
		type = FILETYPE_EXTRA;
1530
	else if ( command == "Screen" )
1531
		type = FILETYPE_SCREEN;
1532
	else if ( command == "Backup" )
1533
		type = FILETYPE_BACKUP;
1534
	else if ( command == "Advert" )
1535
		type = FILETYPE_ADVERT;
1536
	else if ( command == "ShipScene" )
1537
		type = FILETYPE_SHIPSCENE;
1538
	else if ( command == "CockpitScene" )
1539
		type = FILETYPE_COCKPITSCENE;
1540
	else if ( command == "ShipOther" )
1541
		type = FILETYPE_SHIPOTHER;
1542
	else if ( command == "ShipModel" )
1543
		type = FILETYPE_SHIPMODEL;
1544
 
127 cycrow 1545
	if (type == FILETYPE_UNKNOWN)
6 cycrow 1546
		return false;
1547
 
127 cycrow 1548
	C_File *file = new C_File();
6 cycrow 1549
 
127 cycrow 1550
	if (dir.left(5).Compare("GAME_")) {
1551
		file->setGame(1 << 31 | 1 << dir.token("_", 2).toInt());
1552
		dir = Utils::String::Null();
6 cycrow 1553
	} 
127 cycrow 1554
	else if ( line.countToken(":") >= 9 ) 
1555
	{
1556
		Utils::String game = line.token(":", 9);
1557
		if (game.contains("_"))
1558
			file->setGame(1 << 31 | 1 << game.token("_", 2).toInt());
1559
		else
1560
		{
1561
			int iGame = game.toInt();
1562
			if (iGame & (1 << 31))
1563
				file->setGame(iGame);
1564
			else
1565
				file->setGame(1 << 31 | 1 << iGame);
1566
		}
6 cycrow 1567
	}
1568
 
127 cycrow 1569
	if (dir.Compare("NULL")) {
1570
		dir = Utils::String::Null();
1571
	}
1572
 
1573
	file->setFileType(type);
6 cycrow 1574
	file->SetCreationTime ( time );
1575
	file->SetName ( name );
1576
	file->SetDir ( dir );
1577
	file->SetDataSize ( size - 4 );
1578
	file->SetDataCompression ( compression );
1579
	file->SetUncompressedDataSize ( usize );
1580
	file->SetShared ( shared );
1581
	file->SetCompressedToFile ( compressToFile );
1582
 
88 cycrow 1583
	_addFile(file, true);
6 cycrow 1584
 
1585
	return true;
1586
}
1587
 
1588
 
1589
/*
1590
	Func:   ParseFiles
1591
	Input:  String - values in one long line
1592
	Desc:   splits the files data into each line to read the data
1593
*/
1594
void CBaseFile::ReadFiles ( CyString values )
1595
{
1596
	int num = 0;
1597
	CyString *lines = values.SplitToken ( '\n', &num );
1598
 
1599
	for ( int i = 0; i < num; i++ )
1600
		ParseFilesLine ( lines[i] );
1601
 
1602
	CLEANSPLIT(lines, num)
1603
}
1604
 
1605
 
1606
 
1607
/*
1608
	Func:   ReadFile
1609
	Input:  filename - the name of the file to open and read
1610
			readdata - If falses, dont read the files to memory, just read the headers and values
1611
	Return: boolean - return ture if acceptable format
1612
	Desc:   Opens and reads the spk file and loads all data into class
1613
*/
1614
bool CBaseFile::ReadFile ( CyString filename, int readtype, CProgressInfo *progress )
1615
{
58 cycrow 1616
	CFileIO File(filename.ToString());
1617
	if ( !File.startRead() ) return false;
6 cycrow 1618
 
58 cycrow 1619
	bool ret = this->readFile(File, readtype, progress);
50 cycrow 1620
	if ( ret ) this->setFilename(filename.ToString());
6 cycrow 1621
 
58 cycrow 1622
	File.close();
6 cycrow 1623
	return ret;
1624
}
51 cycrow 1625
 
109 cycrow 1626
int CBaseFile::_read_Header(CFileIO &File, int iReadType, int iMaxProgress, CProgressInfo *pProgress)
6 cycrow 1627
{
51 cycrow 1628
	int doneLen = 0;
6 cycrow 1629
 
51 cycrow 1630
	// read data to memory
1631
	unsigned char *readData;
1632
	try {
1633
		readData = new unsigned char[m_SHeader.lValueCompressSize];
1634
	}
1635
	catch (std::exception &e) {
1636
		CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [header], %d (%s)", m_SHeader.lValueCompressSize, e.what());
1637
		return -1;
1638
	}
6 cycrow 1639
 
51 cycrow 1640
	unsigned char size[4];
109 cycrow 1641
	File.read(size, 4);
1642
	File.read(readData, m_SHeader.lValueCompressSize);
6 cycrow 1643
 
51 cycrow 1644
	unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
6 cycrow 1645
 
51 cycrow 1646
	// check for zlib compression
1647
	if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ) {
1648
		// uncomress the data
1649
		try {
6 cycrow 1650
			unsigned char *uncompr = new unsigned char[uncomprLen];
1651
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );
1652
			// update the progress for each section
51 cycrow 1653
			if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);
1654
			if ( err == Z_OK ) this->ReadValues ( CyString ((char *)uncompr) );
6 cycrow 1655
			doneLen = uncomprLen;
1656
			delete uncompr;
1657
		}
51 cycrow 1658
		catch (std::exception &e) {
1659
			CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());
53 cycrow 1660
			delete []readData;
51 cycrow 1661
			return -1;
6 cycrow 1662
		}
51 cycrow 1663
	}
1664
	else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP ) {
1665
		long len = uncomprLen;
1666
		unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lValueCompressSize, (size_t*)&len, NULL );
1667
		// update the progress for each section
1668
		if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);
6 cycrow 1669
 
51 cycrow 1670
		if ( compr ) ReadValues ( CyString ((char *)compr) );
6 cycrow 1671
	}
51 cycrow 1672
	// no compression
1673
	else
1674
		ReadValues ( CyString ((char *)readData) );
6 cycrow 1675
 
53 cycrow 1676
	delete []readData;
6 cycrow 1677
 
51 cycrow 1678
	return doneLen;
1679
}
6 cycrow 1680
 
109 cycrow 1681
int CBaseFile::_read_FileHeader(CFileIO &File, int iReadType, int iMaxProgress, int iDoneLen, CProgressInfo *pProgress)
51 cycrow 1682
{
1683
	unsigned char *readData;
1684
	try {
1685
		readData = new unsigned char[m_SHeader2.lSize];
1686
	}
1687
	catch (std::exception &e) {
1688
		CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [header], %d (%s)", m_SHeader2.lSize, e.what());
1689
		return -1;
1690
	}
6 cycrow 1691
 
51 cycrow 1692
	unsigned char size[4];
109 cycrow 1693
	File.read(size, 4);
1694
	File.read(readData, m_SHeader2.lSize);
6 cycrow 1695
 
51 cycrow 1696
	unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
6 cycrow 1697
 
51 cycrow 1698
	// check for zlib compression
1699
	if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ) {
1700
		if ( uncomprLen < (unsigned long)iDoneLen ) uncomprLen = iDoneLen;
6 cycrow 1701
 
51 cycrow 1702
		try {
6 cycrow 1703
			unsigned char *uncompr = new unsigned char[uncomprLen];
1704
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );
1705
			// update the progress for each section
51 cycrow 1706
			if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);
1707
			if ( err == Z_OK ) ReadFiles ( CyString ((char *)uncompr) );
6 cycrow 1708
			delete uncompr;
1709
		}
51 cycrow 1710
		catch (std::exception &e) {
1711
			CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());
53 cycrow 1712
			delete []readData;
51 cycrow 1713
			return -1;
6 cycrow 1714
		}
1715
 
1716
	}
51 cycrow 1717
	else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
1718
	{
1719
		long len = uncomprLen;
1720
		unsigned char *compr = LZMADecode_C ( readData, m_SHeader2.lSize, (size_t*)&len, NULL );
1721
		// update the progress for each section
1722
		if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);
1723
		if ( compr ) ReadFiles ( CyString ((char *)compr) );
1724
	}
1725
	else
1726
		ReadFiles ( CyString ((char *)readData) );
6 cycrow 1727
 
53 cycrow 1728
	delete []readData;
51 cycrow 1729
	return true;
1730
}
1731
 
58 cycrow 1732
bool CBaseFile::readFile(CFileIO &File, int readtype, CProgressInfo *progress)
51 cycrow 1733
{
1734
	ClearError ();
1735
 
1736
	// first read the header
58 cycrow 1737
	if ( !ParseHeader(File.readEndOfLine()) ) return false;
51 cycrow 1738
	if ( readtype == SPKREAD_HEADER ) return true;
1739
 
1740
	// update the progress for each section
1741
	int maxProgress = (readtype == SPKREAD_VALUES) ? 3 : 6;
1742
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(1, maxProgress);
1743
 
1744
	long doneLen = 0;
1745
	// next read the data values for the spk files
109 cycrow 1746
	if ( m_SHeader.lValueCompressSize ) doneLen = this->_read_Header(File, readtype, maxProgress, progress);
51 cycrow 1747
 
1748
	// update the progress for each section
1749
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(3, maxProgress);
1750
	if ( readtype == SPKREAD_VALUES ) return true;
1751
 
1752
	// next should be the next header
58 cycrow 1753
	if ( !ParseFileHeader(File.readEndOfLine()) ) return false;
51 cycrow 1754
 
1755
	// clear the current file list
1756
	m_lFiles.clear(true);
88 cycrow 1757
	if ( _pTextDB ) {
1758
		delete _pTextDB;
1759
		_pTextDB = NULL;
1760
	}
51 cycrow 1761
 
1762
	// update the progress for each section
1763
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(4, maxProgress);
1764
 
109 cycrow 1765
	if ( m_SHeader2.lSize ) this->_read_FileHeader(File, readtype, maxProgress, doneLen, progress);
51 cycrow 1766
 
6 cycrow 1767
	// file mismatch
1768
	long numfiles = m_lFiles.size();
51 cycrow 1769
	if ( m_pIconFile ) ++numfiles;
1770
	if ( m_SHeader2.iNumFiles != numfiles ) {
6 cycrow 1771
		m_iLastError = SPKERR_FILEMISMATCH;
1772
		return false;
1773
	}
1774
 
1775
	// update the progress for each section
51 cycrow 1776
	if ( readtype != SPKREAD_ALL && progress )	progress->UpdateProgress(6, maxProgress);
6 cycrow 1777
 
51 cycrow 1778
	if ( readtype == SPKREAD_ALL ) {
6 cycrow 1779
		int fileCount = 2;
58 cycrow 1780
		if ( m_pIconFile ) m_pIconFile->readFromFile(File, m_pIconFile->GetDataSize());
6 cycrow 1781
 
51 cycrow 1782
		// ok finally we need to read all the file
1783
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
58 cycrow 1784
			node->Data()->readFromFile(File, node->Data()->GetDataSize());
51 cycrow 1785
			if ( progress )	progress->UpdateProgress(fileCount++, m_lFiles.size() + 2);
6 cycrow 1786
		}
1787
 
1788
		m_bFullyLoaded = true;
1789
	}
1790
 
1791
	return true;
1792
}
1793
 
1794
bool CBaseFile::IsMod()
1795
{
1796
	// check for any mod files that are not fake patchs
1797
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
1798
	{
1799
		C_File *f = fNode->Data();
1800
		if ( f->GetFileType() != FILETYPE_MOD )
1801
			continue;
1802
 
1803
		if ( !f->IsFakePatch() )
1804
			return true;
1805
	}
1806
 
1807
	return false;
1808
}
1809
 
13 cycrow 1810
bool CBaseFile::IsFakePatch() const
6 cycrow 1811
{
1812
	// check for any mod files that are not fake patchs
1813
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
1814
	{
1815
		C_File *f = fNode->Data();
1816
		if ( f->GetFileType() != FILETYPE_MOD )
1817
			continue;
1818
 
1819
		if ( f->IsFakePatch() )
1820
			return true;
1821
	}
1822
 
1823
	return false;
1824
}
1825
 
14 cycrow 1826
Utils::String CBaseFile::CreateValuesLine () const
6 cycrow 1827
{
14 cycrow 1828
	Utils::String values("Name: ");
50 cycrow 1829
	values += this->name() + "\n";
1830
	values += "Author: " + this->author() + "\n";
1831
	values += "Version: " + this->version() + "\n";
1832
	if ( !this->creationDate().empty() )values += "Date: "			+ this->creationDate()	+ "\n";
49 cycrow 1833
	if ( !this->webAddress().empty() )	values += "WebAddress: "	+ this->webAddress()	+ "\n";
1834
	if ( !this->webSite().empty() )		values += "WebSite: "		+ this->webSite()		+ "\n";
1835
	if ( !this->email().empty() )		values += "Email: "			+ this->email()			+ "\n";
1836
	if ( !this->forumLink().empty() )	values += "ForumLink: "		+ this->forumLink()		+ "\n";
1837
 
6 cycrow 1838
	for ( SStringList *str = m_lMirrors.Head(); str; str = str->next )
14 cycrow 1839
		values += Utils::String("WebMirror: ") + str->str.ToString() + "\n";
48 cycrow 1840
	if ( !this->description().empty() ) {
1841
		Utils::String desc = this->description();
14 cycrow 1842
		desc = desc.findReplace("<newline>", "<br>");
1843
		desc = desc.findReplace("\n", "<br>");
1844
		desc.remove('\r');
1845
		values += "Desc: " + desc + "\n";
6 cycrow 1846
	}
1847
 
1848
	for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {
46 cycrow 1849
		if ( !gc->Data()->sVersion.empty() )
1850
			values += Utils::String("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion + "\n";
6 cycrow 1851
		else
14 cycrow 1852
			values += Utils::String("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";
6 cycrow 1853
	}
1854
 
1855
	if ( m_bSigned )
1856
		values += "Signed\n";
1857
 
46 cycrow 1858
	for ( int j = 0; j < 2; j++ ) {
1859
		const CInstallText *text;
1860
		Utils::String textStart;
1861
		switch(j) {
1862
			case 0:	textStart = "Uninstall"; text = this->uninstallText(); break;
1863
			case 1: textStart = "Install"; text = this->installText(); break;
1864
		}
1865
		for ( unsigned int i = 0; i < text->count(); i++ ) {
1866
			int iLang = text->language(i);
1867
			if ( !text->getBefore(iLang).empty() ) values += textStart + "Before: " + (long)iLang + "|" + text->getBefore(iLang) + "\n";
1868
			if ( !text->getAfter(iLang).empty() ) values += textStart + "After: " + (long)iLang + "|" + text->getAfter(iLang) + "\n";
1869
		}
6 cycrow 1870
	}
1871
 
46 cycrow 1872
	values += Utils::String("GameChanging: ") + (long)gameChanging() + "\n";
1873
	values += Utils::String("EaseOfUse: ") + (long)easeOfUse() + "\n";
1874
	values += Utils::String("Recommended: ") + (long)recommended() + "\n";
6 cycrow 1875
 
14 cycrow 1876
	for ( CListNode<SNames> *nNode = m_lNames.Front(); nNode; nNode = nNode->next() )
46 cycrow 1877
		values += Utils::String("ScriptName: ") + (long)nNode->Data()->iLanguage + ":" + nNode->Data()->sName + "\n";
6 cycrow 1878
 
14 cycrow 1879
	for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() ) {
6 cycrow 1880
		SNeededLibrary *l = libNode->Data();
14 cycrow 1881
		values += (CyString("NeededLibrary: ") + l->sName + "||" + l->sAuthor + "||" + l->sMinVersion + "\n").ToString();
6 cycrow 1882
	}
1883
 
1884
	for ( SStringList *fpbNode = m_lFakePatchBefore.Head(); fpbNode; fpbNode = fpbNode->next )
14 cycrow 1885
		values += (CyString("FakePatchBefore: ") + fpbNode->str + "||" + fpbNode->data + "\n").ToString();
6 cycrow 1886
	for ( SStringList *fpaNode = m_lFakePatchAfter.Head(); fpaNode; fpaNode = fpaNode->next )
14 cycrow 1887
		values += (CyString("FakePatchAfter: ") + fpaNode->str + "||" + fpaNode->data + "\n").ToString();
6 cycrow 1888
 
48 cycrow 1889
	values += Utils::String("PluginType: ") + (long)this->pluginType() + "\n";
6 cycrow 1890
 
1891
	return values;
1892
}
1893
 
1894
 
1895
/*
1896
	Func:   WriteFile
1897
	Input:  filename - The filename of the spk file to write to
1898
	Desc:   Writes the data to an spk file
1899
*/
1900
bool CBaseFile::WriteFile ( CyString filename, CProgressInfo *progress )
1901
{
52 cycrow 1902
	CFileIO File(filename);
1903
	if ( File.startWrite() ) return WriteData(File, progress);
1904
	return false;
6 cycrow 1905
}
1906
 
52 cycrow 1907
bool CBaseFile::WriteHeader(CFileIO &file, int valueheader, int valueComprLen)
6 cycrow 1908
{
52 cycrow 1909
	return file.write("BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);
6 cycrow 1910
}
1911
 
52 cycrow 1912
bool CBaseFile::WriteData(CFileIO &file, CProgressInfo *progress )
6 cycrow 1913
{
1914
	int valueheader = m_SHeader.iValueCompression, fileheader = m_SHeader.iValueCompression;
1915
	if ( valueheader == SPKCOMPRESS_7ZIP )
1916
		valueheader = SPKCOMPRESS_ZLIB;
1917
	if ( fileheader == SPKCOMPRESS_7ZIP )
1918
		fileheader = SPKCOMPRESS_ZLIB;
1919
 
1920
	// get the script values
1921
	this->UpdateSigned(true);
1922
	CyString values = this->CreateValuesLine();
1923
 
1924
	// compress the values
1925
	int valueUncomprLen = (int)values.Length();
1926
	unsigned long valueComprLen = 0;
1927
	unsigned char *valueCompr = NULL;
1928
	bool compressed = false;
1929
	if ( valueheader == SPKCOMPRESS_ZLIB )
1930
	{
1931
		valueComprLen = valueUncomprLen;
1932
		if ( valueComprLen < 100 )
1933
			valueComprLen = 200;
1934
		else if ( valueComprLen < 1000 )
1935
			valueComprLen *= 2;
1936
 
1937
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
1938
		int err = compress ( (unsigned char *)valueCompr, &valueComprLen, (const unsigned char *)values.c_str(), (unsigned long)values.Length(), 0 );
1939
		if ( err == Z_OK )
1940
			compressed = true;
1941
	}
1942
 
1943
	if ( !compressed )
1944
	{
1945
		valueComprLen = valueUncomprLen;
1946
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
1947
		memcpy ( valueCompr, values.c_str(), valueComprLen );
1948
		valueheader = SPKCOMPRESS_NONE;
1949
	}
1950
 
1951
	// write the main header to the file
52 cycrow 1952
	if ( !this->WriteHeader(file, valueheader, valueComprLen) )	return false;
6 cycrow 1953
 
1954
	// write the compressed data to file
52 cycrow 1955
	file.put(static_cast<unsigned char>(valueUncomprLen >> 24));
1956
	file.put(static_cast<unsigned char>(valueUncomprLen >> 16));
1957
	file.put(static_cast<unsigned char>(valueUncomprLen >> 8));
1958
	file.put(static_cast<unsigned char>(valueUncomprLen));
1959
	file.write(valueCompr, valueComprLen);
6 cycrow 1960
	free ( valueCompr );
1961
 
1962
	// now compress the files header
1963
	// create the files values
1964
	CyString files = CreateFilesLine ( true, progress );
1965
 
1966
	// compress the files values
1967
	long fileUncomprLen = (long)files.Length(), fileComprLen = fileUncomprLen;
1968
	unsigned char *fileCompr = NULL;
1969
 
1970
	compressed = false;
1971
	if ( fileUncomprLen )
1972
	{
1973
		if ( fileheader == SPKCOMPRESS_ZLIB )
1974
		{
1975
			if ( fileComprLen < 100 )
1976
				fileComprLen = 200;
1977
			else if ( fileComprLen < 1000 )
1978
				fileComprLen *= 2;
1979
			fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
1980
			int err = compress ( (unsigned char *)fileCompr, (unsigned long *)&fileComprLen, (const unsigned char *)files.c_str(), (unsigned long)files.Length(), 0 );
1981
			if ( err == Z_OK )
1982
				compressed = true;
1983
		}
1984
	}
1985
 
1986
	// if unable to compress, store it as plain text
1987
	if ( !compressed )
1988
	{
1989
		fileComprLen = fileUncomprLen;
1990
		fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
1991
		memcpy ( fileCompr, files.c_str(), fileComprLen );
1992
		fileheader = SPKCOMPRESS_NONE;
1993
	}
1994
 
1995
	// now write the file header
1996
	m_SHeader2.lSize = fileComprLen;
52 cycrow 1997
	file.write("FileHeader;%d;%ld;%ld;%d;%d\n", m_SHeader2.iNumFiles, m_SHeader2.lSize, m_SHeader2.lFullSize, fileheader, m_SHeader2.iDataCompression);
6 cycrow 1998
 
52 cycrow 1999
	file.put(static_cast<unsigned char>(fileUncomprLen >> 24));
2000
	file.put(static_cast<unsigned char>(fileUncomprLen >> 16));
2001
	file.put(static_cast<unsigned char>(fileUncomprLen >> 8));
2002
	file.put(static_cast<unsigned char>(fileUncomprLen));
2003
	file.write(fileCompr, fileComprLen);
6 cycrow 2004
	free ( fileCompr );
2005
 
2006
	if ( progress )
2007
	{
2008
		progress->UpdateStatus(STATUS_WRITE);
2009
		progress->SetDone(0);
2010
		long max = 0;
88 cycrow 2011
		for ( CListNode<C_File> *file = m_lFiles.Front(); file; file = file->next() )
2012
			max += file->Data()->GetDataSize();
6 cycrow 2013
		if ( m_pIconFile )
2014
			max += m_pIconFile->GetDataSize();
2015
		progress->SetMax(max);
2016
	}
2017
 
2018
	// now finally, write all the file data
52 cycrow 2019
	if ( m_pIconFile ) {
2020
		if ( progress )	progress->UpdateFile(m_pIconFile);
2021
		file.writeSize(m_pIconFile->GetUncompressedDataSize());
2022
		file.write(m_pIconFile->GetData(), m_pIconFile->GetDataSize());
2023
		if ( progress )	progress->IncDone(m_pIconFile->GetDataSize());
6 cycrow 2024
	}
2025
 
2026
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2027
	{
52 cycrow 2028
		C_File *f = node->Data();
2029
		if ( progress )	progress->UpdateFile(f);
2030
		file.writeSize(f->GetUncompressedDataSize());
2031
		unsigned char *data = f->GetData();
2032
		size_t remaining = f->GetDataSize();
2033
		while ( remaining )	{
6 cycrow 2034
			size_t writeSize = WRITECHUNK;
52 cycrow 2035
			if ( writeSize > remaining ) writeSize = remaining;
6 cycrow 2036
 
52 cycrow 2037
			if ( file.write(data, writeSize) ) {
2038
				data += writeSize;
2039
				remaining -= writeSize;
2040
			}
6 cycrow 2041
 
52 cycrow 2042
			if ( progress ) progress->IncDone((int)writeSize);
6 cycrow 2043
		}
2044
	}
2045
 
50 cycrow 2046
	_changed();
6 cycrow 2047
 
2048
	return true;
2049
}
2050
 
2051
 
2052
bool CBaseFile::ExtractFile ( C_File *file, CyString dir, bool includedir, CProgressInfo *progress )
2053
{
2054
	if ( ReadFileToMemory ( file ) )
2055
	{
2056
		// now finally, uncompress the file
2057
		long len = 0;
2058
		unsigned char *data = file->UncompressData ( &len, progress );
2059
		if ( !data )
2060
		{
2061
			// attempt a file decompress
2062
			if ( file->GetCompressionType() == SPKCOMPRESS_7ZIP )
2063
			{
2064
				if ( file->UncompressToFile ( dir, this, includedir, progress ) )
2065
					return true;
2066
			}
2067
			return false;
2068
		}
2069
 
2070
		if ( !file->WriteToDir ( dir, this, includedir, NullString, data, len ) )
2071
			return false;
2072
 
2073
		return true;
2074
 
2075
	}
2076
	else
2077
		return false;
2078
}
2079
 
2080
bool CBaseFile::ExtractFile ( int filenum, CyString dir, bool includedir, CProgressInfo *progress )
2081
{
2082
	// invalid valus
2083
	if ( filenum < 0 )
2084
		return false;
2085
	// out of range
2086
	if ( filenum > m_lFiles.size() )
2087
		return false;
2088
 
2089
	// get the file pointer
2090
	C_File *file = m_lFiles.Get ( filenum );
2091
	return ExtractFile ( file, dir, includedir, progress );
2092
}
2093
 
2094
 
2095
 
2096
bool CBaseFile::ExtractAll ( CyString dir, int game, bool includedir, CProgressInfo *progress )
2097
{
2098
	// no file to read from
50 cycrow 2099
	if ( this->filename().empty() )
6 cycrow 2100
		return false;
2101
 
2102
	// now open the file
58 cycrow 2103
	CFileIO *File = _startRead();
2104
	if ( !File ) return false;
6 cycrow 2105
 
2106
	// now were in the file section
2107
	// skip past each one
58 cycrow 2108
	if ( m_pIconFile ) File->seek(4 + m_pIconFile->GetDataSize ());
6 cycrow 2109
 
2110
	CDirIO Dir(dir);
2111
 
52 cycrow 2112
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
6 cycrow 2113
		C_File *fit = node->Data();
2114
 
52 cycrow 2115
		if ( progress )	progress->UpdateFile ( fit );
6 cycrow 2116
 
52 cycrow 2117
		if ( (!fit->GetDataSize ()) || (!fit->GetData()) ) {
58 cycrow 2118
			if ( !fit->readFromFile(*File, fit->GetDataSize()) ) return false;
6 cycrow 2119
		}
2120
		else
58 cycrow 2121
			File->seek(fit->GetDataSize());
6 cycrow 2122
 
2123
		if ( game ) {
2124
			if ( fit->GetGame() && fit->GetGame() != game )
2125
				continue;
2126
		}
2127
 
2128
		// create directory first
2129
		Dir.Create(fit->GetDirectory(this));
2130
 
2131
		long size = 0;
2132
		unsigned char *data = fit->UncompressData (&size, progress);
52 cycrow 2133
		if ( (!data) && (fit->GetCompressionType() == SPKCOMPRESS_7ZIP) ) {
2134
			if ( !fit->UncompressToFile ( dir, this, includedir, progress ) ) return false;
6 cycrow 2135
		}
52 cycrow 2136
		else if ( (!data) || (!fit->WriteToDir ( dir, this, includedir, NullString, data, size )) ) return false;
6 cycrow 2137
	}
2138
 
58 cycrow 2139
	delete File;
6 cycrow 2140
	return true;
2141
}
2142
 
2143
 
2144
 
2145
 
2146
bool CBaseFile::UpdateSigned (bool updateFiles)
2147
{
2148
	m_bSigned = true;
2149
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2150
	{
2151
		C_File *file = node->Data();
2152
		if ( updateFiles )
2153
			file->UpdateSigned();
2154
		// extra, text, soundtrack, readmes and screen files do not require a modified game directly
2155
		if ( (file->GetFileType() == FILETYPE_EXTRA) || (file->GetFileType() == FILETYPE_TEXT) || (file->GetFileType() == FILETYPE_SOUND) || (file->GetFileType() == FILETYPE_SCREEN) || (file->GetFileType() == FILETYPE_README) )
2156
			continue;
2157
		// mods and maps always need modified game
2158
		else if ( (file->GetFileType() == FILETYPE_MOD) || (file->GetFileType() == FILETYPE_MAP) )
2159
		{
2160
			m_bSigned = false;
2161
			break;
2162
		}
2163
 
2164
		// else should be a script file, script or uninstall type
2165
		// all scripts must be signed, if any are not, then no signed status
2166
		if ( !file->IsSigned () )
2167
		{
2168
			m_bSigned = false;
2169
			break;
2170
		}
2171
	}
2172
 
2173
	return m_bSigned;
2174
}
2175
 
2176
 
46 cycrow 2177
bool CBaseFile::IsPackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2178
{
2179
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2180
	{
2181
		SNeededLibrary *l = node->Data();
2182
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2183
			return true;
2184
	}
2185
 
2186
	return false;
2187
}
2188
 
46 cycrow 2189
SNeededLibrary *CBaseFile::FindPackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2190
{
2191
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2192
	{
2193
		SNeededLibrary *l = node->Data();
2194
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2195
			return l;
2196
	}
2197
 
2198
	return NULL;
2199
}
2200
 
2201
void CBaseFile::RemoveFakePatchOrder(CyString scriptName, CyString author)
2202
{
2203
	RemoveFakePatchOrder(true, scriptName, author);
2204
	RemoveFakePatchOrder(false, scriptName, author);
2205
}
2206
void CBaseFile::RemoveFakePatchOrder(bool after, CyString scriptName, CyString author)
2207
{
2208
	CyStringList *list;
2209
	if ( after )
2210
		list = &m_lFakePatchAfter;
2211
	else
2212
		list = &m_lFakePatchBefore;
2213
 
2214
	for ( SStringList *str = list->Head(); str; str = str->next )
2215
	{
2216
		// already added
2217
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
2218
			str->remove = true;
2219
	}
2220
 
2221
	list->RemoveMarked();
2222
}
2223
 
2224
void CBaseFile::AddFakePatchOrder(bool after, CyString scriptName, CyString author)
2225
{
2226
	CyStringList *list;
2227
	if ( after )
2228
		list = &m_lFakePatchAfter;
2229
	else
2230
		list = &m_lFakePatchBefore;
2231
 
2232
	// check if the package already exists
2233
	for ( SStringList *str = list->Head(); str; str = str->next )
2234
	{
2235
		// already added
2236
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
2237
			return;
2238
	}
2239
 
2240
	// cant have it on both list
2241
	RemoveFakePatchOrder(!after, scriptName, author);
2242
 
2243
	list->PushBack(scriptName, author);
2244
}
46 cycrow 2245
void CBaseFile::AddNeededLibrary(const Utils::String &scriptName, const Utils::String &author, const Utils::String &minVersion)
6 cycrow 2246
{
2247
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2248
	if ( !l )
2249
	{
2250
		l = new SNeededLibrary;
2251
		l->sName = scriptName;
2252
		l->sAuthor = author;
2253
		m_lNeededLibrarys.push_back(l);
2254
	}
2255
	l->sMinVersion = minVersion;
2256
}
2257
 
46 cycrow 2258
void CBaseFile::RemovePackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2259
{
2260
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2261
	if ( l )
2262
	{
2263
		m_lNeededLibrarys.remove(l);
2264
		delete l;
2265
	}
2266
}
2267
 
2268
void CBaseFile::ClearNeededPackages()
2269
{
2270
	SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");
46 cycrow 2271
	Utils::String version;
2272
	if ( ns ) version = ns->sMinVersion;
2273
 
6 cycrow 2274
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2275
		node->DeleteData();
2276
	m_lNeededLibrarys.clear();
2277
 
46 cycrow 2278
	if ( !version.empty() )	this->AddNeededLibrary("<package>", "<author>", version);
6 cycrow 2279
}
2280
 
2281
 
127 cycrow 2282
bool CBaseFile::GeneratePackagerScript(bool wildcard, Utils::CStringList *list, int game, const Utils::CStringList &gameAddons, bool datafile)
6 cycrow 2283
{
126 cycrow 2284
	list->pushBack("#");
2285
	list->pushBack("# Packager Script");
2286
	list->pushBack("# -- Generated by SPK Libraries V" + Utils::String::FromFloat(GetLibraryVersion(), 2) + " --");
2287
	list->pushBack("#");
2288
	list->pushBack("");
6 cycrow 2289
	if ( !datafile )
2290
	{
126 cycrow 2291
		list->pushBack("# Variable for your game directory, where to get files from");
2292
		list->pushBack("# $PATH variable is used to get the current path");
2293
		list->pushBack("Variable: $GAMEDIR $PATH");
2294
		list->pushBack("");
6 cycrow 2295
	}
126 cycrow 2296
	list->pushBack("# The name of the script");
2297
	list->pushBack("Name: " + this->name());
2298
	list->pushBack("");
2299
	list->pushBack("# The author of the script, ie, you");
2300
	list->pushBack("Author: " + this->author());
2301
	list->pushBack("");
2302
	list->pushBack("# The creation data, when it was created");
6 cycrow 2303
	if ( datafile )
126 cycrow 2304
		list->pushBack("Date: " + this->creationDate());
50 cycrow 2305
	else {
126 cycrow 2306
		list->pushBack("# $DATE variable is used to get the current date");
2307
		list->pushBack("Date: $DATE");
6 cycrow 2308
	}
126 cycrow 2309
	list->pushBack("");
2310
	list->pushBack("# The version of script");
6 cycrow 2311
	if ( datafile )
126 cycrow 2312
		list->pushBack("Version: " + this->version());
6 cycrow 2313
	else
2314
	{
126 cycrow 2315
		list->pushBack("# $ASK variable is used to get an input when creating");
2316
		list->pushBack("Version: $ASK");
6 cycrow 2317
	}
126 cycrow 2318
	list->pushBack("");
6 cycrow 2319
 
2320
	if ( !m_lGames.empty() ) {
126 cycrow 2321
		list->pushBack("# The game version the script is for <game> <version> (can have multiple games)");
6 cycrow 2322
		for ( SGameCompat *g = m_lGames.First(); g; g = m_lGames.Next() ) {
126 cycrow 2323
			if (game > 0 && g->iGame != game)
2324
				continue;
2325
 
13 cycrow 2326
			Utils::String game = CBaseFile::ConvertGameToString(g->iGame);
6 cycrow 2327
 
46 cycrow 2328
			if ( !g->sVersion.empty() )
6 cycrow 2329
			{
2330
				game += " ";
46 cycrow 2331
				game += g->sVersion;
6 cycrow 2332
			}
2333
			else
2334
			{
2335
				game += " ";
2336
				game += (long)g->iVersion;
2337
			}
2338
 
126 cycrow 2339
			list->pushBack("Game: " + game);
6 cycrow 2340
		}
2341
 
126 cycrow 2342
		list->pushBack("");
6 cycrow 2343
	}
2344
 
48 cycrow 2345
	if ( !this->description().empty() ) {
126 cycrow 2346
		list->pushBack("# The description of the script, displays when installing");
2347
		list->pushBack("Description: " + this->description());
2348
		list->pushBack("");
6 cycrow 2349
	}
2350
 
49 cycrow 2351
	if ( !this->webSite().empty() ) {
126 cycrow 2352
		list->pushBack("# A link to the website for the script, ie for an online help page");
2353
		list->pushBack("WebSite: " + this->webSite());
2354
		list->pushBack("");
6 cycrow 2355
	}
2356
 
49 cycrow 2357
	if ( !this->forumLink().empty() ) {
126 cycrow 2358
		list->pushBack("# A direct link to the thread in the egosoft forum");
2359
		list->pushBack("ForumLink: " + this->forumLink());
2360
		list->pushBack("");
6 cycrow 2361
	}
2362
 
49 cycrow 2363
	if ( !this->webAddress().empty() ) {
126 cycrow 2364
		list->pushBack("# A link to the address for the update file");
2365
		list->pushBack("WebAddress: " + this->webAddress());
2366
		list->pushBack("");
6 cycrow 2367
	}
2368
 
49 cycrow 2369
	if ( !this->email().empty() ) {
126 cycrow 2370
		list->pushBack("# The email address of the author, to allow users to contract if needed");
2371
		list->pushBack("Email: " + this->email());
2372
		list->pushBack("");
6 cycrow 2373
	}
2374
 
2375
	if ( m_lMirrors.Count() )
2376
	{
126 cycrow 2377
		list->pushBack("# A link to the mirror address for the update file, can have many of these");
6 cycrow 2378
		for ( SStringList *node = m_lMirrors.Head(); node; node = node->next )
126 cycrow 2379
			list->pushBack(Utils::String("WebMirror: ") + node->str.ToString());
2380
		list->pushBack("");
6 cycrow 2381
	}
2382
 
2383
	if ( m_bAutoGenerateUpdateFile )
2384
	{
126 cycrow 2385
		list->pushBack("# Auto generate the package update file when created");
2386
		list->pushBack("GenerateUpdateFile");
6 cycrow 2387
	}
2388
 
2389
	if ( m_lNeededLibrarys.size() )
2390
	{
126 cycrow 2391
		list->pushBack("# Needed Library dependacies, require these to be installed");
6 cycrow 2392
		for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
126 cycrow 2393
			list->pushBack("Depend: " + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);
6 cycrow 2394
 
126 cycrow 2395
		list->pushBack("");
6 cycrow 2396
	}
2397
 
46 cycrow 2398
	if ( !_noRatings() )
6 cycrow 2399
	{
126 cycrow 2400
		list->pushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");
2401
		list->pushBack(Utils::String("Ratings: ") + (long)easeOfUse() + " " + (long)gameChanging() + " " + (long)recommended());
2402
		list->pushBack("");
6 cycrow 2403
	}
2404
 
2405
	if ( m_lNames.size() )
2406
	{
126 cycrow 2407
		list->pushBack("# Package names, uses different names for different languages");
6 cycrow 2408
		for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
126 cycrow 2409
			list->pushBack(Utils::String("ScriptName: ") + (long)node->Data()->iLanguage + " " + node->Data()->sName);
2410
		list->pushBack("");
6 cycrow 2411
	}
2412
 
46 cycrow 2413
	for ( int j = 0; j < 2; j++ ) {
2414
		Utils::String installText = (j == 0) ? "Install" : "Uninstall";
2415
		const CInstallText *pText = (j == 0) ? this->installText() : this->uninstallText();
2416
		if ( pText->any() )
6 cycrow 2417
		{
126 cycrow 2418
			list->pushBack("# " + installText + " Texts, display text before and/or after " + installText + "ing to inform the use of special conditions");
46 cycrow 2419
			for ( unsigned int i = 0; i < pText->count(); i++ ) {
2420
				long iLang = pText->language(i);
126 cycrow 2421
				if ( !pText->getBefore(iLang).empty() )	list->pushBack(installText + "Before: " + iLang + " " + pText->getBefore(iLang));
2422
				if ( !pText->getAfter(iLang).empty()  )	list->pushBack(installText + "After: " + iLang + " " + pText->getAfter(iLang));
46 cycrow 2423
			}
126 cycrow 2424
			list->pushBack("");
6 cycrow 2425
		}
2426
	}
2427
 
126 cycrow 2428
	list->pushBack("# Plugin Type, the type the plugin is, mainly used to show users the type, types include: Normal, Stable, Experimental, Cheat, Mod");
48 cycrow 2429
	switch ( this->pluginType() )
6 cycrow 2430
	{
2431
		case PLUGIN_NORMAL:
126 cycrow 2432
			list->pushBack("PluginType: Normal");
6 cycrow 2433
			break;
2434
		case PLUGIN_STABLE:
126 cycrow 2435
			list->pushBack("PluginType: Stable");
6 cycrow 2436
			break;
2437
		case PLUGIN_EXPERIMENTAL:
126 cycrow 2438
			list->pushBack("PluginType: Experimental");
6 cycrow 2439
			break;
2440
		case PLUGIN_CHEAT:
126 cycrow 2441
			list->pushBack("PluginType: Cheat");
6 cycrow 2442
			break;
2443
		case PLUGIN_MOD:
126 cycrow 2444
			list->pushBack("PluginType: Mod");
6 cycrow 2445
			break;
2446
	}
126 cycrow 2447
	list->pushBack("");
6 cycrow 2448
 
2449
	return true;
2450
}
2451
 
127 cycrow 2452
bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, Utils::CStringList *list, int game, const Utils::CStringList &gameAddons)
6 cycrow 2453
{
2454
	// now do files and wildcards
126 cycrow 2455
	Utils::CStringList files;
6 cycrow 2456
	for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
2457
	{
127 cycrow 2458
		if (game && !(f->Data()->game() & 1 << game))
126 cycrow 2459
			continue;
6 cycrow 2460
 
126 cycrow 2461
		Utils::String name = "$GAMEDIR/";
2462
 
127 cycrow 2463
		// addon directory?
2464
		unsigned int checkGame = f->Data()->game() & ~(1 << 31);
2465
		unsigned int foundGame = 0;
2466
		for (int i = 0; i < 31; ++i)
2467
		{
2468
			if (checkGame == 1 << i)
2469
			{
2470
				foundGame = i;
2471
				break;
2472
			}
2473
		}
2474
 
2475
		if (foundGame)
2476
		{
2477
			Utils::String str = gameAddons.findString(Utils::String::Number(foundGame));
2478
			if(!str.empty())
2479
				name += str + "/";
2480
		}
2481
 
6 cycrow 2482
		bool done = false;
2483
		if ( wildcard )
2484
		{
126 cycrow 2485
			Utils::String base = f->Data()->GetBaseName().ToString();
6 cycrow 2486
			if ( f->Data()->GetFileType() == FILETYPE_SCRIPT )
2487
			{
126 cycrow 2488
				if ( base.token(".", 1).Compare("plugin") || base.token(".", 1).Compare("lib") )
6 cycrow 2489
				{
126 cycrow 2490
					name += f->Data()->GetDirectory(this).ToString() + "/" + base.tokens(".", 1, 2) + ".*";
6 cycrow 2491
					done = true;
2492
				}
126 cycrow 2493
				else if ( base.token(".", 1).Compare("al") && !base.token(".", 2).Compare("plugin") )
6 cycrow 2494
				{
126 cycrow 2495
					name += f->Data()->GetDirectory(this).ToString() + "/" + base.tokens(".", 1, 2) + ".*";
6 cycrow 2496
					done = true;
2497
				}
2498
			}
2499
			else if ( f->Data()->GetFileType() == FILETYPE_TEXT )
2500
			{
126 cycrow 2501
				if ( base.contains("-L") )
6 cycrow 2502
				{
126 cycrow 2503
					name += f->Data()->GetDirectory(this).ToString() + "/" + base.token("-L", 1) + "-L*";
6 cycrow 2504
					done = true;
2505
				}
2506
				else
2507
				{
126 cycrow 2508
					name += f->Data()->GetDirectory(this).ToString() + "/*" + base.right(4) + ".*";
6 cycrow 2509
					done = true;
2510
				}
2511
			}
2512
		}
2513
 
2514
		if ( !done )
126 cycrow 2515
			name += f->Data()->GetNameDirectory(this).ToString();
6 cycrow 2516
 
2517
		if ( !f->Data()->GetDir().Empty() )
2518
		{
2519
			name += "|";
126 cycrow 2520
			name += f->Data()->GetDir().ToString();
6 cycrow 2521
		}
127 cycrow 2522
		Utils::String s = "GAME ";
2523
		if (!f->Data()->game() || f->Data()->game() == GAME_ALLNEW)
2524
			s += CBaseFile::ConvertGameToString(f->Data()->game());
2525
		else
2526
		{
2527
			bool first = true;
2528
			for (int i = 0; i < 31; ++i) 
2529
			{
2530
				if (f->Data()->game() & 1 << i)
2531
				{
2532
					if (first)
2533
						first = false;
2534
					else
2535
						s += "|";
2536
					s += CBaseFile::ConvertGameToString(i);
2537
				}
2538
			}
2539
		}
2540
 
2541
		s += " " + name;
126 cycrow 2542
		if(!files.contains(s))
2543
			files.pushBack(s, f->Data()->GetFileTypeString().ToString());
6 cycrow 2544
	}
2545
 
2546
 
126 cycrow 2547
	if ( !files.empty() )
6 cycrow 2548
	{
126 cycrow 2549
		list->pushBack("# Files List, all the files to add, can include wild cards");
2550
		for(auto itr = files.begin(); itr != files.end(); itr++)
2551
			list->pushBack((*itr)->data + ": " + (*itr)->str);
2552
		list->pushBack("");
6 cycrow 2553
	}
2554
 
2555
	return true;
2556
}
2557
 
50 cycrow 2558
Utils::String CBaseFile::GetAutosaveName()
6 cycrow 2559
{
50 cycrow 2560
	return this->name() + "-V" + this->version() + "-" + this->creationDate().findReplace("/", ".");
6 cycrow 2561
}
2562
 
2563
bool CBaseFile::CheckGameCompatability(int game)
2564
{
2565
	if ( m_lGames.empty() )
2566
		return true; // no game compatability added, assume its ok for all
2567
 
2568
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2569
		if ( node->Data()->iGame == 0 || node->Data()->iGame == game )
2570
			return true;
2571
	}
2572
	return false;
2573
}
2574
 
2575
bool CBaseFile::CheckGameVersionCompatability(int game, CyString sVersion, int iVersion)
2576
{
2577
	if ( m_lGames.empty() )
2578
		return true; // no game compatability added, assume its ok for all
2579
 
2580
	bool foundAll = false;
2581
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2582
		if ( node->Data()->iGame == 0 )
2583
			foundAll = true;
2584
		else if ( node->Data()->iGame == game ) { // now check the version
46 cycrow 2585
			if ( node->Data()->sVersion.empty() ) {
2586
				if ( CyString(node->Data()->sVersion).CompareVersion(sVersion) == COMPARE_OLDER )
6 cycrow 2587
					return false;
2588
				return true;
2589
			}
2590
			else {
2591
				if ( node->Data()->iVersion > iVersion )
2592
					return false;
2593
				return true;
2594
			}
2595
		}
2596
	}
2597
	return foundAll;
2598
}
2599
 
2600
bool CBaseFile::RemoveGameCompatability(int game)
2601
{
2602
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2603
		if ( node->Data()->iGame == game ) {
2604
			m_lGames.remove(node);
50 cycrow 2605
			_changed();
6 cycrow 2606
			return true;
2607
		}
2608
	}
2609
 
2610
	return false;
2611
}
2612
 
2613
SGameCompat *CBaseFile::GetGameCompatability(int game)
2614
{
2615
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2616
		if ( node->Data()->iGame == game ) {
2617
			return node->Data();
2618
		}
2619
	}
2620
 
2621
	return NULL;
2622
}
2623
 
46 cycrow 2624
void CBaseFile::AddGameCompatability(int game, const Utils::String &version)
6 cycrow 2625
{
2626
	// first check if we already have it on the list
2627
	SGameCompat *Found = this->GetGameCompatability(game);
2628
	if ( !Found ) {
2629
		Found = new SGameCompat;
2630
		m_lGames.push_back(Found);
2631
	}
2632
 
2633
	Found->iGame = game;
2634
	Found->iVersion = -1;
46 cycrow 2635
	Found->sVersion = "";
6 cycrow 2636
 
46 cycrow 2637
	if ( version.isin(".") || !version.isNumber() )
6 cycrow 2638
		Found->sVersion = version;
2639
	else
46 cycrow 2640
		Found->iVersion = version;
50 cycrow 2641
	_changed();
6 cycrow 2642
}
2643
 
127 cycrow 2644
bool CBaseFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames, Utils::CStringList &gameAddons)
6 cycrow 2645
{
50 cycrow 2646
	if ( sFirst.Compare("Name") )					this->setName(sRest);
2647
	else if ( sFirst.Compare("Author") )			this->setAuthor(sRest);
14 cycrow 2648
	else if ( sFirst.Compare("ScriptName") )
2649
		AddLanguageName(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
46 cycrow 2650
	else if ( sFirst.Compare("UninstallBefore") )	this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));
2651
	else if ( sFirst.Compare("UninstallAfter") )	this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));
2652
	else if ( sFirst.Compare("InstallBefore") )		this->addInstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));
2653
	else if ( sFirst.Compare("InstallAfter") )		this->addInstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));
50 cycrow 2654
	else if ( sFirst.Compare("Date") )				this->setCreationDate(sRest);
2655
	else if ( sFirst.Compare("Version") )			this->setVersion(sRest);
14 cycrow 2656
	else if ( sFirst.Compare("GameVersion") )
2657
		this->AddGameCompatability(-1, sRest);
50 cycrow 2658
	else if ( sFirst.Compare("PluginType") ) {
48 cycrow 2659
		if ( sRest.isNumber() )						this->setPluginType(sRest);
2660
		else if ( sRest.Compare("Normal") )			this->setPluginType(PLUGIN_NORMAL);
2661
		else if ( sRest.Compare("Stable") )			this->setPluginType(PLUGIN_STABLE);
2662
		else if ( sRest.Compare("Experimental") )	this->setPluginType(PLUGIN_EXPERIMENTAL);
2663
		else if ( sRest.Compare("Cheat") )			this->setPluginType(PLUGIN_CHEAT);
2664
		else if ( sRest.Compare("Mod") )			this->setPluginType(PLUGIN_MOD);
6 cycrow 2665
	}
2666
	// new version
14 cycrow 2667
	else if ( sFirst.Compare("GenerateUpdateFile") )
6 cycrow 2668
		m_bAutoGenerateUpdateFile = true;
14 cycrow 2669
	else if ( sFirst.Compare("Game") )
6 cycrow 2670
	{
14 cycrow 2671
		Utils::String sGame = sRest.token(" ", 1);
2672
		this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), sRest.token(" ", 2));
6 cycrow 2673
	}
48 cycrow 2674
	else if ( sFirst.Compare("Description") )		this->setDescription(sRest);
14 cycrow 2675
	else if ( sFirst.Compare("AutoSave") || sFirst.Compare("AutoExport") || sFirst.Compare("AutoRarExport") || sFirst.Compare("AutoZipExport") )
6 cycrow 2676
	{
50 cycrow 2677
		Utils::String filename = sRest;
2678
		Utils::String cdate = this->creationDate().findReplace("/", ".").remove(' ');
2679
		if ( filename.isin("$AUTOSAVE") )
6 cycrow 2680
		{
96 cycrow 2681
			if ( this->GetType() == TYPE_XSP )
50 cycrow 2682
				filename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");
6 cycrow 2683
			else
50 cycrow 2684
				filename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");
6 cycrow 2685
		}
50 cycrow 2686
		filename = filename.findReplace("$NAME", this->name().remove(' '));
2687
		filename = filename.findReplace("$AUTHOR", this->author().remove(' '));
2688
		filename = filename.findReplace("$DATE", cdate);
2689
		filename = filename.findReplace("$CDATE", cdate);
2690
		filename = filename.findReplace("$VERSION", this->version());
6 cycrow 2691
 
14 cycrow 2692
		if ( sFirst.Compare("AutoZipExport") || sFirst.Compare("AutoExport") )
50 cycrow 2693
			this->setExportFilename(CFileIO(filename).ChangeFileExtension("zip").ToString());
14 cycrow 2694
		else if ( sFirst.Compare("AutoRarExport") )
50 cycrow 2695
			this->setExportFilename(CFileIO(filename).ChangeFileExtension("rar").ToString());
6 cycrow 2696
		else
50 cycrow 2697
			this->setFilename(filename);
6 cycrow 2698
	}
49 cycrow 2699
	else if ( sFirst.Compare("WebSite") )		this->setWebSite(sRest);
2700
	else if ( sFirst.Compare("ForumLink") || sFirst.Compare("Forum") ) this->setForumLink(sRest);
2701
	else if ( sFirst.Compare("Email") )			this->setEmail(sRest);
2702
	else if ( sFirst.Compare("WebAddress") )	this->setWebAddress(sRest);
14 cycrow 2703
	else if ( sFirst.Compare("WebMirror") )
2704
		this->AddWebMirror(sRest);
2705
	else if ( sFirst.Compare("WebMirror1") )
2706
		this->AddWebMirror(sRest);
2707
	else if ( sFirst.Compare("WebMirror2") )
2708
		this->AddWebMirror(sRest);
2709
	else if ( sFirst.Compare("Ftp") )
2710
		m_sFtpAddr = sRest;
46 cycrow 2711
	else if ( sFirst.Compare("Ratings") )		_setRatings(sRest.token(" ", 1), sRest.token(" ", 2), sRest.token(" ", 3));
2712
	else if ( sFirst.Compare("EaseOfUse") )		setEaseOfUse(sRest);
2713
	else if ( sFirst.Compare("GameChanging"))	setGameChanging(sRest);
2714
	else if ( sFirst.Compare("Recommended") )	setRecommended(sRest);
14 cycrow 2715
	else if ( sFirst.Compare("Depend") )
6 cycrow 2716
	{
46 cycrow 2717
		Utils::String version = sRest.token("|", 2);
2718
		Utils::String name = sRest.token("|", 1);
2719
		Utils::String author = sRest.tokens("|", 3);
6 cycrow 2720
 
2721
		this->AddNeededLibrary(name, author, version);
2722
	}
14 cycrow 2723
	else if ( sFirst.Compare("DependPackage") )
6 cycrow 2724
	{
2725
		CPackages p;
14 cycrow 2726
		CBaseFile *spk =  p.OpenPackage(sRest, 0, 0, SPKREAD_VALUES);
6 cycrow 2727
		if ( spk )
2728
		{
50 cycrow 2729
			this->AddNeededLibrary(spk->name(), spk->author(), spk->version());
6 cycrow 2730
			delete spk;
2731
		}
2732
	}
14 cycrow 2733
	else if ( sFirst.Compare("Icon") )
6 cycrow 2734
	{
14 cycrow 2735
		C_File *icon = new C_File(sRest.c_str());
6 cycrow 2736
		if ( icon->ReadFromFile() )
14 cycrow 2737
			this->SetIcon(icon, CFileIO(sRest).GetFileExtension());
6 cycrow 2738
	}
2739
	else
2740
	{
14 cycrow 2741
		Utils::String checkType = sFirst;
6 cycrow 2742
		bool shared = false;
14 cycrow 2743
		if ( checkType.left(6).Compare("Shared") )
6 cycrow 2744
		{
14 cycrow 2745
			checkType = sFirst.right(-6);
6 cycrow 2746
			shared = true;
2747
		}
2748
 
2749
		// now check type name
127 cycrow 2750
		FileType filetype = GetFileTypeFromString(checkType);
2751
		if (filetype != FILETYPE_UNKNOWN)
2752
			this->AddFileScript(filetype, shared, sRest, sMainGame, otherGames, gameAddons);
6 cycrow 2753
		else if ( !checkType.Compare("changelog") )
2754
			return false;
2755
	}
2756
 
2757
	return true;
2758
}
2759
 
127 cycrow 2760
void CBaseFile::AddFileScript(FileType filetype, bool shared, CyString sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames, Utils::CStringList &gameAddons)
6 cycrow 2761
{
127 cycrow 2762
	Utils::String dir;
2763
	Utils::String rest = sRest.ToString();
2764
 
2765
	unsigned int mainGame = CBaseFile::GetGameFromString(sMainGame);
2766
	unsigned int game = 0;
2767
	if ( rest.token(" ", 1).left(4).Compare("GAME") ) {
2768
		Utils::String gameStr = rest.token(" ", 2);
2769
		if (gameStr.contains("|"))
2770
		{
2771
			int max = 0;
2772
			Utils::String *games = gameStr.tokenise("|", &max);
2773
			for (int i = 0; i < max; ++i)
2774
			{
2775
				unsigned int g = CBaseFile::GetGameFromString(games[i]);
2776
				if (g)
2777
					game |= 1 << g;
2778
			}
2779
			CLEANSPLIT(games, max);
2780
		}
2781
		else
2782
			game = 1 << CBaseFile::GetGameFromString(gameStr);
2783
		rest = rest.tokens(" ", 3);
6 cycrow 2784
	}
127 cycrow 2785
	if (game)
2786
		game |= 1 << 31;
6 cycrow 2787
 
127 cycrow 2788
	if (rest.contains("|"))
2789
	{
2790
		dir = rest.tokens("|", 2);
2791
		rest = rest.token("|", 1);
6 cycrow 2792
	}
2793
 
127 cycrow 2794
	rest = rest.findReplace("\\", "/");
6 cycrow 2795
 
2796
	// wild cards
127 cycrow 2797
	if ( rest.containsAny("*?") )
6 cycrow 2798
	{
102 cycrow 2799
		CDirIO Dir(CFileIO(rest).dir());
6 cycrow 2800
		CyStringList *dirList = Dir.DirList();
2801
		if ( dirList )
2802
		{
2803
			for ( SStringList *strNode = dirList->Head(); strNode; strNode = strNode->next )
2804
			{
127 cycrow 2805
				Utils::String file = Dir.file(strNode->str.ToString());
2806
				if (file.match(rest))
6 cycrow 2807
				{
98 cycrow 2808
					int addGame = game;
2809
					// check if the file exists in the subdirectory too, if it does, add for each game
2810
					if ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {
2811
						CFileIO F(file);
2812
						for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {
102 cycrow 2813
							Utils::String checkDir = F.dir() + "/" + g;
121 cycrow 2814
							if ( CDirIO(checkDir).exists(F.filename()) ) {
98 cycrow 2815
								addGame = mainGame;
2816
								C_File *newfile = this->AppendFile(CDirIO(checkDir).File(F.filename()), filetype, CBaseFile::GetGameFromString(g), dir);
2817
								if ( newfile ) newfile->SetShared(shared);
2818
							}
2819
						}
2820
					}
2821
 
2822
					C_File *newfile = this->AppendFile(file, filetype, addGame, dir);
6 cycrow 2823
					if ( newfile )
2824
						newfile->SetShared(shared);
2825
				}
2826
			}
2827
			delete dirList;
2828
		}
2829
	}
2830
	else
2831
	{
127 cycrow 2832
		unsigned int addGame = game;
98 cycrow 2833
		// check if the file exists in the subdirectory too, if it does, add for each game
2834
		if ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {
2835
			CFileIO F(rest);
2836
			for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {
102 cycrow 2837
				Utils::String checkDir = F.dir() + "/" + g;
121 cycrow 2838
				if ( CDirIO(checkDir).exists(F.filename()) ) {
98 cycrow 2839
					addGame = mainGame;
121 cycrow 2840
					C_File *newfile = this->AppendFile(CDirIO(checkDir).file(F.filename()), filetype, CBaseFile::GetGameFromString(g), dir);
98 cycrow 2841
					if ( newfile ) newfile->SetShared(shared);
2842
				}
2843
			}
2844
		}
2845
 
127 cycrow 2846
		unsigned int checkGame = addGame & ~(1 << 31);
2847
		unsigned int foundGame = 0;
2848
		for (int i = 0; i < 31; ++i)
2849
		{
2850
			if (1 << i == checkGame)
2851
			{
2852
				foundGame = i;
2853
				break;
2854
			}
2855
		}
2856
 
2857
		C_File *file = NULL;
2858
		if (foundGame)
2859
		{
2860
			Utils::String addon = gameAddons.findString(Utils::String::Number(foundGame));
2861
			if (!addon.empty())
2862
			{
2863
				Utils::String dir = C_File::GetDirectory(filetype, rest, this);
2864
				Utils::String filename = rest;
2865
				if (CCatFile::IsAddonDir(dir))
2866
					filename = filename.findReplace(dir + "/", addon + "/" + dir + "/");
2867
 
2868
				file = this->AppendFile(filename, filetype, addGame, dir);
2869
			}
2870
		}
2871
 
2872
		if(!file)
2873
			file = this->AppendFile(rest, filetype, addGame, dir);
2874
 
2875
		if (file)
6 cycrow 2876
			file->SetShared(shared);
2877
	}
2878
}
2879
 
2880
 
2881
CyString CBaseFile::GetFullFileSizeString() { return SPK::GetSizeString ( this->GetFullFileSize() ); }
2882
 
52 cycrow 2883
// used for a multiple spk file
6 cycrow 2884
unsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress)
2885
{
52 cycrow 2886
	if ( this->WriteFile("temp.dat", progress) ) {
2887
		CFileIO File("temp.dat");
2888
		File.setAutoDelete(true);
2889
		return File.readAll(size);
6 cycrow 2890
	}
2891
	return NULL;
2892
}
2893
 
2894
 
2895
void CBaseFile::ConvertNormalMod(C_File *f, CyString to)
2896
{
2897
	C_File *match = this->FindMatchingMod(f);
2898
	if ( match )
2899
	{
2900
		// file link
2901
		if ( !match->GetData() )
2902
			match->ReadFromFile();
2903
		match->ChangeBaseName(to);
2904
	}
2905
 
2906
	// file link
2907
	if ( !f->GetData() )
2908
		f->ReadFromFile();
2909
 
2910
	f->ChangeBaseName(to);
2911
}
2912
 
2913
void CBaseFile::ConvertAutoText(C_File *f)
2914
{
2915
	CyString to;
2916
	if ( f->GetBaseName().IsIn("-L") )
2917
		to = CyString("0000-L") + f->GetBaseName().GetToken("-L", 2, 2);
2918
	else if ( f->GetBaseName().IsIn("-l") )
2919
		to = CyString("0000-L") + f->GetBaseName().GetToken("-l", 2, 2);
2920
	else
2921
		to = f->GetBaseName().Left(-4) + "0000";
2922
 
2923
	// file link
2924
	if ( !f->GetData() )
2925
		f->ReadFromFile();
2926
 
2927
	f->ChangeBaseName(to);
2928
 
2929
}
2930
 
2931
void CBaseFile::ConvertFakePatch(C_File *f)
2932
{
2933
	// find next available fake patch
2934
	int num = 0;
2935
 
2936
	bool found = true;
2937
	while ( found )
2938
	{
2939
		++num;
2940
		found = false;
2941
		CyString find = CyString::Number(num).PadNumber(2);
2942
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2943
		{
2944
			if ( node->Data()->GetFileType() != FILETYPE_MOD )
2945
				continue;
2946
			if ( !node->Data()->IsFakePatch() )
2947
				continue;
2948
			if ( node->Data()->GetBaseName().Compare(find) )
2949
			{
2950
				found = true;
2951
				break;
2952
			}
2953
		}
2954
	}
2955
 
2956
	CyString to = CyString::Number(num).PadNumber(2);
2957
	C_File *match = this->FindMatchingMod(f);
2958
 
2959
	// file link
2960
	if ( !f->GetData() )
2961
		f->ReadFromFile();
2962
 
2963
	f->ChangeBaseName(to);
2964
	if ( match )
2965
	{
2966
		// file link
2967
		if ( !match->GetData() )
2968
			match->ReadFromFile();
2969
		match->ChangeBaseName(to);
2970
	}
2971
}
2972
 
2973
C_File *CBaseFile::FindMatchingMod(C_File *f)
2974
{
2975
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2976
	{
2977
		if ( node->Data()->GetFileType() != FILETYPE_MOD )
2978
			continue;
2979
 
2980
		if ( f->GetFileExt().Compare(node->Data()->GetFileExt()) )
2981
			continue;
2982
 
2983
		if ( f->GetBaseName().Compare(node->Data()->GetBaseName()) )
2984
			return node->Data();
2985
	}
2986
 
2987
	return NULL;
2988
}
2989
 
2990
void CBaseFile::RenameFile(C_File *f, CyString baseName)
2991
{
2992
	if ( f->GetFileType() == FILETYPE_MOD )
2993
	{
2994
		C_File *match = this->FindMatchingMod(f);
2995
		if ( match )
2996
			match->ChangeBaseName(baseName);
2997
	}
2998
 
2999
	// need to edit the file
126 cycrow 3000
if (f->GetFileType() == FILETYPE_SCRIPT || f->GetFileType() == FILETYPE_UNINSTALL)
3001
f->RenameScript(baseName);
6 cycrow 3002
 
126 cycrow 3003
f->ChangeBaseName(baseName);
6 cycrow 3004
}
3005
 
3006
CyString CBaseFile::CreateUpdateFile(CyString dir)
3007
{
50 cycrow 3008
	CyString file = this->GetNameValidFile() + "_" + this->author() + ".dat";
6 cycrow 3009
	file.RemoveChar(' ');
3010
 
3011
	CyStringList write;
50 cycrow 3012
	write.PushBack(CyString("Package: ") + this->name());
3013
	write.PushBack(CyString("Author: ") + this->author());
3014
	write.PushBack(CyString("Version: ") + this->version());
111 cycrow 3015
	write.PushBack(CyString("File: ") + CFileIO(this->filename()).filename());
6 cycrow 3016
 
3017
	CFileIO File(dir + "/" + file);
126 cycrow 3018
	if (File.WriteFile(&write))
102 cycrow 3019
		return File.fullFilename();
6 cycrow 3020
	return NullString;
3021
}
3022
 
3023
CyString CBaseFile::ErrorString(int error, CyString errorStr)
3024
{
126 cycrow 3025
	if (error == SPKERR_NONE) return NullString;
6 cycrow 3026
 
3027
	CyString err;
3028
 
126 cycrow 3029
	switch (error)
6 cycrow 3030
	{
126 cycrow 3031
	case SPKERR_MALLOC:
3032
		err = "Memory Failed";
3033
		break;
3034
	case SPKERR_FILEOPEN:
3035
		err = "Failed to open file";
3036
		break;
3037
	case SPKERR_FILEREAD:
3038
		err = "Failed to read file";
3039
		break;
3040
	case SPKERR_UNCOMPRESS:
3041
		err = "Failed to Uncompress";
3042
		break;
3043
	case SPKERR_WRITEFILE:
3044
		err = "Failed to write file";
3045
		break;
3046
	case SPKERR_CREATEDIRECTORY:
3047
		err = "Failed to create directory";
3048
		break;
3049
	case SPKERR_FILEMISMATCH:
3050
		err = "File count mismatch";
3051
		break;
6 cycrow 3052
	}
3053
 
126 cycrow 3054
	if (!err.Empty())
6 cycrow 3055
	{
126 cycrow 3056
		if (!errorStr.Empty())
6 cycrow 3057
		{
3058
			err += " (";
3059
			err += errorStr + ")";
3060
		}
3061
		return err;
3062
	}
3063
 
3064
	return CyString((long)error);
3065
}
3066
 
126 cycrow 3067
bool CBaseFile::SaveToArchive(CyString filename, int game, const CGameExe *exes, CProgressInfo *progress)
6 cycrow 3068
{
3069
	TCHAR buf[5000];
3070
	wsprintf(buf, L"%hs", filename.c_str());
3071
 
3072
	HZIP hz = CreateZip(buf, 0);
126 cycrow 3073
	if (!hz) return false;
6 cycrow 3074
 
3075
	// read files and compress
3076
	ReadAllFilesToMemory();
126 cycrow 3077
	if (!UncompressAllFiles(progress))
6 cycrow 3078
	{
3079
		CloseZip(hz);
3080
		return false;
3081
	}
3082
 
126 cycrow 3083
	for (CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next())
6 cycrow 3084
	{
126 cycrow 3085
		if (game != -1) {
127 cycrow 3086
			if (game && !(node->Data()->game() & (1 << game)))
6 cycrow 3087
				continue;
127 cycrow 3088
			// extracting for all games, so ignore files that have a game set
3089
			if (!game && node->Data()->game() && node->Data()->game() != GAME_ALLNEW)
6 cycrow 3090
				continue;
3091
		}
126 cycrow 3092
		Utils::String fname = node->Data()->GetNameDirectory(this).ToString();
3093
 
3094
		// use the addon directory
3095
		if (node->Data()->isFileInAddon() && exes)
3096
		{
127 cycrow 3097
			unsigned int whatGame = game;
126 cycrow 3098
			if (game == -1)
127 cycrow 3099
			{
3100
				unsigned int checkGame = node->Data()->game() & ~GAME_ALLNEW;
3101
				whatGame = 0;
3102
				for (int i = 0; i < 31; ++i)
3103
				{
3104
					if (1 << i == checkGame)
3105
					{
3106
						whatGame = i;
3107
						break;
3108
					}
3109
				}
3110
			}
126 cycrow 3111
 
127 cycrow 3112
			if (whatGame > 0)
126 cycrow 3113
			{
127 cycrow 3114
				SGameExe *e = exes->GetGame(whatGame - 1);
3115
				if (e)
3116
				{
3117
					if (e->iFlags & EXEFLAG_ADDON)
3118
						fname = e->sAddon + "/" + fname;
3119
				}
126 cycrow 3120
			}
3121
		}
3122
 
6 cycrow 3123
		// create the directory
3124
		wsprintf(buf, L"%hs", fname.c_str());
127 cycrow 3125
		if (node->Data()->isExternalFile())
3126
		{
3127
			CFileIO file(node->Data()->filePointer());
3128
			size_t size = 0;
3129
			unsigned char *data = file.readAll(&size);
3130
			ZipAdd(hz, buf, data, size);
3131
			delete data;
3132
		}
3133
		else
3134
			ZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());
6 cycrow 3135
	}
3136
 
109 cycrow 3137
	// if its a ship, then add any generated files
3138
	this->addGeneratedFiles(hz);
3139
 
6 cycrow 3140
	// add the data file
126 cycrow 3141
	Utils::CStringList list;
127 cycrow 3142
	Utils::CStringList addons;
3143
	if ( this->GeneratePackagerScript(false, &list, game, addons, true) )
6 cycrow 3144
	{
126 cycrow 3145
		if ( CFileIO("test.tmp").writeFile(&list) )
6 cycrow 3146
		{
3147
			ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");
52 cycrow 3148
			CFileIO::Remove("test.tmp");
6 cycrow 3149
		}
3150
	}
3151
 
3152
	CloseZip(hz);
3153
 
3154
	return true;
3155
}
3156
 
13 cycrow 3157
int CBaseFile::GetGameFromString(const Utils::String &sGame)
6 cycrow 3158
{
3159
	int iGame = GAME_ALL;
3160
	if ( sGame.Compare("ALL") )
3161
		iGame = GAME_ALL;
3162
	else if ( sGame.Compare("X3") )
3163
		iGame = GAME_X3;
3164
	else if ( sGame.Compare("X2") )
3165
		iGame = GAME_X2;
3166
	else if ( sGame.Compare("X3TC") )
3167
		iGame = GAME_X3TC;
126 cycrow 3168
	else if (sGame.Compare("X3AP"))
6 cycrow 3169
		iGame = GAME_X3AP;
126 cycrow 3170
	else if (sGame.Compare("X3FL"))
3171
		iGame = GAME_X3FL;
13 cycrow 3172
	else if ( sGame.isNumber() )
3173
		iGame = sGame;
6 cycrow 3174
 
3175
	return iGame;
3176
}
3177
 
13 cycrow 3178
Utils::String CBaseFile::ConvertGameToString(int iGame)
6 cycrow 3179
{
13 cycrow 3180
	Utils::String game = "ALL";
6 cycrow 3181
 
3182
	switch(iGame) {
3183
		case GAME_ALL:
127 cycrow 3184
		case GAME_ALLNEW:
6 cycrow 3185
			game = "ALL";
3186
			break;
3187
		case GAME_X2:
3188
			game = "X2";
3189
			break;
3190
		case GAME_X3:
3191
			game = "X3";
3192
			break;
3193
		case GAME_X3TC:
3194
			game = "X3TC";
3195
			break;
3196
		case GAME_X3AP:
3197
			game = "X3AP";
3198
			break;
126 cycrow 3199
		case GAME_X3FL:
3200
			game = "X3FL";
3201
			break;
6 cycrow 3202
		default:
3203
			game = (long)iGame;
3204
	}
3205
 
3206
	return game;
3207
}
3208
 
3209
bool CBaseFile::IsGameInPackage(int game)
3210
{
3211
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3212
		if ( node->Data()->GetGame() == game )
3213
			return true;
3214
	}
3215
 
3216
	return false;
3217
}
3218
 
3219
bool CBaseFile::IsAnyGameInPackage()
3220
{
3221
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3222
		if ( node->Data()->GetGame() )
3223
			return true;
3224
	}
3225
 
3226
	return false;
3227
}
3228
 
88 cycrow 3229
Utils::String builtInWares()
3230
{
3231
	Utils::String str;
3232
	str += "28;0;0;0;0;59;5753;0;35714;1;1;0;35714;-100000;0;0;SS_WARE_SW_NEW1;\n";
3233
	str += "28;0;0;0;0;60;5763;0;33232;1;1;0;33232;0;1043;0;SS_WARE_SW_NEW2;\n";
3234
	str += "28;0;0;0;0;61;5773;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW3;\n";
3235
	str += "28;0;0;0;0;62;5783;0;56;1;1;0;56;-100000;0;0;SS_WARE_SW_NEW4;\n";
3236
	str += "28;0;0;0;0;63;5793;0;88;1;1;0;88;-100000;0;0;SS_WARE_SW_NEW5;\n";
3237
	str += "28;0;0;0;0;64;5803;0;283;1;1;0;283;-100000;0;0;SS_WARE_SW_NEW6;\n";
3238
	str += "28;0;0;0;0;65;5813;0;383;1;1;0;383;-100000;0;0;SS_WARE_SW_NEW7;\n";
3239
	str += "28;0;0;0;0;66;5823;0;1389;1;1;0;1389;-100000;1043;0;SS_WARE_SW_NEW8;\n";
3240
	str += "28;0;0;0;0;67;5833;0;3396;1;1;0;3396;-100000;0;0;SS_WARE_SW_NEW9;\n";
3241
	str += "28;0;0;0;0;68;5843;0;4215;1;1;0;4215;-100000;0;0;SS_WARE_SW_NEW10;\n";
3242
	str += "28;0;0;0;0;69;5853;0;5635;1;1;0;5635;-100000;0;0;SS_WARE_SW_NEW11;\n";
3243
	str += "28;0;0;0;0;70;5863;0;65735;1;1;0;65735;-100000;0;0;SS_WARE_SW_NEW12;\n";
3244
	str += "28;0;0;0;0;71;5873;0;17857;1;1;0;17857;333;1043;0;SS_WARE_SW_NEW13;\n";
3245
	str += "28;0;0;0;0;72;5883;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW14;\n";
3246
	str += "28;0;0;0;0;73;5893;0;324515;1;1;0;324515;-100000;0;0;SS_WARE_SW_NEW15;\n";
3247
	str += "28;0;0;0;0;74;5903;0;638508;1;1;0;638508;-100000;0;0;SS_WARE_SW_NEW16;\n";
3248
	str += "28;0;0;0;0;75;5913;0;225755;1;1;0;225755;-100000;0;0;SS_WARE_SW_NEW17;\n";
3249
	str += "28;0;0;0;0;76;5923;0;1931535;1;1;0;1931535;1000;0;0;SS_WARE_SW_NEW18;\n";
3250
	str += "28;0;0;0;0;77;5933;0;2209150;1;1;0;2209150;-100000;0;0;SS_WARE_SW_NEW19;\n";
3251
	str += "28;0;0;0;0;78;5943;0;6727565;1;1;0;6727565;-100000;0;0;SS_WARE_SW_NEW20;\n";
3252
	str += "28;0;0;0;0;85;9999;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_1;\n";
3253
	str += "28;0;0;0;0;86;15053;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_2;\n";
3254
	str += "28;0;0;0;0;87;15063;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_3;\n";
3255
	str += "28;0;0;0;0;88;15073;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_4;\n";
3256
	str += "28;0;0;0;0;89;15083;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_5;\n";
3257
	str += "28;0;0;0;0;90;15093;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_6;\n";
3258
 
3259
	return str;
3260
}
3261
 
3262
void CBaseFile::_addWaresToList(int iLang, CLinkList<SWareEntry> &list, const Utils::String &wares, enum WareTypes eType)
3263
{
3264
	int totalWares = 0;
3265
	Utils::String *w = wares.tokenise("\n", &totalWares);
3266
 
3267
	for(int i = 0; i < totalWares; i++) {
3268
		int textId = w[i].token(";", 7).toLong();
3269
		int useLang = iLang;
3270
		if ( !_pTextDB->exists(useLang, 17, textId) )
3271
			useLang = 44;
3272
		if ( !_pTextDB->exists(useLang, 17, textId) )
3273
			useLang = 49;
3274
		if ( _pTextDB->exists(useLang, 17, textId) ) {	
3275
			SWareEntry *ware = new SWareEntry;
3276
			ware->name = _pTextDB->get(useLang, 17, textId);
3277
			ware->description = _pTextDB->get(useLang, 17, textId + 1);
3278
			ware->id = w[i].token(";", -2);
3279
			ware->relval = w[i].token(";", 9).toLong();
3280
			ware->notority = w[i].token(";", 14).toLong();
3281
			ware->type = eType;
3282
			ware->position = i;
89 cycrow 3283
			ware->package = this;
88 cycrow 3284
			list.push_back(ware);
3285
		}
3286
	}
3287
 
3288
	CLEANSPLIT(w, totalWares);
3289
}
3290
 
3291
bool CBaseFile::readWares(int iLang, CLinkList<SWareEntry> &list, const Utils::String &empWares)
3292
{
3293
	_pTextDB->setLanguage(iLang);
3294
 
3295
	// now go through all emp wares and get the ones we have text for
3296
	_addWaresToList(iLang, list, empWares, Ware_EMP);
3297
	_addWaresToList(iLang, list, builtInWares(), Ware_BuiltIn);
3298
 
89 cycrow 3299
	return true;
3300
}
88 cycrow 3301
 
89 cycrow 3302
bool CBaseFile::_readCommands(int iLang, int iStartID, CLinkList<SCommandSlot> &list)
3303
{
3304
	_pTextDB->setLanguage(iLang);
3305
 
3306
	for(int i = 2; i <= 13; i++) {
3307
		for(int j = 0; j < 64; j++) {
3308
			int id = (i * 100) + j;
3309
			if ( _pTextDB->exists(iLang, iStartID + 2, id) ) {
3310
				SCommandSlot *slot = new SCommandSlot;
3311
				list.push_back(slot);
3312
 
3313
				slot->id = _pTextDB->get(iLang, iStartID, id);
3314
				slot->name = _pTextDB->get(iLang, iStartID + 2, id);
3315
				slot->shortName = _pTextDB->get(iLang, iStartID + 3, id);
3316
				slot->info = _pTextDB->get(iLang, iStartID + 14, id);
3317
				slot->slot = id;
3318
				slot->package = this;
3319
 			}
3320
		}
3321
	}
3322
 
3323
	for(int i = 1400; i <= 2000; i++) {
3324
		if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {
3325
			SCommandSlot *slot = new SCommandSlot;
3326
			list.push_back(slot);
3327
 
3328
			slot->id = _pTextDB->get(iLang, iStartID, i);
3329
			slot->name = _pTextDB->get(iLang, iStartID + 2, i);
3330
			slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);
3331
			slot->info = _pTextDB->get(iLang, iStartID + 14, i);
3332
			slot->slot = i;
3333
			slot->package = this;
3334
		}
3335
	}
3336
 
3337
	for(int i = 6000; i <= 9999; i++) {
3338
		if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {
3339
			SCommandSlot *slot = new SCommandSlot;
3340
			list.push_back(slot);
3341
 
3342
			slot->id = _pTextDB->get(iLang, iStartID, i);
3343
			slot->name = _pTextDB->get(iLang, iStartID + 2, i);
3344
			slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);
3345
			slot->info = _pTextDB->get(iLang, iStartID + 14, i);
3346
			slot->slot = i;
3347
			slot->package = this;
3348
		}
3349
	}
3350
 
88 cycrow 3351
	return true;
3352
}
3353
 
89 cycrow 3354
bool CBaseFile::readWingCommands(int iLang, CLinkList<SCommandSlot> &list)
3355
{
3356
	return _readCommands(iLang, 2028, list);
3357
}
3358
 
3359
bool CBaseFile::readCommands(int iLang, CLinkList<SCommandSlot> &list)
3360
{
3361
	return _readCommands(iLang, 2008, list);
3362
}
3363
 
6 cycrow 3364
int CBaseFile::FindFirstGameInPackage()
3365
{
3366
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3367
		if ( node->Data()->GetGame() )
3368
			return node->Data()->GetGame();
3369
	}
3370
 
3371
	return 0;
3372
}
3373
bool CBaseFile::IsMultipleGamesInPackage()
3374
{
3375
	int game = 0;
3376
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3377
		if ( node->Data()->GetGame() ) {
3378
			if ( game != node->Data()->GetGame() )
3379
				return true;
3380
			game = node->Data()->GetGame();
3381
		}
3382
	}
3383
 
3384
	return false;
3385
}