Subversion Repositories spk

Rev

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

Rev Author Line No. Line
6 cycrow 1
// SpkFile.cpp: implementation of the CSpkFile class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
 
5
#include "BaseFile.h"
6
 
7
//////////////////////////////////////////////////////////////////////
8
// Construction/Destruction
9
//////////////////////////////////////////////////////////////////////
10
 
11
#include "spk.h"
12
 
13
#include "DirIO.h"
14
#include "File_IO.h"
15
#include "CatFile.h"
16
#include "archive/zip.h"
17
#include "Packages.h"
18
 
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
 
14 cycrow 1033
void CBaseFile::_install_adjustFakePatches(CPackages *pPackages)
6 cycrow 1034
{
1035
	CyStringList lPatches;
14 cycrow 1036
	int startfake = pPackages->FindNextFakePatch();
6 cycrow 1037
 
14 cycrow 1038
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1039
	{
1040
		C_File *fit = node->Data();
1041
		// only do fake patchs
1042
		if ( !fit->IsFakePatch() )
1043
			continue;
1044
 
1045
		// we should only have cat and dat files, but lets check just incase they have been added incorrectly
1046
		if ( !fit->CheckFileExt ("cat") && !fit->CheckFileExt("dat") )
1047
			continue;
1048
 
1049
		// search for the name on the list
1050
		SStringList *opposite = lPatches.FindString(fit->GetBaseName());
1051
		CyString newname;
1052
		if ( opposite )
1053
			newname = opposite->data;
1054
		else
1055
		{
1056
			newname = CyString::Number((long)startfake).PadNumber(2);
1057
			lPatches.PushBack(fit->GetBaseName(), newname);
1058
		}
1059
 
1060
		// rename the file
1061
		fit->FixOriginalName();
1062
		fit->SetName ( newname + "." + fit->GetFileExt() );
1063
 
1064
		// find the next gap
1065
		if ( !opposite ) {
1066
			startfake = pPackages->FindNextFakePatch(startfake + 1);
1067
		}
1068
	}
1069
 
1070
}
1071
 
43 cycrow 1072
void CBaseFile::_install_renameText(CPackages *pPackages)
14 cycrow 1073
{
43 cycrow 1074
	int starttext = pPackages->FindNextTextFile();
1075
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
1076
		C_File *fit = node->Data();
1077
		if ( !fit->IsAutoTextFile() )
1078
			continue;
6 cycrow 1079
 
43 cycrow 1080
		CyString newname = SPK::FormatTextName(starttext, pPackages->GetLanguage(), (pPackages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));
1081
		fit->FixOriginalName();
1082
		fit->SetName ( newname + "." + fit->GetFileExt() );
6 cycrow 1083
 
43 cycrow 1084
		++starttext;
1085
	}
1086
}
6 cycrow 1087
 
43 cycrow 1088
bool CBaseFile::InstallFiles ( CyString destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, CyStringList *errorStr, bool enabled, CPackages *packages )
1089
{
1090
	if ( enabled ) {
14 cycrow 1091
		this->_install_adjustFakePatches(packages);
43 cycrow 1092
		if ( packages ) this->_install_renameText(packages);
6 cycrow 1093
	}
1094
 
1095
	CDirIO Dir(destdir);
1096
	int fileCount = 0;
1097
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1098
	{
1099
		C_File *fit = node->Data();
1100
		bool fileEnabled = enabled;
1101
		if ( !fileEnabled )
1102
		{
1103
			if ( (fit->GetFileType() == FILETYPE_UNINSTALL) || (fit->GetFileType() == FILETYPE_README) || (fit->GetFileType() == FILETYPE_ADVERT) )
1104
				fileEnabled = true;
1105
			else if ( (fit->GetFileType() == FILETYPE_EXTRA) && (fit->GetDir().Left(7).ToLower() == "Extras/") )
1106
				fileEnabled = true;
1107
			else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )
1108
				fileEnabled = true;
1109
		}
1110
 
1111
		if ( fit->GetGame() && packages->GetGame() ) {
1112
			if ( fit->GetGame() != packages->GetGame() )
1113
				continue;
1114
		}
1115
 
1116
		if ( progress )
1117
		{
1118
			if ( progress->IsSecond() )
1119
				progress->SwitchSecond();
1120
			progress->UpdateFile ( fit );
1121
			progress->UpdateProgress(fileCount++, m_lFiles.size());
1122
			progress->SwitchSecond();
1123
		}
1124
 
1125
		// first uncompress the file
1126
		bool uncomprToFile = false;
1127
		m_sLastError = fit->GetNameDirectory(this);
1128
		m_iLastError = SPKERR_UNCOMPRESS;
1129
		if ( !fit->UncompressData ( progress ) )
1130
		{
1131
			if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP )
1132
			{
1133
				if ( fit->UncompressToFile ( NullString, this, false, progress ) )
1134
					uncomprToFile = true;
1135
			}
1136
 
1137
			if ( !uncomprToFile )
1138
			{
1139
				if ( errorStr )
1140
					errorStr->PushBack(m_sLastError, ERRORLOG(SPKINSTALL_UNCOMPRESS_FAIL));
1141
				return false;
1142
			}
1143
		}
1144
		ClearError ();
1145
		bool dofile = true;
1146
 
1147
		// new check if we should install the file
1148
		// first get the version
14 cycrow 1149
		if ( !m_bOverrideFiles && fit->ReadScriptVersion() )
6 cycrow 1150
		{
1151
			C_File checkfile;
1152
			CyString checkfilename = destdir;
1153
			if ( !checkfilename.Empty() )
1154
				checkfilename += "/";
1155
			checkfilename += fit->GetNameDirectory(this);
1156
			checkfile.SetFilename ( checkfilename );
1157
			checkfile.SetFileType ( fit->GetFileType() );
1158
			if ( checkfile.CheckValidFilePointer() )
1159
			{
1160
				if ( checkfile.ReadScriptVersion() > fit->GetVersion() )
1161
					dofile = false;
1162
			}
1163
		}
1164
 
1165
		// change file pointer
1166
		CyString filename = destdir;
1167
		if ( !filename.Empty() )
1168
			filename += "/";
1169
		if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) )
1170
			fit->SetDir ( CyString("Patch") );
1171
 
1172
		if ( fit->IsInMod() )
1173
		{
1174
			if ( fileEnabled )
1175
				fit->SetFilename(filename + fit->GetInMod() + "::" + fit->GetNameDirectory(this));
1176
			else
1177
				fit->SetFilename(filename + "PluginManager/DisabledFiles.cat::" + fit->GetNameDirectory(this));
1178
		}
1179
		else
1180
			fit->SetFilename ( filename + fit->GetNameDirectory(this) );
1181
 
1182
		if ( !fileEnabled )
1183
		{
1184
			if ( !fit->IsInMod() )
1185
			{
1186
				if ( fit->IsFakePatch() )
1187
					fit->SetFilename ( filename + "PluginManager/Disabled/FakePatches/FakePatch_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );
1188
				else if ( fit->IsAutoTextFile() )
1189
					fit->SetFilename ( filename + "PluginManager/Disabled/TextFiles/Text_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );
1190
				else
1191
					fit->SetFullDir ( filename + "PluginManager/Disabled/" + fit->GetDirectory(this) );
1192
			}
1193
			fit->SetDisabled(true);
1194
		}
1195
 
1196
		C_File *adjustPointer = NULL;
1197
 
1198
		bool checkFile = dofile;
1199
		if ( filelist )
1200
		{
1201
			C_File *cFile = NULL;
1202
			if ( checkFile )
1203
			{
1204
				if ( !fit->IsFakePatch() && fit->GetFileType() != FILETYPE_README )
1205
				{
1206
					for ( cFile = filelist->First(); cFile; cFile = filelist->Next() )
1207
					{
1208
						if ( !cFile->MatchFile ( fit ) )
1209
							continue;
1210
 
1211
						if ( !m_bOverrideFiles && !cFile->CompareNew ( fit ) )
1212
						{
1213
							if ( errorStr )
1214
								errorStr->PushBack(fit->GetNameDirectory(this), ERRORLOG(SPKINSTALL_SKIPFILE));
1215
							dofile = false;
1216
						}
1217
						break;
1218
					}
1219
				}
1220
			}
1221
 
1222
			// no matching file found, adding to main list
1223
			if ( !cFile )
1224
				filelist->push_back ( fit );
1225
			else
1226
			{
1227
				// if the file is not enabled, we need to check for any that might be enabled
1228
				if ( !fileEnabled )
1229
				{
1230
					if ( !cFile->GetUsed() )
1231
					{
1232
						CFileIO rFile(cFile->GetFilePointer());
1233
						if ( rFile.Exists() )
1234
						{
1235
							if ( errorStr )
1236
							{
1237
								if ( rFile.Remove() )
1238
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));
1239
								else
1240
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));
1241
							}
1242
						}
1243
						cFile->SetFilename(fit->GetFilePointer());
1244
						cFile->SetDisabled(true);
1245
					}
1246
					else
1247
					{
1248
						fit->SetFullDir ( filename + fit->GetDirectory(this) );
1249
						fit->SetDisabled(false);
1250
					}
1251
				}
1252
				else
1253
				// move it to enabled
1254
				{
1255
					// found a file, check if its in the disabled directory
1256
					CyString dir = cFile->GetFilePointer();
1257
					dir = dir.GetToken ( 1, dir.NumToken ('/') - 1, '/' );
1258
					CyString lastDir = dir.GetToken ( dir.NumToken('/'), '/' ).ToLower();
1259
 
1260
					// if its disabled, rename it so its enabled
1261
					if ( ((cFile->IsDisabled()) || (lastDir == "disabled") || (dir.ToLower().IsIn ("/disabled/"))) && (enabled) )
1262
					{
1263
						// first check if the directory exists
1264
						if ( cFile->IsInMod() )
1265
						{
1266
							CyString tofile = cFile->GetFilePointer().GetToken("::", 2, 2);
1267
 
1268
							CCatFile tocat;
1269
							int err = tocat.Open ( fit->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, true );
1270
							if ( (err == CATERR_NONE) || (err == CATERR_CREATED) )
1271
							{
1272
								tocat.AppendFile ( cFile->GetFilePointer(), tofile );
1273
							}
1274
 
1275
							CCatFile fromcat;
1276
							err = fromcat.Open ( cFile->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, false );
1277
							if ( err == CATERR_NONE )
1278
							{
1279
								fromcat.RemoveFile(tofile);
1280
							}
1281
 
1282
							cFile->SetFilename ( fit->GetFilePointer() );
1283
							cFile->SetInMod(fit->GetInMod());
1284
						}
1285
						else
1286
						{
1287
							CyString to = cFile->GetDirectory(this);
1288
							CDirIO Dir(destdir);
1289
							if ( !Dir.Exists(to) )
1290
							{
1291
								if ( !Dir.Create ( to ) )
1292
								{
1293
									if ( errorStr )
1294
										errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1295
									return false;
1296
								}
1297
								if ( errorStr )
1298
									errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1299
							}
1300
 
1301
							CyString destfile = destdir + "/" + cFile->GetNameDirectory(this);
1302
							if ( CFileIO(destfile).Exists() )
1303
								CFileIO(destfile).Remove();
1304
							rename ( cFile->GetFilePointer().c_str(), destfile.c_str() );
1305
							cFile->SetFilename ( destdir + "/" + cFile->GetNameDirectory(this) );
1306
						}
1307
						cFile->SetDisabled(false);
1308
 
1309
						if ( !dofile && errorStr )
1310
							errorStr->PushBack(cFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));
1311
					}
1312
				}
1313
 
1314
				adjustPointer = cFile;
1315
				if ( dofile )
