Subversion Repositories spk

Rev

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