Subversion Repositories spk

Rev

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