1316
					adjustPointer->SetCreationTime ( fit->GetCreationTime() );
1317
			}
1318
		}
1319
 
1320
		if ( dofile )
1321
		{
1322
			// uncompressed to file, rename and move
1323
			if ( uncomprToFile )
1324
			{
1325
				m_iLastError = SPKERR_WRITEFILE;
1326
				CyString to = fit->GetDirectory(this);
1327
				//to = to.GetToken ( 1, to.NumToken ('/') - 1, '/' );
1328
				if ( !fileEnabled )
1329
					to = CyString("PluginManager/Disabled/") + to;
1330
 
1331
				CDirIO Dir(destdir);
1332
				if ( !Dir.Exists(to) )
1333
				{
1334
					if ( !Dir.Create ( to ) )
1335
					{
1336
						if ( errorStr )
1337
							errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1338
						return false;
1339
					}
1340
					if ( errorStr )
1341
						errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1342
				}
1343
 
1344
				int err = 1;
1345
				m_sLastError = to;
1346
				if ( !fit->GetTempFile ().Empty() )
1347
					err = rename ( fit->GetTempFile().c_str(), to.c_str() );
1348
				if ( err )
1349
					return false;
1350
			}
1351
			//otherwise, just extract the file
1352
			else
1353
			{
1354
				// old file is found in list, switch to using new one
1355
				if ( (filelist) && (adjustPointer) )
1356
					adjustPointer->CopyData(fit, false);
1357
 
1358
				CyString fpointer = fit->GetFilePointer();
1359
				m_iLastError = SPKERR_CREATEDIRECTORY;
1360
				CyString dir = fit->GetFilePointer().GetToken ( "/", 1, fit->GetFilePointer().NumToken("/") - 1 );
1361
 
1362
				dir = dir.Remove(destdir);
1363
				if ( dir[0] == '/' || dir[0] == '\\' )
1364
					dir.Erase(0, 1);
1365
 
1366
				m_sLastError = dir;
1367
				if ( !dir.IsIn ( "::" ) )
1368
				{
1369
					if ( !Dir.Exists(dir) )
1370
					{
1371
						if ( !Dir.Create(dir) )
1372
						{
1373
							if ( errorStr )
1374
								errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1375
							return false;
1376
						}
1377
						if ( errorStr )
1378
							errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1379
					}
1380
				}
1381
				else
1382
					fit->SetFilename(CCatFile::PckChangeExtension(fit->GetFilePointer()));
1383
 
1384
				m_iLastError = SPKERR_WRITEFILE;
1385
				m_sLastError = fit->GetFilePointer();
1386
				CyString sInstalledFile = fit->GetNameDirectory(this);
1387
				if ( fit->IsDisabled() )
1388
				{
1389
					sInstalledFile = fit->GetFilePointer().Remove(destdir);
1390
					if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )
1391
						sInstalledFile.Erase(0, 1);
1392
				}
1393
 
1394
				if ( !fit->WriteFilePointer() )
1395
				{
1396
					if ( errorStr )
1397
						errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));
1398
				}
1399
				else
1400
				{
1401
					fit->UpdateSigned();
1402
					if ( errorStr )
1403
						errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));
1404
 
1405
					switch(fit->GetFileType())
1406
					{
1407
						case FILETYPE_SCRIPT:
1408
						case FILETYPE_UNINSTALL:
1409
							fit->UpdateSignature();
1410
							break;
1411
					}
1412
				}
1413
			}
1414
			ClearError ();
1415
		}
1416
 
1417
		if ( adjustPointer )
1418
		{
1419
			node->ChangeData(adjustPointer);
1420
			delete fit;
1421
		}
1422
	}
1423
 
1424
	// now clear or data memory
1425
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1426
	{
1427
		// add plugin manager file to identify fake patches
1428
		/*
1429
		if ( fit->IsFakePatch() && fit->CheckFileExt ("cat") )
1430
		{
1431
			CFileIO plugin("pluginmanager.txt");
1432
			std::vector<CyString> lines;
1433
			CyString version;
1434
			version.FromFloat(GetLibraryVersion(), 2);
1435
			SStringList *strList = lPatches.FindData(fit->GetBaseName());
1436
 
1437
			CyString baseName;
1438
			if ( strList )
1439
				baseName = strList->str;
1440
			else
1441
				baseName = fit->GetBaseName();
1442
 
1443
			lines.push_back(CyString("FakePatch:") + baseName);
1444
			lines.push_back(CyString("spklibrary:") + version);
1445
			lines.push_back(CyString("Package:") + m_sName);
1446
			lines.push_back(CyString("Author:") + m_sAuthor);
1447
			lines.push_back(CyString("OriginalFile:") + fit->GetOriginalName());
1448
			if ( plugin.WriteFile(&lines) )
1449
			{
1450
				CCatFile cat;
1451
				if ( cat.Open(fit->GetFilePointer(), CATREAD_DAT, false) == CATERR_NONE )
1452
				{
1453
					cat.AppendFile(plugin.GetFilename(), plugin.GetFilename(), true);
1454
					cat.WriteCatFile();
1455
				}
1456
				plugin.Remove();
1457
			}
1458
		}
1459
*/
1460
		node->Data()->DeleteData();
1461
	}
1462
 
1463
	return true;
1464
}
1465
 
1466
 
1467
 
1468
/*######################################################################################################*/
1469
 
1470
 
1471
/*
1472
	Func:   ParseHeader
1473
	Input:  Header String - string formated directly from the file
1474
	Return: Boolean - If string is a valid header
1475
	Desc:   Splits up the main header string to get all required settings
1476
*/
1477
bool CBaseFile::ParseHeader ( CyString header )
1478
{
14 cycrow 1479
	if ( !this->CheckHeader(header.GetToken ( 1, ';' ).ToString()) )
6 cycrow 1480
		return false;
1481
 
1482
	m_SHeader.fVersion = header.GetToken ( 2, ';' ).ToFloat();
1483
	if ( m_SHeader.fVersion > FILEVERSION )
1484
		return false;
1485
 
1486
	m_SHeader.iValueCompression = header.GetToken ( 3, ';' ).ToInt();
1487
	m_SHeader.lValueCompressSize = header.GetToken ( 4, ';' ).ToLong();
1488
 
1489
	return true;
1490
}
1491
 
14 cycrow 1492
bool CBaseFile::CheckHeader(const Utils::String header) const
6 cycrow 1493
{
1494
	if ( header.Compare("BaseCycrow") )
1495
		return true;
1496
	return false;
1497
}
1498
 
1499
/*
1500
	Func:   ParseFileHeader
1501
	Input:  Header String - string formated directly from the file
1502
	Return: Boolean - If string is a valid header
1503
	Desc:   Splits up the file header string to get all required settings
1504
*/
1505
bool CBaseFile::ParseFileHeader ( CyString header )
1506
{
1507
	if ( header.GetToken ( 1, ';' ) != "FileHeader" )
1508
		return false;
1509
 
1510
	m_SHeader2.iNumFiles = header.GetToken ( 2, ';' ).ToInt();
1511
	m_SHeader2.lSize = header.GetToken ( 3, ';' ).ToInt();
1512
	m_SHeader2.lFullSize = header.GetToken ( 4, ';' ).ToInt();
1513
	m_SHeader2.iFileCompression = header.GetToken ( 5, ';' ).ToInt();
1514
	m_SHeader2.iDataCompression = header.GetToken ( 6, ';' ).ToInt();
1515
 
1516
	return true;
1517
}
1518
 
1519
 
1520
/*
1521
	Func:   ParseValueLine
1522
	Input:  String - single line from a file to set
1523
	Return: Boolean - returns true if value exists
1524
	Desc:   Reads the line and assigns the parameters for the file
1525
*/
14 cycrow 1526
bool CBaseFile::ParseValueLine(const Utils::String &sLine)
6 cycrow 1527
{
14 cycrow 1528
	Utils::String first = sLine.token(" ", 1);
1529
	Utils::String rest  = sLine.tokens(" ", 2);
6 cycrow 1530
 
14 cycrow 1531
	if ( first.Compare("Name:") )
6 cycrow 1532
		m_sName = rest;
14 cycrow 1533
	else if ( first.Compare("Author:") )
6 cycrow 1534
		m_sAuthor = rest;
14 cycrow 1535
	else if ( first.Compare("Version:") )
6 cycrow 1536
		m_sVersion = rest;
14 cycrow 1537
	else if ( first.Compare("fGameVersion:") ) {
6 cycrow 1538
		if ( m_lGames.Back() ) {
1539
			m_lGames.Back()->Data()->sVersion = rest;
1540
		}
1541
	}
14 cycrow 1542
	else if ( first.Compare("GameVersion:") ) {
6 cycrow 1543
		if ( m_lGames.Back() ) {
14 cycrow 1544
			m_lGames.Back()->Data()->iVersion = rest;
6 cycrow 1545
		}
1546
	}
14 cycrow 1547
	else if ( first.Compare("Game:") )
1548
		this->AddGameCompatability(rest, NullString);
1549
	else if ( first.Compare("GameCompat:") )
1550
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
1551
	else if ( first.Compare("GameCompatExact:") )
1552
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
1553
	else if ( first.Compare("Date:") )
6 cycrow 1554
		m_sCreationDate = rest;
14 cycrow 1555
	else if ( first.Compare("WebAddress:") )
6 cycrow 1556
		m_sWebAddress = rest;
14 cycrow 1557
	else if ( first.Compare("WebSite:") )
6 cycrow 1558
		m_sWebSite = rest;
14 cycrow 1559
	else if ( first.Compare("Email:") )
6 cycrow 1560
		m_sEmail = rest;
14 cycrow 1561
	else if ( first.Compare("WebMirror1:") || first.Compare("Mirror1:") || first.Compare("WebMirror:") )
6 cycrow 1562
		this->AddWebMirror(rest);
14 cycrow 1563
	else if ( first.Compare("WebMirror2:") || first.Compare("Mirror2:") )
6 cycrow 1564
		this->AddWebMirror(rest);
14 cycrow 1565
	else if ( first.Compare("PluginType:") )
1566
		m_iPluginType = rest;
1567
	else if ( first.Compare("Desc:") )
6 cycrow 1568
	{
1569
		m_sDescription = rest;
1570
		m_sDescription.RemoveFirstChar('\n');
1571
		m_sDescription.RemoveFirstChar('\r');
1572
		m_sDescription.RemoveFirstSpace();
1573
		m_sDescription = m_sDescription.FindReplace("&quot;", "\"");
1574
		m_sDescription = m_sDescription.FindReplace("&gt;", ">");
1575
		m_sDescription = m_sDescription.FindReplace("&lt;", "<");
1576
		m_sDescription = m_sDescription.FindReplace("&amp;", "&");
1577
		m_sDescription = m_sDescription.FindReplace("<newline>", "\n");
1578
		m_sDescription = m_sDescription.FindReplace("<br>", "\n");
1579
 
1580
		if ( m_sDescription.Left(6).lower() == "<html>" )
1581
		{
1582
			int foundFirst = -1;
1583
			int pos = 0;
1584
			while ( foundFirst == -1 )
1585
			{
1586
				pos = m_sDescription.FindPos(">", pos);
1587
 
1588
				pos++;
1589
				if ( pos >= (int)m_sDescription.Length() )
1590
					break;
1591
				char c = m_sDescription[pos];
1592
 
1593
				if ( c != '<' )
1594
					foundFirst = pos;
1595
			}
1596
 
1597
			if ( foundFirst == -1 )
1598
				m_sDescription = "";
1599
			else
1600
			{
1601
				CyString firstStr = m_sDescription.Left(foundFirst);
1602
				firstStr.FindRemove("<br />");
1603
				firstStr.FindRemove("<br/>");
1604
				CyString lastStr = m_sDescription.Right(m_sDescription.Length() - foundFirst);
1605
 
1606
				m_sDescription = firstStr + lastStr;
1607
			}
1608
		}
1609
	}
14 cycrow 1610
	else if ( first.Compare("UninstallAfter:") )
1611
		AddUninstallAfterText(ParseInstallText(rest.token("|", 1)), rest.tokens("|", 2));
1612
	else if ( first.Compare("UninstallBefore:") )
1613
		AddUninstallBeforeText(ParseInstallText(rest.token("|", 1)), rest.tokens("|", 2));
1614
	else if ( first.Compare("InstallAfter:") )
1615
		AddInstallAfterText(ParseInstallText(rest.token("|", 1)), rest.tokens("|", 2));
1616
	else if ( first.Compare("InstallBefore:") )
1617
		AddInstallBeforeText(ParseInstallText(rest.token("|", 1)), rest.tokens("|", 2));
1618
	else if ( first.Compare("ScriptName:") )
1619
		AddLanguageName(ParseLanguage(rest.token(":", 1)), rest.token(":", 2));
1620
	else if ( first.Compare("GameChanging:") )
1621
		m_iGameChanging = rest;
1622
	else if ( first.Compare("EaseOfUse:") )
1623
		m_iEaseOfUse = rest;
1624
	else if ( first.Compare("Recommended:") )
1625
		m_iRecommended = rest;
1626
	else if ( first.Compare("NeededLibrary:") )
1627
		this->AddNeededLibrary(rest.token("||", 1), rest.token("||", 2), rest.token("||", 3));
1628
	else if ( first.Compare("FakePatchBefore:") )
1629
		this->AddFakePatchOrder(false, rest.token("||", 1), rest.token("||", 2));
1630
	else if ( first.Compare("FakePatchAfter:") )
1631
		this->AddFakePatchOrder(true, rest.token("||", 1), rest.token("||", 2));
1632
	else if ( first.Compare("ForumLink:") )
6 cycrow 1633
		m_sForumLink = rest;
1634
	else
1635
		return false;
1636
 
1637
	return true;
1638
}
1639
 
