Subversion Repositories spk

Rev

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