Subversion Repositories spk

Rev

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