1640
int CBaseFile::ParseLanguage(CyString lang)
1641
{
1642
	int langID = lang.ToInt();
1643
 
1644
	if ( !langID )
1645
	{
1646
		lang = lang.ToLower();
1647
		if ( lang == "english" )
1648
			return 44;
1649
		else if ( lang == "default" )
1650
			return 0;
1651
		else if ( lang == "german" )
1652
			return 49;
1653
		else if ( lang == "russian" )
1654
			return 7;
1655
		else if ( lang == "spanish" )
1656
			return 34;
1657
		else if ( lang == "french" )
1658
			return 33;
1659
	}
1660
 
1661
	return langID;
1662
}
1663
 
1664
 
1665
int CBaseFile::ParseInstallText(CyString lang)
1666
{
1667
	return this->ParseLanguage(lang);
1668
}
1669
 
1670
 
1671
/*
1672
	Func:   ReadValues
1673
	Input:  String - values in one long line
1674
	Desc:   splits the values data into each line to read the data
1675
*/
1676
void CBaseFile::ReadValues ( CyString values )
1677
{
1678
	int num = 0;
1679
	CyString *lines = values.SplitToken ( '\n', &num );
1680
 
1681
	for ( int i = 0; i < num; i++ )
14 cycrow 1682
		ParseValueLine ( lines[i].ToString() );
6 cycrow 1683
 
1684
	CLEANSPLIT(lines, num)
1685
}
1686
 
1687
/*
1688
	Func:   ParseFilesLine
1689
	Input:  String - single line from a file to set
1690
	Return: Boolean - returns true if value exists
1691
	Desc:   Reads the line and assigns the parameters for the file
1692
*/
1693
bool CBaseFile::ParseFilesLine ( CyString line )
1694
{
1695
	if ( !line.IsIn(":") )
1696
		return false;
1697
 
1698
	CyString command = line.GetToken ( 1, ':' );
1699
 
1700
	long size = line.GetToken ( 2, ':').ToInt ();
1701
	long usize = line.GetToken ( 3, ':').ToInt ();
1702
	long compression = line.GetToken ( 4, ':').ToInt ();
1703
 
1704
	if ( command == "Icon" )
1705
	{
1706
		m_sIconExt = line.GetToken ( 5, ':' );
1707
		m_pIconFile = new C_File ();
1708
		m_pIconFile->SetDataSize ( size - 4 );
1709
		m_pIconFile->SetDataCompression ( compression );
1710
		m_pIconFile->SetUncompressedDataSize ( usize );
1711
 
1712
		return true;
1713
	}
1714
 
1715
	time_t time = line.GetToken ( 5,':' ).ToLong();
1716
	bool compressToFile = (line.GetToken ( 6, ':').ToInt() == 1) ? true : false;
1717
	CyString name  = line.GetToken ( 7, ':' );
1718
	CyString dir = line.GetToken ( 8, ':' );
1719
 
1720
	if ( name.Empty() )
1721
		return true;
1722
 
1723
	bool shared = false;
1724
	if ( command.Left(1) == "$" )
1725
	{
1726
		shared = true;
1727
		command.Erase ( 0, 1 );
1728
	}
1729
 
1730
	int type = -1;
1731
	if ( command == "Script" )
1732
		type = FILETYPE_SCRIPT;
1733
	else if ( command == "Text" )
1734
		type = FILETYPE_TEXT;
1735
	else if ( command == "Readme" )
1736
		type = FILETYPE_README;
1737
	else if ( command == "Map" )
1738
		type = FILETYPE_MAP;
1739
	else if ( command == "Mod" )
1740
		type = FILETYPE_MOD;
1741
	else if ( command == "Uninstall" )
1742
		type = FILETYPE_UNINSTALL;
1743
	else if ( command == "Sound" )
1744
		type = FILETYPE_SOUND;
1745
	else if ( command == "Mission" )
1746
		type = FILETYPE_MISSION;
1747
	else if ( command == "Extra" )
1748
		type = FILETYPE_EXTRA;
1749
	else if ( command == "Screen" )
1750
		type = FILETYPE_SCREEN;
1751
	else if ( command == "Backup" )
1752
		type = FILETYPE_BACKUP;
1753
	else if ( command == "Advert" )
1754
		type = FILETYPE_ADVERT;
1755
	else if ( command == "ShipScene" )
1756
		type = FILETYPE_SHIPSCENE;
1757
	else if ( command == "CockpitScene" )
1758
		type = FILETYPE_COCKPITSCENE;
1759
	else if ( command == "ShipOther" )
1760
		type = FILETYPE_SHIPOTHER;
1761
	else if ( command == "ShipModel" )
1762
		type = FILETYPE_SHIPMODEL;
1763
 
1764
	if ( type == -1 )
1765
		return false;
1766
 
1767
	C_File *file = new C_File ();
1768
 
1769
	if ( dir.Left(5).Compare("GAME_") ) {
1770
		file->SetGame(dir.GetToken("_", 2, 2).ToInt());
1771
		dir = NullString;
1772
	} 
1773
	else if ( line.NumToken(":") >= 9 ) {
1774
		file->SetGame(line.GetToken(":", 9, 9).GetToken("_", 2, 2).ToInt());
1775
	}
1776
 
1777
	file->SetFileType ( type );
1778
	file->SetCreationTime ( time );
1779
	file->SetName ( name );
1780
	file->SetDir ( dir );
1781
	file->SetDataSize ( size - 4 );
1782
	file->SetDataCompression ( compression );
1783
	file->SetUncompressedDataSize ( usize );
1784
	file->SetShared ( shared );
1785
	file->SetCompressedToFile ( compressToFile );
1786
 
1787
	m_lFiles.push_back ( file );
1788
 
1789
	return true;
1790
}
1791
 
1792
 
1793
/*
1794
	Func:   ParseFiles
1795
	Input:  String - values in one long line
1796
	Desc:   splits the files data into each line to read the data
1797
*/
1798
void CBaseFile::ReadFiles ( CyString values )
1799
{
1800
	int num = 0;
1801
	CyString *lines = values.SplitToken ( '\n', &num );
1802
 
1803
	for ( int i = 0; i < num; i++ )
1804
		ParseFilesLine ( lines[i] );
1805
 
1806
	CLEANSPLIT(lines, num)
1807
}
1808
 
1809
 
1810
 
1811
/*
1812
	Func:   ReadFile
1813
	Input:  filename - the name of the file to open and read
1814
			readdata - If falses, dont read the files to memory, just read the headers and values
1815
	Return: boolean - return ture if acceptable format
1816
	Desc:   Opens and reads the spk file and loads all data into class
1817
*/
1818
bool CBaseFile::ReadFile ( CyString filename, int readtype, CProgressInfo *progress )
1819
{
1820
	FILE *id = fopen ( filename.c_str(), "rb" );
1821
	if ( !id )
1822
		return false;
1823
 
1824
	bool ret = ReadFile ( id, readtype, progress );
1825
	if ( ret )
1826
		m_sFilename = filename;
1827
 
1828
	fclose ( id );
1829
 
1830
	return ret;
1831
}
1832
bool CBaseFile::ReadFile ( FILE *id, int readtype, CProgressInfo *progress )
1833
{
1834
	ClearError ();
1835
 
1836
	// first read the header
1837
	if ( !ParseHeader ( GetEndOfLine ( id, NULL, false ) ) )
1838
		return false;
1839
 
1840
	if ( readtype == SPKREAD_HEADER )
1841
		return true;
1842
 
1843
	// update the progress for each section
1844
	int maxProgress = (readtype == SPKREAD_VALUES) ? 3 : 6;
1845
	if ( readtype != SPKREAD_ALL && progress )
1846
		progress->UpdateProgress(1, maxProgress);
1847
 
1848
	long doneLen = 0;
1849
	// next read the data values for the spk files
1850
	if ( m_SHeader.lValueCompressSize )
1851
	{
1852
		// read data to memory
1853
		unsigned char *readData = new unsigned char[m_SHeader.lValueCompressSize];
1854
		unsigned char size[4];
1855
		fread ( size, 4, 1, id );
1856
		fread ( readData, sizeof(unsigned char), m_SHeader.lValueCompressSize, id );
1857
		unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
1858
 
1859
		// check for zlib compression
1860
		if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB )
1861
		{
1862
			// uncomress the data
1863
			unsigned char *uncompr = new unsigned char[uncomprLen];
1864
 
1865
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );
1866
			// update the progress for each section
1867
			if ( readtype != SPKREAD_ALL && progress )
1868
				progress->UpdateProgress(2, maxProgress);
1869
			if ( err == Z_OK )
1870
				ReadValues ( CyString ((char *)uncompr) );
1871
			doneLen = uncomprLen;
1872
			delete uncompr;
1873
		}
1874
		else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
1875
		{
1876
			long len = uncomprLen;
1877
			unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lValueCompressSize, (size_t*)&len, NULL );
1878
			// update the progress for each section
1879
			if ( readtype != SPKREAD_ALL && progress )
1880
				progress->UpdateProgress(2, maxProgress);
1881
 
1882
			if ( compr )
1883
				ReadValues ( CyString ((char *)compr) );
1884
		}
1885
		// no compression
1886
		else
1887
			ReadValues ( CyString ((char *)readData) );
1888
 
1889
		delete readData;
1890
	}
1891
 
1892
	// update the progress for each section
1893
	if ( readtype != SPKREAD_ALL && progress )
1894
		progress->UpdateProgress(3, maxProgress);
1895
 
1896
	if ( readtype == SPKREAD_VALUES )
1897
		return true;
1898
 
1899
	// next should be the next header
1900
	if ( !ParseFileHeader ( GetEndOfLine (id, NULL, false) ) )
1901
		return false;
1902
 
1903
	// clear the current file list
1904
	m_lFiles.clear(true);
1905
 
1906
	// update the progress for each section
1907
	if ( readtype != SPKREAD_ALL && progress )
1908
		progress->UpdateProgress(4, maxProgress);
1909
 
1910
	if ( m_SHeader2.lSize )
1911
	{
1912
		unsigned char *readData = new unsigned char[m_SHeader2.lSize];
1913
		unsigned char size[4];
1914
		fread ( size, 4, 1, id );
1915
		fread ( readData, sizeof(char), m_SHeader2.lSize, id );
1916
 
1917
		unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
1918
		// check for zlib compression
1919
		if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB )
1920
		{
1921
 
1922
			if ( uncomprLen < (unsigned long)doneLen )
1923
				uncomprLen = doneLen;
1924
 
1925
			unsigned char *uncompr = new unsigned char[uncomprLen];
1926
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );
1927
			// update the progress for each section
1928
			if ( readtype != SPKREAD_ALL && progress )
1929
				progress->UpdateProgress(5, maxProgress);
1930
			if ( err == Z_OK )
1931
				ReadFiles ( CyString ((char *)uncompr) );
1932
			delete uncompr;
1933
		}
1934
		else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
1935
		{
1936
			long len = uncomprLen;
1937
			unsigned char *compr = LZMADecode_C ( readData, m_SHeader2.lSize, (size_t*)&len, NULL );
1938
			// update the progress for each section
1939
			if ( readtype != SPKREAD_ALL && progress )
1940
				progress->UpdateProgress(5, maxProgress);
1941
			if ( compr )
1942
				ReadFiles ( CyString ((char *)compr) );
1943
		}
1944
		else
1945
			ReadFiles ( CyString ((char *)readData) );
1946
 
1947
		delete readData;
1948
	}
1949
 
1950
	// file mismatch
1951
	long numfiles = m_lFiles.size();
1952
	if ( m_pIconFile )
1953
		++numfiles;
1954
	if ( m_SHeader2.iNumFiles != numfiles )
1955
	{
1956
		m_iLastError = SPKERR_FILEMISMATCH;
1957
		return false;
1958
	}
1959
 
1960
	// update the progress for each section
1961
	if ( readtype != SPKREAD_ALL && progress )
1962
		progress->UpdateProgress(6, maxProgress);
1963
 
1964
	if ( readtype == SPKREAD_ALL )
1965
	{
1966
		int fileCount = 2;
1967
		if ( m_pIconFile )
1968
			m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );
1969
 
1970
		// ok finally we need to read all the files
1971
 
1972
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1973
		{
1974
			node->Data()->ReadFromFile ( id, node->Data()->GetDataSize() );
1975
			if ( progress )
1976
				progress->UpdateProgress(fileCount++, m_lFiles.size() + 2);
1977
		}
1978
 
1979
		m_bFullyLoaded = true;
1980
	}
1981
 
1982
	return true;
1983
}
1984
 
1985
bool CBaseFile::IsMod()
1986
{
1987
	// check for any mod files that are not fake patchs
1988
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
1989
	{
1990
		C_File *f = fNode->Data();
1991
		if ( f->GetFileType() != FILETYPE_MOD )
1992
			continue;
1993
 
1994
		if ( !f->IsFakePatch() )
1995
			return true;
1996
	}
1997
 
1998
	return false;
1999
}
2000
 
13 cycrow 2001
bool CBaseFile::IsFakePatch() const
6 cycrow 2002
{
2003
	// check for any mod files that are not fake patchs
2004
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
2005
	{
2006
		C_File *f = fNode->Data();
2007
		if ( f->GetFileType() != FILETYPE_MOD )
2008
			continue;
2009
 
2010
		if ( f->IsFakePatch() )
2011
			return true;
2012
	}
2013
 
2014
	return false;
2015
}
2016
 
14 cycrow 2017
Utils::String CBaseFile::CreateValuesLine () const
6 cycrow 2018
{
14 cycrow 2019
	Utils::String values("Name: ");
2020
	values += Utils::String(m_sName.ToString()) + "\n";
2021
	values += Utils::String("Author: ") + m_sAuthor.ToString() + "\n";
2022
	values += Utils::String("Version: ") + m_sVersion.ToString() + "\n";
6 cycrow 2023
	if ( !m_sCreationDate.Empty() )
14 cycrow 2024
		values += Utils::String("Date: ") + m_sCreationDate.ToString() + "\n";
6 cycrow 2025
	if ( !m_sWebAddress.Empty() )
14 cycrow 2026
		values += Utils::String("WebAddress: ") + m_sWebAddress.ToString() + "\n";
6 cycrow 2027
	if ( !m_sWebSite.Empty() )
14 cycrow 2028
		values += Utils::String("WebSite: ") + m_sWebSite.ToString() + "\n";
6 cycrow 2029
	if ( !m_sEmail.Empty() )
14 cycrow 2030
		values += Utils::String("Email: ") + m_sEmail.ToString() + "\n";
6 cycrow 2031
	for ( SStringList *str = m_lMirrors.Head(); str; str = str->next )
14 cycrow 2032
		values += Utils::String("WebMirror: ") + str->str.ToString() + "\n";
6 cycrow 2033
	if ( !m_sDescription.Empty() )
2034
	{
14 cycrow 2035
		Utils::String desc = m_sDescription.ToString();
2036
		desc = desc.findReplace("<newline>", "<br>");
2037
		desc = desc.findReplace("\n", "<br>");
2038
		desc.remove('\r');
2039
		values += "Desc: " + desc + "\n";
6 cycrow 2040
	}
2041
 
2042
	for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {
2043
		if ( !gc->Data()->sVersion.Empty() )
14 cycrow 2044
			values += Utils::String("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion.ToString() + "\n";
6 cycrow 2045
		else
14 cycrow 2046
			values += Utils::String("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";
6 cycrow 2047
	}
2048
	if ( !m_sForumLink.Empty() )
14 cycrow 2049
		values += Utils::String("ForumLink: ") + m_sForumLink.ToString() + "\n";
6 cycrow 2050
 
2051
	if ( m_bSigned )
2052
		values += "Signed\n";
2053
 
14 cycrow 2054
	CListNode<SInstallText> *it;
2055
	for ( it = m_lUninstallText.Front(); it; it = it->next() ) {
2056
		if ( !it->Data()->sAfter.Empty() )
2057
			values += (CyString("UninstallAfter: ") + CyString::Number(it->Data()->iLanguage) + "|" + it->Data()->sAfter + "\n").ToString();
2058
		if ( !it->Data()->sBefore.Empty() )
2059
			values += (CyString("UninstallBefore: ") + CyString::Number(it->Data()->iLanguage) + "|" + it->Data()->sBefore + "\n").ToString();
6 cycrow 2060
	}
14 cycrow 2061
	for ( it = m_lInstallText.Front(); it; it = it->next() ) {
2062
		if ( !it->Data()->sAfter.Empty() )
2063
			values += (CyString("InstallAfter: ") + CyString::Number(it->Data()->iLanguage) + "|" + it->Data()->sAfter + "\n").ToString();
2064
		if ( !it->Data()->sBefore.Empty() )
2065
			values += (CyString("InstallBefore: ") + CyString::Number(it->Data()->iLanguage) + "|" + it->Data()->sBefore + "\n").ToString();
6 cycrow 2066
	}
2067
 
14 cycrow 2068
	values += Utils::String("GameChanging: ") + (long)m_iGameChanging + "\n";
2069
	values += Utils::String("EaseOfUse: ") + (long)m_iEaseOfUse + "\n";
2070
	values += Utils::String("Recommended: ") + (long)m_iRecommended + "\n";
6 cycrow 2071
 
14 cycrow 2072
	for ( CListNode<SNames> *nNode = m_lNames.Front(); nNode; nNode = nNode->next() )
2073
		values += Utils::String("ScriptName: ") + (long)nNode->Data()->iLanguage + ":" + nNode->Data()->sName.ToString() + "\n";
6 cycrow 2074
 
14 cycrow 2075
	for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() ) {
6 cycrow 2076
		SNeededLibrary *l = libNode->Data();
14 cycrow 2077
		values += (CyString("NeededLibrary: ") + l->sName + "||" + l->sAuthor + "||" + l->sMinVersion + "\n").ToString();
6 cycrow 2078
	}
2079
 
2080
	for ( SStringList *fpbNode = m_lFakePatchBefore.Head(); fpbNode; fpbNode = fpbNode->next )
14 cycrow 2081
		values += (CyString("FakePatchBefore: ") + fpbNode->str + "||" + fpbNode->data + "\n").ToString();
6 cycrow 2082
	for ( SStringList *fpaNode = m_lFakePatchAfter.Head(); fpaNode; fpaNode = fpaNode->next )
14 cycrow 2083
		values += (CyString("FakePatchAfter: ") + fpaNode->str + "||" + fpaNode->data + "\n").ToString();
6 cycrow 2084
 
14 cycrow 2085
	values += Utils::String("PluginType: ") + (long)m_iPluginType + "\n";
6 cycrow 2086
 
2087
	return values;
2088
}
2089
 
2090
 
2091
/*
2092
	Func:   WriteFile
2093
	Input:  filename - The filename of the spk file to write to
2094
	Desc:   Writes the data to an spk file
2095
*/
2096
bool CBaseFile::WriteFile ( CyString filename, CProgressInfo *progress )
2097
{
2098
	FILE *id = fopen ( filename.c_str(), "wb" );
2099
	if ( !id )
2100
		return false;
2101
 
2102
	bool ret = WriteData ( id, progress );
2103
	fclose ( id );
2104
 
2105
	return ret;
2106
}
2107
 
2108
bool CBaseFile::WriteHeader(FILE *id, int valueheader, int valueComprLen)
2109
{
2110
	fprintf ( id, "BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );
2111
	if ( ferror(id) )
2112
		return false;
2113
	return true;
2114
}
2115
 
2116
bool CBaseFile::WriteData ( FILE *id, CProgressInfo *progress )
2117
{
2118
	int valueheader = m_SHeader.iValueCompression, fileheader = m_SHeader.iValueCompression;
2119
	if ( valueheader == SPKCOMPRESS_7ZIP )
2120
		valueheader = SPKCOMPRESS_ZLIB;
2121
	if ( fileheader == SPKCOMPRESS_7ZIP )
2122
		fileheader = SPKCOMPRESS_ZLIB;
2123
 
2124
	// get the script values
2125
	this->UpdateSigned(true);
2126
	CyString values = this->CreateValuesLine();
2127
 
2128
	// compress the values
2129
	int valueUncomprLen = (int)values.Length();
2130
	unsigned long valueComprLen = 0;
2131
	unsigned char *valueCompr = NULL;
2132
	bool compressed = false;
2133
	if ( valueheader == SPKCOMPRESS_ZLIB )
2134
	{
2135
		valueComprLen = valueUncomprLen;
2136
		if ( valueComprLen < 100 )
2137
			valueComprLen = 200;
2138
		else if ( valueComprLen < 1000 )
2139
			valueComprLen *= 2;
2140
 
2141
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
2142
		int err = compress ( (unsigned char *)valueCompr, &valueComprLen, (const unsigned char *)values.c_str(), (unsigned long)values.Length(), 0 );
2143
		if ( err == Z_OK )
2144
			compressed = true;
2145
	}
2146
 
2147
	if ( !compressed )
2148
	{
2149
		valueComprLen = valueUncomprLen;
2150
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
2151
		memcpy ( valueCompr, values.c_str(), valueComprLen );
2152
		valueheader = SPKCOMPRESS_NONE;
2153
	}
2154
 
2155
	// write the main header to the file
2156
	if ( !this->WriteHeader(id, valueheader, valueComprLen) )
2157
		return false;
2158
 
2159
	// write the compressed data to file
2160
	fputc ( (unsigned char)(valueUncomprLen >> 24), id );
2161
	fputc ( (unsigned char)(valueUncomprLen >> 16), id );
2162
	fputc ( (unsigned char)(valueUncomprLen >> 8), id );
2163
	fputc ( (unsigned char)valueUncomprLen, id );
2164
	fwrite ( valueCompr, sizeof(char), valueComprLen, id );
2165
 
2166
	free ( valueCompr );
2167
 
2168
	// now compress the files header
2169
	// create the files values
2170
	CyString files = CreateFilesLine ( true, progress );
2171
 
2172
	// compress the files values
2173
	long fileUncomprLen = (long)files.Length(), fileComprLen = fileUncomprLen;
2174
	unsigned char *fileCompr = NULL;
2175
 
2176
	compressed = false;
2177
	if ( fileUncomprLen )
2178
	{
2179
		if ( fileheader == SPKCOMPRESS_ZLIB )
2180
		{
2181
			if ( fileComprLen < 100 )
2182
				fileComprLen = 200;
2183
			else if ( fileComprLen < 1000 )
2184
				fileComprLen *= 2;
2185
			fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
2186
			int err = compress ( (unsigned char *)fileCompr, (unsigned long *)&fileComprLen, (const unsigned char *)files.c_str(), (unsigned long)files.Length(), 0 );
2187
			if ( err == Z_OK )
2188
				compressed = true;
2189
		}
2190
	}
2191
 
2192
	// if unable to compress, store it as plain text
2193
	if ( !compressed )
2194
	{
2195
		fileComprLen = fileUncomprLen;
2196
		fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
2197
		memcpy ( fileCompr, files.c_str(), fileComprLen );
2198
		fileheader = SPKCOMPRESS_NONE;
2199
	}
2200
 
2201
	// now write the file header
2202
	m_SHeader2.lSize = fileComprLen;
2203
	fprintf ( id, "FileHeader;%d;%ld;%ld;%d;%d\n", m_SHeader2.iNumFiles, m_SHeader2.lSize, m_SHeader2.lFullSize, fileheader, m_SHeader2.iDataCompression );
2204
 
2205
	fputc ( (unsigned char)(fileUncomprLen >> 24), id );
2206
	fputc ( (unsigned char)(fileUncomprLen >> 16), id );
2207
	fputc ( (unsigned char)(fileUncomprLen >> 8), id );
2208
	fputc ( (unsigned char)fileUncomprLen, id );
2209
	fwrite ( fileCompr, sizeof(char), fileComprLen, id );
2210
 
2211
	free ( fileCompr );
2212
 
2213
	if ( progress )
2214
	{
2215
		progress->UpdateStatus(STATUS_WRITE);
2216
		progress->SetDone(0);
2217
		long max = 0;
2218
		for ( C_File *file = m_lFiles.First(); file; file = m_lFiles.Next() )
2219
			max += file->GetDataSize();
2220
		if ( m_pIconFile )
2221
			max += m_pIconFile->GetDataSize();
2222
		progress->SetMax(max);
2223
	}
2224
 
2225
	// now finally, write all the file data
2226
	if ( m_pIconFile )
2227
	{
2228
		if ( progress )
2229
			progress->UpdateFile(m_pIconFile);
2230
		fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 24), id );
2231
		fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 16), id );
2232
		fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 8), id );
2233
		fputc ( (unsigned char)m_pIconFile->GetUncompressedDataSize(), id );
2234
		fwrite ( m_pIconFile->GetData(), sizeof(char), m_pIconFile->GetDataSize(), id );
2235
		if ( progress )
2236
			progress->IncDone(m_pIconFile->GetDataSize());
2237
	}
2238
 
2239
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2240
	{
2241
		C_File *file = node->Data();
2242
		if ( progress )
2243
			progress->UpdateFile(file);
2244
		fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 24), id );
2245
		fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 16), id );
2246
		fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 8), id );
2247
		fputc ( (unsigned char)file->GetUncompressedDataSize(), id );
2248
		unsigned char *data = file->GetData();
2249
		size_t remaining = file->GetDataSize();
2250
		while ( remaining )
2251
		{
2252
			size_t writeSize = WRITECHUNK;
2253
			if ( writeSize > remaining )
2254
				writeSize = remaining;
2255
 
2256
			size_t written = fwrite ( data, sizeof(char), writeSize, id );
2257
			data += written;
2258
			remaining -= written;
2259
 
2260
			if ( progress )
2261
				progress->IncDone((int)written);
2262
		}
2263
 
2264
	}
2265
 
2266
	m_bChanged = false;
2267
 
2268
	return true;
2269
}
2270
 
2271
 
2272
 
2273
 
2274
 
2275
bool CBaseFile::ExtractFile ( C_File *file, CyString dir, bool includedir, CProgressInfo *progress )
2276
{
2277
	if ( ReadFileToMemory ( file ) )
2278
	{
2279
		// now finally, uncompress the file
2280
		long len = 0;
2281
		unsigned char *data = file->UncompressData ( &len, progress );
2282
		if ( !data )
2283
		{
2284
			// attempt a file decompress
2285
			if ( file->GetCompressionType() == SPKCOMPRESS_7ZIP )
2286
			{
2287
				if ( file->UncompressToFile ( dir, this, includedir, progress ) )
2288
					return true;
2289
			}
2290
			return false;
2291
		}
2292
 
2293
		if ( !file->WriteToDir ( dir, this, includedir, NullString, data, len ) )
2294
			return false;
2295
 
2296
		return true;
2297
 
2298
	}
2299
	else
2300
		return false;
2301
}
2302
 
2303
bool CBaseFile::ExtractFile ( int filenum, CyString dir, bool includedir, CProgressInfo *progress )
2304
{
2305
	// invalid valus
2306
	if ( filenum < 0 )
2307
		return false;
2308
	// out of range
2309
	if ( filenum > m_lFiles.size() )
2310
		return false;
2311
 
2312
	// get the file pointer
2313
	C_File *file = m_lFiles.Get ( filenum );
2314
	return ExtractFile ( file, dir, includedir, progress );
2315
}
2316
 
2317
 
2318
 
2319
bool CBaseFile::ExtractAll ( CyString dir, int game, bool includedir, CProgressInfo *progress )
2320
{
2321
	// no file to read from
2322
	if ( m_sFilename.Empty() )
2323
		return false;
2324
 
2325
	// now open the file
2326
	FILE *id = fopen ( m_sFilename.c_str(), "rb" );
2327
	if ( !id )
2328
		return false;
2329
 
2330
	fseek ( id, 0, SEEK_SET );
2331
	// read the header
2332
	GetEndOfLine ( id, NULL, false );
2333
	// skip past values
2334
	fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );
2335
 
2336
	// read the next header
2337
	GetEndOfLine ( id, NULL, false );
2338
	// skip past files
2339
	fseek ( id, 4, SEEK_CUR );
2340
	fseek ( id, m_SHeader2.lSize, SEEK_CUR );
2341
 
2342
	// now were in the file section
2343
	// skip past each one
2344
	if ( m_pIconFile )
2345
	{
2346
		fseek ( id, 4, SEEK_CUR );
2347
		fseek ( id, m_pIconFile->GetDataSize (), SEEK_CUR );
2348
	}
2349
 
2350
	CDirIO Dir(dir);
2351
 
2352
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2353
	{
2354
		C_File *fit = node->Data();
2355
 
2356
		if ( progress )
2357
			progress->UpdateFile ( fit );
2358
 
2359
		if ( (!fit->GetDataSize ()) || (!fit->GetData()) )
2360
		{
2361
			if ( !fit->ReadFromFile ( id, fit->GetDataSize() ) )
2362
			{
2363
				fclose ( id );
2364
				return false;
2365
			}
2366
		}
2367
		else
2368
			fseek ( id, fit->GetDataSize(), SEEK_CUR );
2369
 
2370
		if ( game ) {
2371
			if ( fit->GetGame() && fit->GetGame() != game )
2372
				continue;
2373
		}
2374
 
2375
		// create directory first
2376
		Dir.Create(fit->GetDirectory(this));
2377
 
2378
		long size = 0;
2379
		unsigned char *data = fit->UncompressData (&size, progress);
2380
		if ( (!data) && (fit->GetCompressionType() == SPKCOMPRESS_7ZIP) )
2381
		{
2382
			if ( !fit->UncompressToFile ( dir, this, includedir, progress ) )
2383
			{
2384
				fclose ( id );
2385
				return false;
2386
			}
2387
		}
2388
		else if ( (!data) || (!fit->WriteToDir ( dir, this, includedir, NullString, data, size )) )
2389
		{
2390
			fclose ( id );
2391
			return false;
2392
		}
2393
	}
2394
 
2395
	fclose ( id );
2396
 
2397
	return true;
2398
}
2399
 
2400
 
2401
 
2402
 
2403
bool CBaseFile::UpdateSigned (bool updateFiles)
2404
{
2405
	m_bSigned = true;
2406
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2407
	{
2408
		C_File *file = node->Data();
2409
		if ( updateFiles )
2410
			file->UpdateSigned();
2411
		// extra, text, soundtrack, readmes and screen files do not require a modified game directly
2412
		if ( (file->GetFileType() == FILETYPE_EXTRA) || (file->GetFileType() == FILETYPE_TEXT) || (file->GetFileType() == FILETYPE_SOUND) || (file->GetFileType() == FILETYPE_SCREEN) || (file->GetFileType() == FILETYPE_README) )
2413
			continue;
2414
		// mods and maps always need modified game
2415
		else if ( (file->GetFileType() == FILETYPE_MOD) || (file->GetFileType() == FILETYPE_MAP) )
2416
		{
2417
			m_bSigned = false;
2418
			break;
2419
		}
2420
 
2421
		// else should be a script file, script or uninstall type
2422
		// all scripts must be signed, if any are not, then no signed status
2423
		if ( !file->IsSigned () )
2424
		{
2425
			m_bSigned = false;
2426
			break;
2427
		}
2428
	}
2429
 
2430
	return m_bSigned;
2431
}
2432
 
2433
 
2434
bool CBaseFile::IsPackageNeeded(CyString scriptName, CyString author)
2435
{
2436
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2437
	{
2438
		SNeededLibrary *l = node->Data();
2439
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2440
			return true;
2441
	}
2442
 
2443
	return false;
2444
}
2445
 
2446
SNeededLibrary *CBaseFile::FindPackageNeeded(CyString scriptName, CyString author)
2447
{
2448
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2449
	{
2450
		SNeededLibrary *l = node->Data();
2451
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2452
			return l;
2453
	}
2454
 
2455
	return NULL;
2456
}
2457
 
2458
void CBaseFile::RemoveFakePatchOrder(CyString scriptName, CyString author)
2459
{
2460
	RemoveFakePatchOrder(true, scriptName, author);
2461
	RemoveFakePatchOrder(false, scriptName, author);
2462
}
2463
void CBaseFile::RemoveFakePatchOrder(bool after, CyString scriptName, CyString author)
2464
{
2465
	CyStringList *list;
2466
	if ( after )
2467
		list = &m_lFakePatchAfter;
2468
	else
2469
		list = &m_lFakePatchBefore;
2470
 
2471
	for ( SStringList *str = list->Head(); str; str = str->next )
2472
	{
2473
		// already added
2474
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
2475
			str->remove = true;
2476
	}
2477
 
2478
	list->RemoveMarked();
2479
}
2480
 
2481
void CBaseFile::AddFakePatchOrder(bool after, CyString scriptName, CyString author)
2482
{
2483
	CyStringList *list;
2484
	if ( after )
2485
		list = &m_lFakePatchAfter;
2486
	else
2487
		list = &m_lFakePatchBefore;
2488
 
2489
	// check if the package already exists
2490
	for ( SStringList *str = list->Head(); str; str = str->next )
2491
	{
2492
		// already added
2493
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
2494
			return;
2495
	}
2496
 
2497
	// cant have it on both list
2498
	RemoveFakePatchOrder(!after, scriptName, author);
2499
 
2500
	list->PushBack(scriptName, author);
2501
}
2502
void CBaseFile::AddNeededLibrary(CyString scriptName, CyString author, CyString minVersion)
2503
{
2504
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2505
	if ( !l )
2506
	{
2507
		l = new SNeededLibrary;
2508
		l->sName = scriptName;
2509
		l->sAuthor = author;
2510
		m_lNeededLibrarys.push_back(l);
2511
	}
2512
	l->sMinVersion = minVersion;
2513
}
2514
 
2515
void CBaseFile::RemovePackageNeeded(CyString scriptName, CyString author)
2516
{
2517
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2518
	if ( l )
2519
	{
2520
		m_lNeededLibrarys.remove(l);
2521
		delete l;
2522
	}
2523
}
2524
 
2525
void CBaseFile::ClearNeededPackages()
2526
{
2527
	SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");
2528
	CyString version;
2529
	if ( ns )
2530
		version = ns->sMinVersion;
2531
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2532
		node->DeleteData();
2533
	m_lNeededLibrarys.clear();
2534
 
2535
	if ( !version.Empty() )
2536
		this->AddNeededLibrary("<package>", "<author>", version);
2537
}
2538
 
2539
 
2540
bool CBaseFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
2541
{
2542
	list->PushBack("#");
2543
	list->PushBack(CyString("# Packager Script"));
2544
	list->PushBack(CyString("# -- Generated by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2) + " --");
2545
	list->PushBack("#");
2546
	list->PushBack("");
2547
	if ( !datafile )
2548
	{
2549
		list->PushBack("# Variable for your game directory, where to get files from");
2550
		list->PushBack("# $PATH variable is used to get the current path");
2551
		list->PushBack("Variable: $GAMEDIR $PATH");
2552
		list->PushBack("");
2553
	}
2554
	list->PushBack("# The name of the script");
2555
	list->PushBack(CyString("Name: ") + m_sName);
2556
	list->PushBack("");
2557
	list->PushBack("# The author of the script, ie, you");
2558
	list->PushBack(CyString("Author: ") + m_sAuthor);
2559
	list->PushBack("");
2560
	list->PushBack("# The creation data, when it was created");
2561
	if ( datafile )
2562
		list->PushBack(CyString("Date: ") + m_sCreationDate);
2563
	else
2564
	{
2565
		list->PushBack("# $DATE variable is used to get the current date");
2566
		list->PushBack("Date: $DATE");
2567
	}
2568
	list->PushBack("");
2569
	list->PushBack("# The version of script");
2570
	if ( datafile )
2571
		list->PushBack(CyString("Version: ") + m_sVersion);
2572
	else
2573
	{
2574
		list->PushBack("# $ASK variable is used to get an input when creating");
2575
		list->PushBack("Version: $ASK");
2576
	}
2577
	list->PushBack("");
2578
 
2579
	if ( !m_lGames.empty() ) {
2580
		list->PushBack("# The game version the script is for <game> <version> (can have multiple games)");
2581
		for ( SGameCompat *g = m_lGames.First(); g; g = m_lGames.Next() ) {
13 cycrow 2582
			Utils::String game = CBaseFile::ConvertGameToString(g->iGame);
6 cycrow 2583
 
2584
			if ( !g->sVersion.Empty() )
2585
			{
2586
				game += " ";
13 cycrow 2587
				game += g->sVersion.ToString();
6 cycrow 2588
			}
2589
			else
2590
			{
2591
				game += " ";
2592
				game += (long)g->iVersion;
2593
			}
2594
 
2595
			list->PushBack(CyString("Game: ") + game);
2596
		}
2597
 
2598
		list->PushBack("");
2599
	}
2600
 
2601
	if ( !m_sDescription.Empty() )
2602
	{
2603
		list->PushBack("# The description of the script, displays when installing");
2604
		list->PushBack(CyString("Description: ") + m_sDescription);
2605
		list->PushBack("");
2606
	}
2607
 
2608
	if ( !m_sWebSite.Empty() )
2609
	{
2610
		list->PushBack("# A link to the website for the script, ie for an online help page");
2611
		list->PushBack(CyString("WebSite: ") + m_sWebSite);
2612
		list->PushBack("");
2613
	}
2614
 
2615
	if ( !m_sForumLink.Empty() )
2616
	{
2617
		list->PushBack("# A direct link to the thread in the egosoft forum");
2618
		list->PushBack(CyString("ForumLink: ") + m_sForumLink);
2619
		list->PushBack("");
2620
	}
2621
 
2622
	if ( !m_sWebAddress.Empty() )
2623
	{
2624
		list->PushBack("# A link to the address for the update file");
2625
		list->PushBack(CyString("WebAddress: ") + m_sWebAddress);
2626
		list->PushBack("");
2627
	}
2628
 
2629
	if ( !m_sEmail.Empty() )
2630
	{
2631
		list->PushBack("# The email address of the author, to allow users to contract if needed");
2632
		list->PushBack(CyString("Email: ") + m_sEmail);
2633
		list->PushBack("");
2634
	}
2635
 
2636
	if ( m_lMirrors.Count() )
2637
	{
2638
		list->PushBack("# A link to the mirror address for the update file, can have many of these");
2639
		for ( SStringList *node = m_lMirrors.Head(); node; node = node->next )
2640
			list->PushBack(CyString("WebMirror: ") + node->str);
2641
		list->PushBack("");
2642
	}
2643
 
2644
	if ( m_bAutoGenerateUpdateFile )
2645
	{
2646
		list->PushBack("# Auto generate the package update file when created");
2647
		list->PushBack("GenerateUpdateFile");
2648
	}
2649
 
2650
	if ( m_lNeededLibrarys.size() )
2651
	{
2652
		list->PushBack("# Needed Library dependacies, require these to be installed");
2653
		for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2654
			list->PushBack(CyString("Depend: ") + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);
2655
 
2656
		list->PushBack("");
2657
	}
2658
 
2659
	if ( m_iEaseOfUse != -1 && m_iRecommended != -1 && m_iGameChanging != -1 )
2660
	{
2661
		list->PushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");
2662
		list->PushBack(CyString("Ratings: ") + (long)m_iEaseOfUse + " " + (long)m_iGameChanging + " " + (long)m_iRecommended);
2663
		list->PushBack("");
2664
	}
2665
 
2666
	if ( m_lNames.size() )
2667
	{
2668
		list->PushBack("# Package names, uses different names for different languages");
2669
		for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
2670
			list->PushBack(CyString("ScriptName: ") + (long)node->Data()->iLanguage + " " + node->Data()->sName);
2671
		list->PushBack("");
2672
	}
2673
 
2674
	if ( m_lInstallText.size() )
2675
	{
2676
		list->PushBack("# Install Texts, display text before and/or after installing to inform the use of special conditions");
2677
		for ( CListNode<SInstallText> *node = m_lInstallText.Front(); node; node = node->next() )
2678
		{
2679
			if ( !node->Data()->sBefore.Empty() )
2680
				list->PushBack(CyString("InstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);
2681
			if ( !node->Data()->sAfter.Empty() )
2682
				list->PushBack(CyString("InstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);
2683
		}
2684
		list->PushBack("");
2685
	}
2686
 
2687
	if ( m_lUninstallText.size() )
2688
	{
2689
		list->PushBack("# Uninstall Texts, display text before and/or after uninstalling to inform the use of special conditions");
2690
		for ( CListNode<SInstallText> *node = m_lUninstallText.Front(); node; node = node->next() )
2691
		{
2692
			if ( !node->Data()->sBefore.Empty() )
2693
				list->PushBack(CyString("UninstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);
2694
			if ( !node->Data()->sAfter.Empty() )
2695
				list->PushBack(CyString("UninstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);
2696
		}
2697
		list->PushBack("");
2698
	}
2699
 
2700
	list->PushBack("# Plugin Type, the type the plugin is, mainly used to show users the type, types include: Normal, Stable, Experimental, Cheat, Mod");
2701
	switch ( this->GetPluginType() )
2702
	{
2703
		case PLUGIN_NORMAL:
2704
			list->PushBack("PluginType: Normal");
2705
			break;
2706
		case PLUGIN_STABLE:
2707
			list->PushBack("PluginType: Stable");
2708
			break;
2709
		case PLUGIN_EXPERIMENTAL:
2710
			list->PushBack("PluginType: Experimental");
2711
			break;
2712
		case PLUGIN_CHEAT:
2713
			list->PushBack("PluginType: Cheat");
2714
			break;
2715
		case PLUGIN_MOD:
2716
			list->PushBack("PluginType: Mod");
2717
			break;
2718
	}
2719
	list->PushBack("");
2720
 
2721
	return true;
2722
}
2723
 
2724
bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, CyStringList *list)
2725
{
2726
	// now do files and wildcards
2727
	CyStringList files;
2728
	for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
2729
	{
2730
		CyString name = "$GAMEDIR/";
2731
 
2732
		bool done = false;
2733
		if ( wildcard )
2734
		{
2735
			CyString base = f->Data()->GetBaseName();
2736
			if ( f->Data()->GetFileType() == FILETYPE_SCRIPT )
2737
			{
2738
				if ( base.GetToken(".", 1, 1).Compare("plugin") || base.GetToken(".", 1, 1).Compare("lib") )
2739
				{
2740
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
2741
					done = true;
2742
				}
2743
				else if ( base.GetToken(".", 1, 1).Compare("al") && !base.GetToken(".", 2, 2).Compare("plugin") )
2744
				{
2745
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
2746
					done = true;
2747
				}
2748
			}
2749
			else if ( f->Data()->GetFileType() == FILETYPE_TEXT )
2750
			{
2751
				if ( base.IsIn("-L") )
2752
				{
2753
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken("-L", 1, 1) + "-L*";
2754
					done = true;
2755
				}
2756
				else
2757
				{
2758
					name += f->Data()->GetDirectory(this) + "/*" + base.Right(4) + ".*";
2759
					done = true;
2760
				}
2761
			}
2762
		}
2763
 
2764
		if ( !done )
2765
			name += f->Data()->GetNameDirectory(this);
2766
 
2767
		if ( !f->Data()->GetDir().Empty() )
2768
		{
2769
			name += "|";
2770
			name += f->Data()->GetDir();
2771
		}
2772
		files.PushBack(CyString("GAME ") + CBaseFile::ConvertGameToString(f->Data()->GetGame()) + " " + name, f->Data()->GetFileTypeString(), true);
2773
	}
2774
 
2775
 
2776
	if ( !files.Empty() )
2777
	{
2778
		list->PushBack("# Files List, all the files to add, can include wild cards");
2779
		for ( SStringList *node = files.Head(); node; node = node->next )
2780
			list->PushBack(node->data + ": " + node->str);
2781
		list->PushBack("");
2782
	}
2783
 
2784
	return true;
2785
}
2786
 
2787
CyString CBaseFile::GetAutosaveName()
2788
{
2789
	CyString cdate = m_sCreationDate;
2790
	cdate = cdate.FindReplace("/", ".");
2791
	CyString name = m_sName + "-V" + m_sVersion + "-" + cdate;
2792
 
2793
	return name;
2794
}
2795
 
2796
bool CBaseFile::CheckGameCompatability(int game)
2797
{
2798
	if ( m_lGames.empty() )
2799
		return true; // no game compatability added, assume its ok for all
2800
 
2801
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2802
		if ( node->Data()->iGame == 0 || node->Data()->iGame == game )
2803
			return true;
2804
	}
2805
	return false;
2806
}
2807
 
2808
bool CBaseFile::CheckGameVersionCompatability(int game, CyString sVersion, int iVersion)
2809
{
2810
	if ( m_lGames.empty() )
2811
		return true; // no game compatability added, assume its ok for all
2812
 
2813
	bool foundAll = false;
2814
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2815
		if ( node->Data()->iGame == 0 )
2816
			foundAll = true;
2817
		else if ( node->Data()->iGame == game ) { // now check the version
2818
			if ( node->Data()->sVersion.Empty() ) {
2819
				if ( node->Data()->sVersion.CompareVersion(sVersion) == COMPARE_OLDER )
2820
					return false;
2821
				return true;
2822
			}
2823
			else {
2824
				if ( node->Data()->iVersion > iVersion )
2825
					return false;
2826
				return true;
2827
			}
2828
		}
2829
	}
2830
	return foundAll;
2831
}
2832
 
2833
bool CBaseFile::RemoveGameCompatability(int game)
2834
{
2835
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2836
		if ( node->Data()->iGame == game ) {
2837
			m_lGames.remove(node);
2838
			m_bChanged = true;
2839
			return true;
2840
		}
2841
	}
2842
 
2843
	return false;
2844
}
2845
 
2846
SGameCompat *CBaseFile::GetGameCompatability(int game)
2847
{
2848
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2849
		if ( node->Data()->iGame == game ) {
2850
			return node->Data();
2851
		}
2852
	}
2853
 
2854
	return NULL;
2855
}
2856
 
2857
void CBaseFile::AddGameCompatability(int game, CyString version)
2858
{
2859
	// first check if we already have it on the list
2860
	SGameCompat *Found = this->GetGameCompatability(game);
2861
	if ( !Found ) {
2862
		Found = new SGameCompat;
2863
		m_lGames.push_back(Found);
2864
	}
2865
 
2866
	Found->iGame = game;
2867
	Found->iVersion = -1;
2868
	Found->sVersion = NullString;
2869
 
2870
	if ( version.IsIn(".") || !version.IsNumber() )
2871
		Found->sVersion = version;
2872
	else
2873
		Found->iVersion = version.ToInt();
2874
	m_bChanged = true;
2875
}
2876
 
14 cycrow 2877
bool CBaseFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest)
6 cycrow 2878
{
14 cycrow 2879
	if ( sFirst.Compare("Name") )
2880
		m_sName = sRest;
2881
	else if ( sFirst.Compare("Author") )
2882
		m_sAuthor = sRest;
2883
	else if ( sFirst.Compare("ScriptName") )
2884
		AddLanguageName(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
2885
	else if ( sFirst.Compare("UninstallBefore") )
2886
		this->AddUninstallBeforeText(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
2887
	else if ( sFirst.Compare("UninstallAfter") )
2888
		this->AddUninstallAfterText(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
2889
	else if ( sFirst.Compare("InstallBefore") )
2890
		this->AddInstallBeforeText(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
2891
	else if ( sFirst.Compare("InstallAfter") )
2892
		this->AddInstallAfterText(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
2893
	else if ( sFirst.Compare("Date") )
2894
		m_sCreationDate = sRest;
2895
	else if ( sFirst.Compare("Version") )
2896
		m_sVersion = sRest;
6 cycrow 2897
	// old version
14 cycrow 2898
	else if ( sFirst.Compare("GameVersion") )
2899
		this->AddGameCompatability(-1, sRest);
2900
	else if ( sFirst.Compare("PluginType") )
6 cycrow 2901
	{
14 cycrow 2902
		if ( sRest.isNumber() )
2903
			this->SetPluginType(sRest);
2904
		else if ( sRest.Compare("Normal") )
6 cycrow 2905
			this->SetPluginType(PLUGIN_NORMAL);
14 cycrow 2906
		else if ( sRest.Compare("Stable") )
6 cycrow 2907
			this->SetPluginType(PLUGIN_STABLE);
14 cycrow 2908
		else if ( sRest.Compare("Experimental") )
6 cycrow 2909
			this->SetPluginType(PLUGIN_EXPERIMENTAL);
14 cycrow 2910
		else if ( sRest.Compare("Cheat") )
6 cycrow 2911
			this->SetPluginType(PLUGIN_CHEAT);
14 cycrow 2912
		else if ( sRest.Compare("Mod") )
6 cycrow 2913
			this->SetPluginType(PLUGIN_MOD);
2914
	}
2915
	// new version
14 cycrow 2916
	else if ( sFirst.Compare("GenerateUpdateFile") )
6 cycrow 2917
		m_bAutoGenerateUpdateFile = true;
14 cycrow 2918
	else if ( sFirst.Compare("Game") )
6 cycrow 2919
	{
14 cycrow 2920
		Utils::String sGame = sRest.token(" ", 1);
2921
		this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), sRest.token(" ", 2));
6 cycrow 2922
	}
14 cycrow 2923
	else if ( sFirst.Compare("Description") )
2924
		m_sDescription = sRest;
2925
	else if ( sFirst.Compare("AutoSave") || sFirst.Compare("AutoExport") || sFirst.Compare("AutoRarExport") || sFirst.Compare("AutoZipExport") )
6 cycrow 2926
	{
14 cycrow 2927
		CyString filename = sRest;
6 cycrow 2928
		CyString name = m_sName;
2929
		CyString author = m_sAuthor;
2930
		CyString cdate = m_sCreationDate;
2931
		cdate = cdate.FindReplace("/", ".").Remove(" ");
2932
		if ( filename.IsIn("$AUTOSAVE") )
2933
		{
2934
			if ( m_iType == TYPE_XSP )
2935
				filename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");
2936
			else
2937
				filename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");
2938
		}
2939
		if ( filename.IsIn("$NAME") )
2940
			filename.FindReplace("$NAME", name.Remove(" "));
2941
		if ( filename.IsIn("$AUTHOR") )
2942
			filename.FindReplace("$AUTHOR", author.Remove(" "));
2943
		if ( filename.IsIn("$DATE") )
2944
			filename.FindReplace("$DATE", cdate);
2945
		if ( filename.IsIn("$CDATE") )
2946
			filename.FindReplace("$CDATE", cdate);
2947
		if ( filename.IsIn("$VERSION") )
2948
			filename.FindReplace("$VERSION", m_sVersion);
2949
 
14 cycrow 2950
		if ( sFirst.Compare("AutoZipExport") || sFirst.Compare("AutoExport") )
6 cycrow 2951
			m_sExportFilename = CFileIO(filename).ChangeFileExtension("zip");
14 cycrow 2952
		else if ( sFirst.Compare("AutoRarExport") )
6 cycrow 2953
			m_sExportFilename = CFileIO(filename).ChangeFileExtension("rar");
2954
		else
2955
			m_sFilename = filename;
2956
	}
14 cycrow 2957
	else if ( sFirst.Compare("WebSite") )
2958
		m_sWebSite = sRest;
2959
	else if ( sFirst.Compare("ForumLink") || sFirst.Compare("Forum") )
2960
		m_sForumLink = sRest;
2961
	else if ( sFirst.Compare("Email") )
2962
		m_sEmail = sRest;
2963
	else if ( sFirst.Compare("WebAddress") )
2964
		m_sWebAddress = sRest;
2965
	else if ( sFirst.Compare("WebMirror") )
2966
		this->AddWebMirror(sRest);
2967
	else if ( sFirst.Compare("WebMirror1") )
2968
		this->AddWebMirror(sRest);
2969
	else if ( sFirst.Compare("WebMirror2") )
2970
		this->AddWebMirror(sRest);
2971
	else if ( sFirst.Compare("Ftp") )
2972
		m_sFtpAddr = sRest;
2973
	else if ( sFirst.Compare("Ratings") )
6 cycrow 2974
	{
14 cycrow 2975
		m_iEaseOfUse = sRest.token(" ", 1);
2976
		m_iGameChanging = sRest.token(" ", 2);
2977
		m_iRecommended = sRest.token(" ", 3);
6 cycrow 2978
	}
14 cycrow 2979
	else if ( sFirst.Compare("EaseOfUse") )
2980
		m_iEaseOfUse = sRest;
2981
	else if ( sFirst.Compare("GameChanging") )
2982
		m_iGameChanging = sRest;
2983
	else if ( sFirst.Compare("Recommended") )
2984
		m_iRecommended = sRest;
2985
	else if ( sFirst.Compare("Depend") )
6 cycrow 2986
	{
14 cycrow 2987
		CyString version = sRest.token("|", 2);
2988
		CyString name = sRest.token("|", 1);
2989
		CyString author = sRest.tokens("|", 3);
6 cycrow 2990
 
2991
		this->AddNeededLibrary(name, author, version);
2992
	}
14 cycrow 2993
	else if ( sFirst.Compare("DependPackage") )
6 cycrow 2994
	{
2995
		CPackages p;
14 cycrow 2996
		CBaseFile *spk =  p.OpenPackage(sRest, 0, 0, SPKREAD_VALUES);
6 cycrow 2997
		if ( spk )
2998
		{
2999
			this->AddNeededLibrary(spk->GetName(), spk->GetAuthor(), spk->GetVersion());
3000
			delete spk;
3001
		}
3002
	}
14 cycrow 3003
	else if ( sFirst.Compare("Icon") )
6 cycrow 3004
	{
14 cycrow 3005
		C_File *icon = new C_File(sRest.c_str());
6 cycrow 3006
		if ( icon->ReadFromFile() )
14 cycrow 3007
			this->SetIcon(icon, CFileIO(sRest).GetFileExtension());
6 cycrow 3008
	}
3009
	else
3010
	{
14 cycrow 3011
		Utils::String checkType = sFirst;
6 cycrow 3012
		bool shared = false;
14 cycrow 3013
		if ( checkType.left(6).Compare("Shared") )
6 cycrow 3014
		{
14 cycrow 3015
			checkType = sFirst.right(-6);
6 cycrow 3016
			shared = true;
3017
		}
3018
 
3019
		// now check type name
3020
		int filetype = GetFileTypeFromString(checkType);
3021
		if ( filetype != -1 )
14 cycrow 3022
			this->AddFileScript(filetype, shared, sRest);
6 cycrow 3023
		else if ( !checkType.Compare("changelog") )
3024
			return false;
3025
	}
3026
 
3027
	return true;
3028
}
3029
 
3030
void CBaseFile::AddFileScript(int filetype, bool shared, CyString rest)
3031
{
3032
	CyString dir;
3033
	if ( rest.IsIn("|") )
3034
	{
3035
		dir = rest.GetToken("|", 2);
3036
		rest = rest.GetToken("|", 1, 1);
3037
	}
3038
 
3039
	int game = 0;
3040
	if ( rest.GetToken(" ", 1, 1).Left(4).Compare("GAME") ) {
13 cycrow 3041
		game = CBaseFile::GetGameFromString(rest.GetToken(" ", 2, 2).ToString());
6 cycrow 3042
		rest = rest.GetToken(" ", 3);
3043
	}
3044
 
3045
	rest = rest.FindReplace("\\", "/");
3046
 
3047
	// wild cards
3048
	if ( rest.IsAnyIn("*?") )
3049
	{
3050
		CDirIO Dir(CFileIO(rest).GetDir());
3051
		CyStringList *dirList = Dir.DirList();
3052
		if ( dirList )
3053
		{
3054
			for ( SStringList *strNode = dirList->Head(); strNode; strNode = strNode->next )
3055
			{
3056
				CyString file = Dir.File(strNode->str);
3057
				if ( file.WildMatch(rest) )
3058
				{
3059
					C_File *newfile = this->AppendFile(file, filetype, game, dir);
3060
					if ( newfile )
3061
						newfile->SetShared(shared);
3062
				}
3063
			}
3064
			delete dirList;
3065
		}
3066
	}
3067
	else
3068
	{
3069
		C_File *file = this->AppendFile(rest, filetype, game, dir);
3070
		if ( file )
3071
			file->SetShared(shared);
3072
	}
3073
}
3074
 
3075
 
3076
CyString CBaseFile::GetFullFileSizeString() { return SPK::GetSizeString ( this->GetFullFileSize() ); }
3077
 
3078
unsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress)
3079
{
3080
	if ( this->WriteFile("temp.dat", progress) )
3081
	{
3082
		FILE *id = fopen("temp.dat", "rb");
3083
		if ( id )
3084
		{
3085
			fseek(id, 0, SEEK_END);
3086
			*size = ftell(id);
3087
			fseek(id, 0, SEEK_SET);
3088
			unsigned char *data = new unsigned char[*size];
3089
			fread(data, sizeof(unsigned char), *size, id);
3090
			fclose(id);
3091
 
3092
			remove("temp.dat");
3093
			return data;
3094
		}
3095
	}
3096
 
3097
	remove("temp.dat");
3098
	return NULL;
3099
}
3100
 
3101
 
3102
void CBaseFile::ConvertNormalMod(C_File *f, CyString to)
3103
{
3104
	C_File *match = this->FindMatchingMod(f);
3105
	if ( match )
3106
	{
3107
		// file link
3108
		if ( !match->GetData() )
3109
			match->ReadFromFile();
3110
		match->ChangeBaseName(to);
3111
	}
3112
 
3113
	// file link
3114
	if ( !f->GetData() )
3115
		f->ReadFromFile();
3116
 
3117
	f->ChangeBaseName(to);
3118
}
3119
 
3120
void CBaseFile::ConvertAutoText(C_File *f)
3121
{
3122
	CyString to;
3123
	if ( f->GetBaseName().IsIn("-L") )
3124
		to = CyString("0000-L") + f->GetBaseName().GetToken("-L", 2, 2);
3125
	else if ( f->GetBaseName().IsIn("-l") )
3126
		to = CyString("0000-L") + f->GetBaseName().GetToken("-l", 2, 2);
3127
	else
3128
		to = f->GetBaseName().Left(-4) + "0000";
3129
 
3130
	// file link
3131
	if ( !f->GetData() )
3132
		f->ReadFromFile();
3133
 
3134
	f->ChangeBaseName(to);
3135
 
3136
}
3137
 
3138
void CBaseFile::ConvertFakePatch(C_File *f)
3139
{
3140
	// find next available fake patch
3141
	int num = 0;
3142
 
3143
	bool found = true;
3144
	while ( found )
3145
	{
3146
		++num;
3147
		found = false;
3148
		CyString find = CyString::Number(num).PadNumber(2);
3149
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
3150
		{
3151
			if ( node->Data()->GetFileType() != FILETYPE_MOD )
3152
				continue;
3153
			if ( !node->Data()->IsFakePatch() )
3154
				continue;
3155
			if ( node->Data()->GetBaseName().Compare(find) )
3156
			{
3157
				found = true;
3158
				break;
3159
			}
3160
		}
3161
	}
3162
 
3163
	CyString to = CyString::Number(num).PadNumber(2);
3164
	C_File *match = this->FindMatchingMod(f);
3165
 
3166
	// file link
3167
	if ( !f->GetData() )
3168
		f->ReadFromFile();
3169
 
3170
	f->ChangeBaseName(to);
3171
	if ( match )
3172
	{
3173
		// file link
3174
		if ( !match->GetData() )
3175
			match->ReadFromFile();
3176
		match->ChangeBaseName(to);
3177
	}
3178
}
3179
 
3180
C_File *CBaseFile::FindMatchingMod(C_File *f)
3181
{
3182
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
3183
	{
3184
		if ( node->Data()->GetFileType() != FILETYPE_MOD )
3185
			continue;
3186
 
3187
		if ( f->GetFileExt().Compare(node->Data()->GetFileExt()) )
3188
			continue;
3189
 
3190
		if ( f->GetBaseName().Compare(node->Data()->GetBaseName()) )
3191
			return node->Data();
3192
	}
3193
 
3194
	return NULL;
3195
}
3196
 
3197
void CBaseFile::RenameFile(C_File *f, CyString baseName)
3198
{
3199
	if ( f->GetFileType() == FILETYPE_MOD )
3200
	{
3201
		C_File *match = this->FindMatchingMod(f);
3202
		if ( match )
3203
			match->ChangeBaseName(baseName);
3204
	}
3205
 
3206
	// need to edit the file
3207
	if ( f->GetFileType() == FILETYPE_SCRIPT || f->GetFileType() == FILETYPE_UNINSTALL )
3208
		f->RenameScript(baseName);
3209
 
3210
	f->ChangeBaseName(baseName);
3211
}
3212
 
3213
CyString CBaseFile::CreateUpdateFile(CyString dir)
3214
{
3215
	CyString file = this->GetNameValidFile() + "_" + m_sAuthor + ".dat";
3216
	file.RemoveChar(' ');
3217
 
3218
	CyStringList write;
3219
	write.PushBack(CyString("Package: ") + m_sName);
3220
	write.PushBack(CyString("Author: ") + m_sAuthor);
3221
	write.PushBack(CyString("Version: ") + m_sVersion);
3222
	write.PushBack(CyString("File: ") + CFileIO(m_sFilename).GetFilename());
3223
 
3224
	CFileIO File(dir + "/" + file);
3225
	if ( File.WriteFile(&write) )
3226
		return File.GetFullFilename();
3227
	return NullString;
3228
}
3229
 
3230
CyString CBaseFile::ErrorString(int error, CyString errorStr)
3231
{
3232
	if ( error == SPKERR_NONE ) return NullString;
3233
 
3234
	CyString err;
3235
 
3236
	switch(error)
3237
	{
3238
		case SPKERR_MALLOC:
3239
			err = "Memory Failed";
3240
			break;
3241
		case SPKERR_FILEOPEN:
3242
			err = "Failed to open file";
3243
			break;
3244
		case SPKERR_FILEREAD:
3245
			err = "Failed to read file";
3246
			break;
3247
		case SPKERR_UNCOMPRESS:
3248
			err = "Failed to Uncompress";
3249
			break;
3250
		case SPKERR_WRITEFILE:
3251
			err = "Failed to write file";
3252
			break;
3253
		case SPKERR_CREATEDIRECTORY:
3254
			err = "Failed to create directory";
3255
			break;
3256
		case SPKERR_FILEMISMATCH:
3257
			err = "File count mismatch";
3258
			break;
3259
	}
3260
 
3261
	if ( !err.Empty() )
3262
	{
3263
		if ( !errorStr.Empty() )
3264
		{
3265
			err += " (";
3266
			err += errorStr + ")";
3267
		}
3268
		return err;
3269
	}
3270
 
3271
	return CyString((long)error);
3272
}
3273
 
3274
bool CBaseFile::SaveToArchive(CyString filename, int game, CProgressInfo *progress)
3275
{
3276
	TCHAR buf[5000];
3277
	wsprintf(buf, L"%hs", filename.c_str());
3278
 
3279
	HZIP hz = CreateZip(buf, 0);
3280
	if ( !hz ) return false;
3281
 
3282
	// read files and compress
3283
	ReadAllFilesToMemory();
3284
	if ( !UncompressAllFiles(progress) )
3285
	{
3286
		CloseZip(hz);
3287
		return false;
3288
	}
3289
 
3290
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
3291
	{
3292
		if ( game != -1 ) {
3293
			if ( game && node->Data()->GetGame() && node->Data()->GetGame() != game )
3294
				continue;
3295
			if ( !game && node->Data()->GetGame() )
3296
				continue;
3297
		}
3298
		CyString fname = node->Data()->GetNameDirectory(this);
3299
		// create the directory
3300
		wsprintf(buf, L"%hs", fname.c_str());
3301
		ZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());
3302
	}
3303
 
3304
	// add the data file
3305
	CyStringList list;
3306
	if ( this->GeneratePackagerScript(false, &list, true) )
3307
	{
3308
		if ( CFileIO("test.tmp").WriteFile(&list) )
3309
		{
3310
			ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");
3311
			CFileIO("test.tmp").Remove();
3312
		}
3313
	}
3314
 
3315
	CloseZip(hz);
3316
 
3317
	return true;
3318
}
3319
 
13 cycrow 3320
int CBaseFile::GetGameFromString(const Utils::String &sGame)
6 cycrow 3321
{
3322
	int iGame = GAME_ALL;
3323
	if ( sGame.Compare("ALL") )
3324
		iGame = GAME_ALL;
3325
	else if ( sGame.Compare("X3") )
3326
		iGame = GAME_X3;
3327
	else if ( sGame.Compare("X2") )
3328
		iGame = GAME_X2;
3329
	else if ( sGame.Compare("X3TC") )
3330
		iGame = GAME_X3TC;
3331
	else if ( sGame.Compare("X3AP") )
3332
		iGame = GAME_X3AP;
3333
	else if ( sGame.Compare("XREBIRTH") )
3334
		iGame = GAME_XREBIRTH;
13 cycrow 3335
	else if ( sGame.isNumber() )
3336
		iGame = sGame;
6 cycrow 3337
 
3338
	return iGame;
3339
}
3340
 
13 cycrow 3341
Utils::String CBaseFile::ConvertGameToString(int iGame)
6 cycrow 3342
{
13 cycrow 3343
	Utils::String game = "ALL";
6 cycrow 3344
 
3345
	switch(iGame) {
3346
		case GAME_ALL:
3347
			game = "ALL";
3348
			break;
3349
		case GAME_X2:
3350
			game = "X2";
3351
			break;
3352
		case GAME_X3:
3353
			game = "X3";
3354
			break;
3355
		case GAME_X3TC:
3356
			game = "X3TC";
3357
			break;
3358
		case GAME_X3AP:
3359
			game = "X3AP";
3360
			break;
3361
		case GAME_XREBIRTH:
3362
			game = "XREBIRTH";
3363
			break;
3364
		default:
3365
			game = (long)iGame;
3366
	}
3367
 
3368
	return game;
3369
}
3370
 
3371
bool CBaseFile::IsGameInPackage(int game)
3372
{
3373
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3374
		if ( node->Data()->GetGame() == game )
3375
			return true;
3376
	}
3377
 
3378
	return false;
3379
}
3380
 
3381
bool CBaseFile::IsAnyGameInPackage()
3382
{
3383
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3384
		if ( node->Data()->GetGame() )
3385
			return true;
3386
	}
3387
 
3388
	return false;
3389
}
3390
 
3391
int CBaseFile::FindFirstGameInPackage()
3392
{
3393
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3394
		if ( node->Data()->GetGame() )
3395
			return node->Data()->GetGame();
3396
	}
3397
 
3398
	return 0;
3399
}
3400
bool CBaseFile::IsMultipleGamesInPackage()
3401
{
3402
	int game = 0;
3403
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3404
		if ( node->Data()->GetGame() ) {
3405
			if ( game != node->Data()->GetGame() )
3406
				return true;
3407
			game = node->Data()->GetGame();
3408
		}
3409
	}
3410
 
3411
	return false;
3412
}