Subversion Repositories spk

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 cycrow 1
// SpkFile.cpp: implementation of the CSpkFile class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
 
5
#include "SpkFile.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
CSpkFile::CSpkFile() : CBaseFile ()
21
{
22
	SetDefaults ();
23
 
24
	m_iType = TYPE_SPK;
25
}
26
 
27
CSpkFile::~CSpkFile()
28
{
29
	Delete ();
30
}
31
 
32
CArchiveFile::~CArchiveFile()
33
{
34
	Delete ();
35
}
36
 
37
CArchiveFile::CArchiveFile() : CBaseFile ()
38
{
39
	SetDefaults ();
40
 
41
	m_iType = TYPE_ARCHIVE;
42
}
43
 
44
/*
45
	Func:   SetDefaults
46
	Desc:   Sets the  default values when class is created
47
*/
48
void CSpkFile::SetDefaults ()
49
{
50
	m_pLastWare = NULL;
51
	m_iPackageType = PACKAGETYPE_NORMAL;
52
	m_bForceProfile = false;
53
	m_iScriptType = SCRIPTTYPE_CUSTOM;
54
 
55
	CBaseFile::SetDefaults ();
56
}
57
void CBaseFile::SetDefaults ()
58
{
59
	m_pIconFile = NULL;
60
 
61
	m_bAutoGenerateUpdateFile = false;
62
	m_SHeader.iValueCompression = SPKCOMPRESS_ZLIB;
63
	m_SHeader2.iFileCompression = SPKCOMPRESS_ZLIB;
64
	m_SHeader2.iDataCompression = SPKCOMPRESS_LZMA;
65
	m_pParent = NULL;
66
	m_bChanged = false;
67
	m_bUpdate = false;
68
	m_iPluginType = PLUGIN_NORMAL;
69
 
70
	ClearError();
71
 
72
	m_iLoadError = 0;
73
 
74
	m_bFullyLoaded = false;
75
	m_bSigned = false;
76
	m_bEnable = m_bGlobal = m_bProfile = m_bModifiedEnabled = true;
77
	m_bOverrideFiles = false;
78
 
79
	m_iRecommended = m_iEaseOfUse = m_iGameChanging = -1;
80
}
81
 
82
CBaseFile::CBaseFile()
83
{
84
	SetDefaults ();
85
 
86
	m_iType = TYPE_BASE;
87
}
88
CBaseFile::~CBaseFile()
89
{
90
	Delete();
91
}
92
 
93
void CSpkFile::Delete ()
94
{
95
	m_lWares.clear(true);
96
	m_lSettings.clear(true);
97
 
98
	CBaseFile::Delete ();
99
}
100
void CBaseFile::Delete ()
101
{
102
	m_lFiles.clear(true);
103
 
104
	if ( m_pIconFile )
105
	{
106
		delete m_pIconFile;
107
		m_pIconFile = NULL;
108
	}
109
 
110
	m_lInstallText.clear(true);
111
	m_lUninstallText.clear(true);
112
	m_lNames.clear(true);
113
}
114
 
115
CyString CBaseFile::GetLanguageName ( int lang )
116
{
117
	for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
118
	{
119
		SNames *n = node->Data();
120
		if ( n->iLanguage == lang )
121
			return n->sName;
122
	}
123
	return m_sName;
124
}
125
 
126
 
127
/*
128
##########################################################################################
129
##################                Base Class Functions                  ##################
130
##########################################################################################
131
*/
132
 
133
CLinkList<C_File> *CBaseFile::GetFileList(int type)
134
{
135
	CLinkList<C_File> *list = new CLinkList<C_File>;
136
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
137
	{
138
		C_File *f = node->Data();
139
		if ( f->GetFileType() == type )
140
			list->push_back(f);
141
	}
142
 
143
	return list;
144
}
145
 
146
C_File *CBaseFile::GetNextFile(C_File *prev)
147
{
148
	int type = -1;
149
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
150
	{
151
		C_File *f = node->Data();
152
		if ( type == -1 )
153
		{
154
			if ( f == prev )
155
				type = f->GetFileType();
156
		}
157
		else
158
		{
159
			if ( f->GetFileType() == type )
160
				return f;
161
		}
162
	}
163
 
164
	return NULL;
165
}
166
 
167
C_File *CBaseFile::GetPrevFile(C_File *next)
168
{
169
	if ( !next )
170
		return NULL;
171
 
172
	int type = -1;
173
	for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() )
174
	{
175
		C_File *f = node->Data();
176
		if ( type == -1 )
177
		{
178
			if ( f == next )
179
				type = f->GetFileType();
180
		}
181
		else
182
		{
183
			if ( f->GetFileType() == type )
184
				return f;
185
		}
186
	}
187
 
188
	return NULL;
189
}
190
 
191
C_File *CBaseFile::GetFirstFile(int type)
192
{
193
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
194
	{
195
		C_File *f = node->Data();
196
		if ( f->GetFileType() == type )
197
			return f;
198
	}
199
 
200
	return NULL;
201
}
202
 
203
int CBaseFile::CheckFile ( CyString filename, float *version )
204
{
205
	FILE *id = fopen ( filename.c_str(), "rb" );
206
	if ( !id )
207
		return false;
208
 
209
	CyString line = GetEndOfLine ( id, NULL, false );
210
	CyString type = line.GetToken ( 1, ';' );
211
	fclose ( id );
212
 
213
	// check for old version
214
	if ( line.Left(3) == "HiP" )
215
		return SPKFILE_OLD;
216
 
217
	// check for format
218
	if ( version )
219
		*version = line.GetToken ( 2, ';' ).ToFloat();
220
 
221
	if ( type == "BaseCycrow" )
222
		return SPKFILE_BASE;
223
	if ( type == "SPKCycrow" )
224
		return SPKFILE_SINGLE;
225
	if ( type == "XSPCycrow" )
226
		return SPKFILE_SINGLESHIP;
227
	if ( type == "MSPKCycrow" )
228
		return SPKFILE_MULTI;
229
	return SPKFILE_INVALID;
230
}
231
 
232
void CBaseFile::ClearFileData()
233
{
234
	for ( C_File *f = m_lFiles.First(); f; f = m_lFiles.Next() )
235
	{
236
		f->DeleteData();
237
	}
238
}
239
 
240
CyString CBaseFile::GetNameValidFile ()
241
{
242
	CyString name = m_sName;
243
	name.RemoveChar ( ':' );
244
	name.RemoveChar ( '/' );
245
	name.RemoveChar ( '\\' );
246
	name.RemoveChar ( '*' );
247
	name.RemoveChar ( '?' );
248
	name.RemoveChar ( '"' );
249
	name.RemoveChar ( '<' );
250
	name.RemoveChar ( '>' );
251
	name.RemoveChar ( '|' );
252
	return name;
253
}
254
 
255
void CBaseFile::SwitchFilePointer(C_File *oldFile, C_File *newFile)
256
{
257
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
258
	{
259
		C_File *f = node->Data();
260
		if ( f == oldFile )
261
		{
262
			node->ChangeData(newFile);
263
			break;
264
		}
265
	}
266
}
267
 
268
bool CBaseFile::AnyFileType ( int type )
269
{
270
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
271
	{
272
		C_File *f = node->Data();
273
		if ( f->GetFileType() == type )
274
			return true;
275
	}
276
 
277
	return false;
278
}
279
 
280
void CBaseFile::AddFile ( C_File *file )
281
{
282
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
283
	{
284
		C_File *f = node->Data();
285
		if ( f->GetFileType() != file->GetFileType() )
286
			continue;
287
		if ( f->GetName() != file->GetName () )
288
			continue;
289
		if ( f->GetDir() != file->GetDir() )
290
			continue;
291
		if ( f->GetGame() != file->GetGame() )
292
			continue;
293
 
294
		m_lFiles.remove(node, true);
295
		break;
296
	}
297
 
298
	file->UpdateSigned();
299
	m_bChanged = true;
300
	m_lFiles.push_back ( file );
301
}
302
 
303
C_File *CBaseFile::AddFile ( CyString file, CyString dir, int type, int game )
304
{
305
	C_File *newfile = new C_File ( file );
306
	newfile->SetDir ( dir );
307
	newfile->SetFileType ( type );
308
	newfile->SetGame(game);
309
 
310
	// first check if the file already exists
311
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
312
	{
313
		C_File *f = node->Data();
314
		if ( f->GetFileType() != newfile->GetFileType() )
315
			continue;
316
		if ( f->GetName() != newfile->GetName () )
317
			continue;
318
		if ( f->GetDir() != newfile->GetDir() )
319
			continue;
320
		if ( f->GetGame() != newfile->GetGame() )
321
			continue;
322
 
323
		// must already exist, delete this one
324
		m_lFiles.remove(node, true);
325
		break;
326
	}
327
 
328
	m_bChanged = true;
329
	newfile->UpdateSigned();
330
	m_lFiles.push_back ( newfile );
331
 
332
	return newfile;
333
}
334
 
335
bool CBaseFile::AddFileNow ( CyString file, CyString dir, int type, CProgressInfo *progress )
336
{
337
	C_File *f = AddFile ( file, dir, type );
338
	if ( !f->ReadFromFile () )
339
		return false;
340
 
341
	// compress the file
342
	return f->CompressData ( m_SHeader2.iDataCompression, progress );
343
}
344
 
345
C_File *CBaseFile::AppendFile ( CyString file, int type, int game, CyString dir, CProgressInfo *progress )
346
{
347
	C_File *newfile = AddFile ( file, dir, type, game );
348
	if ( !newfile )
349
		return NULL;
350
 
351
 
352
	// read the file into memory
353
	if ( newfile->ReadFromFile () )
354
	{
355
		// now compress the file
356
		if ( newfile->CompressData ( m_SHeader2.iDataCompression, progress ) )
357
			return newfile;
358
	}
359
	else if ( newfile->GetLastError() == SPKERR_MALLOC )
360
	{
361
		if ( newfile->CompressFile ( progress ) )
362
			return newfile;
363
	}
364
 
365
	m_lFiles.pop_back ();
366
	delete newfile;
367
 
368
	return NULL;
369
}
370
 
371
C_File *CBaseFile::FindFileAt ( int filetype, int pos )
372
{
373
	int count = 0;
374
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
375
	{
376
		C_File *file = node->Data();
377
		if ( file->GetFileType() != filetype )
378
			continue;
379
 
380
		if ( count == pos )
381
			return file;
382
 
383
		++count;
384
	}
385
 
386
	return NULL;
387
}
388
 
389
C_File *CBaseFile::FindFile ( CyString filename, int type, CyString dir, int game )
390
{
391
	CyString lfile = filename.ToLower();
392
	lfile = lfile.FindReplace ( "\\", "/" );
393
 
394
	lfile = lfile.GetToken ( lfile.NumToken('/'), '/' );
395
 
396
	CListNode<C_File> *node = m_lFiles.Front();
397
	while ( node )
398
	{
399
		C_File *f = node->Data();
400
		node = node->next();
401
 
402
		if ( type != f->GetFileType() )
403
			continue;
404
		if ( dir != f->GetDir() )
405
			continue;
406
		if ( game != f->GetGame() )
407
			continue;
408
		if ( f->GetName().ToLower() == lfile )
409
			return f;
410
	}
411
	return NULL;
412
}
413
 
414
bool CBaseFile::RemoveFile ( CyString file, int type, CyString dir, int game )
415
{
416
	C_File *f = FindFile (file, type, dir, game);
417
	if ( !f )
418
		return false;
419
	return RemoveFile ( f );
420
}
421
 
422
bool CBaseFile::RemoveFile ( C_File *file )
423
{
424
	int count = 0;
425
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
426
	{
427
		C_File *f = node->Data();
428
		if ( f == file )
429
			return RemoveFile ( count );
430
		++count;
431
	}
432
	return false;
433
}
434
 
435
bool CBaseFile::RemoveFile ( int pos )
436
{
437
	if ( (pos < 0) || (pos >= m_lFiles.size()) )
438
		return false;
439
 
440
	C_File *file = m_lFiles.Get ( pos );
441
	m_lFiles.erase ( pos + 1 );
442
 
443
	if ( file )
444
		delete file;
445
 
446
	m_bChanged = true;
447
 
448
	return true;
449
}
450
 
451
 
452
void CBaseFile::RemoveAllFiles ( int type, int game )
453
{
454
	if ( m_lFiles.empty() )
455
		return;
456
 
457
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
458
	{
459
		if ( game > -1 ) {
460
			if ( node->Data()->GetGame() != game )
461
				continue;
462
		}
463
		if ( type == -1 || node->Data()->GetFileType() == type )
464
			node->DeleteData();
465
	}
466
 
467
	m_lFiles.RemoveEmpty();
468
 
469
	m_bChanged = true;
470
}
471
 
472
void CBaseFile::RecompressAllFiles ( int type, CProgressInfo *progress )
473
{
474
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
475
	{
476
		C_File *file = node->Data();
477
		if ( progress )
478
			progress->UpdateFile(file);
479
 
480
		if ( file->GetCompressionType() == type )
481
			continue;
482
 
483
		if ( !file->GetData() )
484
			file->ReadFromFile();
485
 
486
		file->ChangeCompression ( type, progress );
487
	}
488
}
489
 
490
void CBaseFile::CompressAllFiles ( int type, CProgressInfo *progress, int level )
491
{
492
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
493
	{
494
		C_File *file = node->Data();
495
		if ( progress )
496
			progress->UpdateFile(file);
497
 
498
		if ( !file->GetData() )
499
			file->ReadFromFile();
500
 
501
		file->CompressData ( type, progress, level );
502
	}
503
}
504
 
505
bool CBaseFile::UncompressAllFiles ( CProgressInfo *progress )
506
{
507
	int countFile = 0;
508
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
509
	{
510
		C_File *fit = node->Data();
511
		if ( progress )
512
		{
513
			progress->UpdateFile ( fit );
514
			progress->UpdateProgress(countFile++, m_lFiles.size());
515
		}
516
 
517
		bool uncomprToFile = false;
518
 
519
		if ( progress )
520
			progress->SwitchSecond();
521
 
522
		if ( !fit->UncompressData ( progress ) )
523
		{
524
			if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP )
525
			{
526
				if ( !fit->UncompressToFile ( "temp", this, false, progress ) )
527
					return false;
528
				else
529
				{
530
					uncomprToFile = true;
531
					fit->SetFullDir ( "temp" );
532
				}
533
			}
534
 
535
			if ( !uncomprToFile )
536
				return false;
537
		}
538
 
539
		if ( progress )
540
			progress->SwitchSecond();
541
	}
542
	return true;
543
}
544
 
545
long CBaseFile::GetFullFileSize()
546
{
547
	long fullsize = 1000;
548
 
549
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
550
		fullsize += node->Data()->GetUncompressedDataSize();
551
 
552
	if ( m_pIconFile )
553
		fullsize += m_pIconFile->GetUncompressedDataSize();
554
 
555
	return fullsize;
556
}
557
 
558
 
559
/*
560
	Func:   GetEndOfLine
561
	Input:  id - The file id for the current file to read from
562
	        line - Pointed to hold the line number thats read
563
			upper - true if it converts to uppercase
564
	Return: String - the string it has read
565
	Desc:   Reads a string from a file, simlar to readLine() classes, reads to the end of the line in a file
566
*/
567
CyString CBaseFile::GetEndOfLine ( FILE *id, int *line, bool upper )
568
{
569
	CyString word;
570
 
571
	char c = fgetc ( id );
572
	if ( c == -1 )
573
		return "";
574
 
575
	while ( (c != 13) && (!feof(id)) && (c != '\n') )
576
	{
577
		word += c;
578
		c = fgetc ( id );
579
	}
580
 
581
	if ( line )
582
		++(*line);
583
 
584
	if ( upper )
585
		return word.ToUpper();
586
 
587
	return word;
588
}
589
 
590
int CBaseFile::CountFiles ( int filetype )
591
{
592
	int i = 0;
593
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
594
	{
595
		C_File *file = node->Data();
596
		if ( file->GetFileType() != filetype )
597
			continue;
598
		++i;
599
	}
600
 
601
	return i;
602
}
603
 
604
void CBaseFile::ClearNames ()
605
{
606
	m_lNames.clear(true);
607
}
608
void CBaseFile::RemoveLanguageName ( int lang )
609
{
610
	SNames *n;
611
	for ( n = m_lNames.First(); n; n = m_lNames.Next() )
612
	{
613
		if ( n->iLanguage == lang )
614
		{
615
			m_lNames.RemoveCurrent();
616
			delete n;
617
			m_bChanged = true;
618
		}
619
	}
620
}
621
 
622
void CBaseFile::AddLanguageName ( int lang, CyString name )
623
{
624
	// first check for an existing language
625
	SNames *n;
626
	for ( n = m_lNames.First(); n; n = m_lNames.Next() )
627
	{
628
		if ( n->iLanguage == lang )
629
		{
630
			n->sName = name;
631
			return;
632
		}
633
	}
634
 
635
	// not found, add a new entry
636
	n = new SNames;
637
	n->iLanguage = lang;
638
	n->sName = name;
639
	m_lNames.push_back ( n );
640
 
641
	m_bChanged = true;
642
}
643
 
644
/*
645
	Func:   AddInstallText
646
	Input:	before - true for before text, false for after text
647
			install - true to add to install text list, false for unisntall text list
648
			lang - string containing the language to use
649
			data - The text to add for the language
650
	Return: install text - Returns the text struct that it used to add
651
	Desc:   Adds the text to list, adds either install or uninstall text
652
			If language already exists, then its overwritten
653
			Allows adding before and after seperatly to the same entry
654
*/
655
SInstallText *CBaseFile::AddInstallText ( bool before, bool install, int lang, CyString data )
656
{
657
	CLinkList<SInstallText> *list = NULL;
658
	if ( install )
659
		list = &m_lInstallText;
660
	else
661
		list = &m_lUninstallText;
662
 
663
 
664
	SInstallText *unist = NULL;
665
	// check if language already exists and overright if needed
666
	for ( SInstallText *u = list->First(); u; u = list->Next() )
667
	{
668
		if ( u->iLanguage == lang )
669
		{
670
			unist = u;
671
			break;
672
		}
673
	}
674
 
675
	if ( !unist )
676
	{
677
		unist = new SInstallText;
678
		unist->iLanguage = lang;
679
		if ( lang == 0 )
680
			list->push_front ( unist );
681
		else
682
			list->push_back ( unist );
683
	}
684
 
685
	if ( !before )
686
		unist->sAfter = data;
687
	else
688
		unist->sBefore = data;
689
 
690
	m_bChanged = true;
691
 
692
	return unist;
693
}
694
 
695
SInstallText *CBaseFile::FindInstallText ( bool install, int lang )
696
{
697
	CLinkList<SInstallText> *list = NULL;
698
	if ( install )
699
		list = &m_lInstallText;
700
	else
701
		list = &m_lUninstallText;
702
 
703
	for ( SInstallText *it = list->First(); it; it = list->Next() )
704
	{
705
		if ( it->iLanguage == lang )
706
			return it;
707
	}
708
	return NULL;
709
}
710
 
711
void CBaseFile::AddInstallText ( SInstallText *add )
712
{
713
	SInstallText *it = FindInstallText ( true, add->iLanguage );
714
	if ( it == add )
715
		return;
716
 
717
	if ( it )
718
	{
719
		m_lInstallText.remove ( it );
720
		delete it;
721
	}
722
 
723
	m_bChanged = true;
724
 
725
	m_lInstallText.push_back ( add );
726
}
727
 
728
void CBaseFile::AddUninstallText ( SInstallText *add )
729
{
730
	SInstallText *it = FindInstallText ( false, add->iLanguage );
731
	if ( it == add )
732
		return;
733
 
734
	if ( it )
735
	{
736
		m_lUninstallText.remove ( it );
737
		delete it;
738
	}
739
 
740
	m_bChanged = true;
741
 
742
	m_lUninstallText.push_back ( add );
743
}
744
 
745
void CBaseFile::RemoveInstallText ( bool install, int lang )
746
{
747
	SInstallText *it = FindInstallText ( install, lang );
748
	if ( it )
749
	{
750
		if ( install )
751
			m_lInstallText.remove ( it );
752
		else
753
			m_lUninstallText.remove ( it );
754
		delete it;
755
		m_bChanged = true;
756
	}
757
}
758
 
759
bool CBaseFile::IsThereInstallText ( bool install )
760
{
761
	CLinkList<SInstallText> *list = NULL;
762
	if ( install )
763
		list = &m_lInstallText;
764
	else
765
		list = &m_lUninstallText;
766
 
767
	if ( list->size() > 1 )
768
		return true;
769
	if ( list->size() <= 0 )
770
		return false;
771
 
772
	SInstallText *it = list->First();
773
	if ( !it->sAfter.Empty() )
774
		return true;
775
	if ( !it->sBefore.Empty() )
776
		return true;
777
	return false;
778
}
779
 
780
CyString CBaseFile::GetBeforeText ( CLinkList<SInstallText> *list, int lang, bool noDefault )
781
{
782
	CyString beforetext;
783
	for ( SInstallText *u = list->First(); u; u = list->Next() )
784
	{
785
		if ( !noDefault )
786
		{
787
			if ( (beforetext.Empty()) && (u->iLanguage == 0) )
788
				beforetext = u->sBefore;
789
		}
790
 
791
		if ( (u->iLanguage == lang) && (!u->sBefore.Empty()) )
792
			beforetext = u->sBefore;
793
	}
794
	return beforetext;
795
}
796
 
797
CyString CBaseFile::GetAfterText ( CLinkList<SInstallText> *list, int lang, bool noDefault )
798
{
799
	CyString text;
800
	for ( SInstallText *u = list->First(); u; u = list->Next() )
801
	{
802
		if ( (u->iLanguage == lang) && (!u->sAfter.Empty()) )
803
			text = u->sAfter;
804
 
805
		if ( !noDefault )
806
		{
807
			if ( (text.Empty()) && (u->iLanguage == 0) )
808
				text = u->sAfter;
809
		}
810
	}
811
	return text;
812
}
813
 
814
CyString CBaseFile::GetFullPackageName(CyString format, int lang)
815
{
816
	if ( format.Empty() )
817
		return GetFullPackageName(lang);
818
 
819
	CyString args[3] = { this->GetLanguageName(lang), this->GetVersion(), this->GetAuthor() };
820
	return format.Args(args, 3);
821
}
822
 
823
/*
824
	Func:   CreateFilesLine
825
	Return: String - returns the full string for files list
826
	Desc:   Creates a signle line list of all the files
827
*/
828
CyString CBaseFile::CreateFilesLine ( bool updateheader, CProgressInfo *progress )
829
{
830
	CyString line;
831
 
832
	if ( progress )
833
	{
834
		progress->SetDone(0);
835
		progress->UpdateStatus(STATUS_COMPRESS);
836
	}
837
 
838
	if ( updateheader )
839
	{
840
		m_SHeader2.iNumFiles = 0;
841
		m_SHeader2.lFullSize = 0;
842
	}
843
 
844
	if ( m_pIconFile )
845
	{
846
		// no data, read it from file
847
		if ( !m_pIconFile->GetData() )
848
			m_pIconFile->ReadFromFile ();
849
 
850
		// compress the file
851
		if ( !m_pIconFile->CompressData ( m_SHeader2.iDataCompression, progress ) )
852
			m_pIconFile->SetDataCompression(SPKCOMPRESS_NONE);
853
 
854
		line += CyString("Icon:") + (m_pIconFile->GetDataSize() + (long)4) + ":" + m_pIconFile->GetUncompressedDataSize() + ":" + (long)m_pIconFile->GetCompressionType() + ":" + m_sIconExt + "\n";
855
		if ( updateheader )
856
		{
857
			++m_SHeader2.iNumFiles;
858
			m_SHeader2.lFullSize += (m_pIconFile->GetDataSize() + 4);
859
		}
860
	}
861
 
862
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
863
	{
864
		C_File *file = node->Data();
865
		if ( progress )
866
			progress->UpdateFile ( file );
867
 
868
		// no data, read it from file
869
		if ( !file->GetData() )
870
		{
871
			if ( !file->ReadFromFile () )
872
			{
873
				if ( file->GetLastError() == SPKERR_MALLOC )
874
				{
875
					if ( !file->CompressFile ( progress ) )
876
						continue;
877
				}
878
			}
879
		}
880
 
881
		if ( !file->GetData() )
882
			continue;
883
 
884
		// compress the file
885
		if ( !file->CompressData ( m_SHeader2.iDataCompression, progress ) )
886
		{
887
			file->SetDataCompression(SPKCOMPRESS_NONE);
888
			file->SetUncompressedDataSize(file->GetDataSize());
889
		}
890
 
891
		CyString command = GetFileTypeString ( file->GetFileType() );
892
		if ( command.Empty() )
893
			continue;
894
 
895
		if ( file->IsShared() )
896
			command = CyString("$") + command;
897
 
898
		if ( file->GetDir().Empty() )
899
			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");
900
		else
901
			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");
902
 
903
		if ( updateheader )
904
		{
905
			++m_SHeader2.iNumFiles;
906
			m_SHeader2.lFullSize += (file->GetDataSize() + 4);
907
		}
908
	}
909
 
910
	return line;
911
}
912
 
913
 
914
/*
915
######################################################################################
916
##########							Reading Functions			    		##########
917
######################################################################################
918
*/
919
 
920
void CBaseFile::ReadAllFilesToMemory ()
921
{
922
	// no file to read from
923
	if ( m_sFilename.Empty() )
924
		return;
925
 
926
	// now open the file
927
	FILE *id = fopen ( m_sFilename.c_str(), "rb" );
928
	if ( !id )
929
		return;
930
 
931
	// read the header
932
	GetEndOfLine ( id, NULL, false );
933
	// skip past values
934
	fseek ( id, 4, SEEK_CUR );
935
	fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );
936
 
937
	// read the next header
938
	GetEndOfLine ( id, NULL, false );
939
	// skip past files
940
	fseek ( id, 4, SEEK_CUR );
941
	fseek ( id, m_SHeader2.lSize, SEEK_CUR );
942
 
943
	if ( m_pIconFile )
944
	{
945
		if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
946
			m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );
947
		else
948
		{
949
			fseek ( id, 4, SEEK_CUR );
950
			fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );
951
		}
952
	}
953
 
954
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
955
	{
956
		C_File *fit = node->Data();
957
		if ( (!fit->GetData()) && (!fit->Skip()) )
958
			fit->ReadFromFile ( id, fit->GetDataSize() );
959
		else
960
		{
961
			fseek ( id, 4, SEEK_CUR );
962
			fseek ( id, fit->GetDataSize(), SEEK_CUR );
963
		}
964
	}
965
 
966
	fclose ( id );
967
}
968
 
969
bool CBaseFile::ReadFileToMemory(C_File *f)
970
{
971
	if ( f->GetData() && f->GetDataSize() )
972
		return true;
973
	// no file to read from
974
	if ( m_sFilename.Empty() || !f )
975
		return false;
976
 
977
	// check the file is part of the package
978
	if ( !m_lFiles.FindData(f) )
979
		return false;
980
 
981
	// now open the file
982
	FILE *id = fopen ( m_sFilename.c_str(), "rb" );
983
	if ( !id )
984
		return false;
985
 
986
	// read the header
987
	GetEndOfLine ( id, NULL, false );
988
	// skip past values
989
	fseek ( id, 4, SEEK_CUR );
990
	fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );
991
 
992
	// read the next header
993
	GetEndOfLine ( id, NULL, false );
994
	// skip past files
995
	fseek ( id, 4, SEEK_CUR );
996
	fseek ( id, m_SHeader2.lSize, SEEK_CUR );
997
 
998
	if ( m_pIconFile )
999
	{
1000
		fseek ( id, 4, SEEK_CUR );
1001
		fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );
1002
	}
1003
 
1004
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1005
	{
1006
		C_File *fit = node->Data();
1007
		if (fit == f )
1008
		{
1009
			fit->ReadFromFile ( id, fit->GetDataSize() );
1010
			break;
1011
		}
1012
		else
1013
		{
1014
			fseek ( id, 4, SEEK_CUR );
1015
			fseek ( id, fit->GetDataSize(), SEEK_CUR );
1016
		}
1017
	}
1018
 
1019
 
1020
	fclose(id);
1021
	return true;
1022
}
1023
 
1024
void CBaseFile::ReadIconFileToMemory ()
1025
{
1026
	// no file to read from
1027
	if ( m_sFilename.Empty() )
1028
		return;
1029
 
1030
	if ( !m_pIconFile )
1031
		return;
1032
 
1033
	// now open the file
1034
	FILE *id = fopen ( m_sFilename.c_str(), "rb" );
1035
	if ( !id )
1036
		return;
1037
 
1038
	// read the header
1039
	GetEndOfLine ( id, NULL, false );
1040
	// skip past values
1041
	fseek ( id, 4, SEEK_CUR );
1042
	fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );
1043
 
1044
	// read the next header
1045
	GetEndOfLine ( id, NULL, false );
1046
	// skip past files
1047
	fseek ( id, 4, SEEK_CUR );
1048
	fseek ( id, m_SHeader2.lSize, SEEK_CUR );
1049
 
1050
	if ( m_pIconFile )
1051
	{
1052
		if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
1053
			m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );
1054
		else
1055
		{
1056
			fseek ( id, 4, SEEK_CUR );
1057
			fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );
1058
		}
1059
	}
1060
 
1061
	fclose ( id );
1062
}
1063
 
1064
bool CBaseFile::InstallFiles ( CyString destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, CyStringList *errorStr, bool enabled, CPackages *packages )
1065
{
1066
	// first rename any fake patches
1067
	CyStringList lPatches;
1068
 
1069
	if ( enabled )
1070
	{
1071
		int startfake = 1;
1072
		while ( startfake < 99 )
1073
		{
1074
			CyString filename = destdir;
1075
			if ( !filename.Empty() )
1076
				filename += "/";
1077
			filename += CyString::Number((long)startfake).PadNumber(2);
1078
 
1079
			if ( !CFileIO(filename + ".cat").Exists() )
1080
			{
1081
				if ( !CFileIO(filename + ".dat").Exists() )
1082
					break;
1083
			}
1084
			startfake++;
1085
		}
1086
 
1087
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1088
		{
1089
			C_File *fit = node->Data();
1090
			// only do fake patchs
1091
			if ( !fit->IsFakePatch() )
1092
				continue;
1093
 
1094
			if ( !fit->CheckFileExt ("cat") && !fit->CheckFileExt("dat") )
1095
				continue;
1096
 
1097
			// search for the name on the list
1098
			SStringList *opposite = lPatches.FindString(fit->GetBaseName());
1099
			CyString newname;
1100
			if ( opposite )
1101
				newname = opposite->data;
1102
			else
1103
			{
1104
				newname = CyString::Number((long)startfake).PadNumber(2);
1105
				lPatches.PushBack(fit->GetBaseName(), newname);
1106
			}
1107
 
1108
			// rename the file
1109
			fit->FixOriginalName();
1110
			fit->SetName ( newname + "." + fit->GetFileExt() );
1111
 
1112
			// find the next gap
1113
			if ( !opposite )
1114
			{
1115
				startfake++; // make sure we moved past the one we've just used
1116
				while ( startfake < 99 )
1117
				{
1118
					CyString filename = destdir;
1119
					if ( !filename.Empty() )
1120
						filename += "/";
1121
					filename += CyString::Number((long)startfake).PadNumber(2);
1122
 
1123
					if ( !CFileIO(filename + ".cat").Exists() )
1124
					{
1125
						if ( !CFileIO(filename + ".dat").Exists() )
1126
							break;
1127
					}
1128
					startfake++;
1129
				}
1130
			}
1131
		}
1132
 
1133
		// find renable text file
1134
		if ( packages )
1135
		{
1136
			int starttext = 3;
1137
			while ( starttext < 9999 )
1138
			{
1139
				CyString filename = destdir;
1140
				if ( !filename.Empty() )
1141
					filename += "/t/";
1142
				filename += SPK::FormatTextName(starttext, packages->GetLanguage(), (packages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));
1143
 
1144
				if ( !CFileIO(filename + ".xml").Exists() )
1145
				{
1146
					if ( !CFileIO(filename + ".pck").Exists() )
1147
						break;
1148
				}
1149
				starttext++;
1150
			}
1151
 
1152
			for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1153
			{
1154
				C_File *fit = node->Data();
1155
				if ( !fit->IsAutoTextFile() )
1156
					continue;
1157
 
1158
				CyString newname = SPK::FormatTextName(starttext, packages->GetLanguage(), (packages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));
1159
				fit->FixOriginalName();
1160
				fit->SetName ( newname + "." + fit->GetFileExt() );
1161
 
1162
				++starttext;
1163
			}
1164
		}
1165
	}
1166
 
1167
	CDirIO Dir(destdir);
1168
	int fileCount = 0;
1169
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1170
	{
1171
		C_File *fit = node->Data();
1172
		bool fileEnabled = enabled;
1173
		if ( !fileEnabled )
1174
		{
1175
			if ( (fit->GetFileType() == FILETYPE_UNINSTALL) || (fit->GetFileType() == FILETYPE_README) || (fit->GetFileType() == FILETYPE_ADVERT) )
1176
				fileEnabled = true;
1177
			else if ( (fit->GetFileType() == FILETYPE_EXTRA) && (fit->GetDir().Left(7).ToLower() == "Extras/") )
1178
				fileEnabled = true;
1179
			else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )
1180
				fileEnabled = true;
1181
		}
1182
 
1183
		if ( fit->GetGame() && packages->GetGame() ) {
1184
			if ( fit->GetGame() != packages->GetGame() )
1185
				continue;
1186
		}
1187
 
1188
		if ( progress )
1189
		{
1190
			if ( progress->IsSecond() )
1191
				progress->SwitchSecond();
1192
			progress->UpdateFile ( fit );
1193
			progress->UpdateProgress(fileCount++, m_lFiles.size());
1194
			progress->SwitchSecond();
1195
		}
1196
 
1197
		// first uncompress the file
1198
		bool uncomprToFile = false;
1199
		m_sLastError = fit->GetNameDirectory(this);
1200
		m_iLastError = SPKERR_UNCOMPRESS;
1201
		if ( !fit->UncompressData ( progress ) )
1202
		{
1203
			if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP )
1204
			{
1205
				if ( fit->UncompressToFile ( NullString, this, false, progress ) )
1206
					uncomprToFile = true;
1207
			}
1208
 
1209
			if ( !uncomprToFile )
1210
			{
1211
				if ( errorStr )
1212
					errorStr->PushBack(m_sLastError, ERRORLOG(SPKINSTALL_UNCOMPRESS_FAIL));
1213
				return false;
1214
			}
1215
		}
1216
		ClearError ();
1217
		bool dofile = true;
1218
 
1219
		// new check if we should install the file
1220
		// first get the version
1221
		if ( fit->ReadScriptVersion () && !m_bOverrideFiles )
1222
		{
1223
			C_File checkfile;
1224
			CyString checkfilename = destdir;
1225
			if ( !checkfilename.Empty() )
1226
				checkfilename += "/";
1227
			checkfilename += fit->GetNameDirectory(this);
1228
			checkfile.SetFilename ( checkfilename );
1229
			checkfile.SetFileType ( fit->GetFileType() );
1230
			if ( checkfile.CheckValidFilePointer() )
1231
			{
1232
				if ( checkfile.ReadScriptVersion() > fit->GetVersion() )
1233
					dofile = false;
1234
			}
1235
		}
1236
 
1237
		// change file pointer
1238
		CyString filename = destdir;
1239
		if ( !filename.Empty() )
1240
			filename += "/";
1241
		if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) )
1242
			fit->SetDir ( CyString("Patch") );
1243
 
1244
		if ( fit->IsInMod() )
1245
		{
1246
			if ( fileEnabled )
1247
				fit->SetFilename(filename + fit->GetInMod() + "::" + fit->GetNameDirectory(this));
1248
			else
1249
				fit->SetFilename(filename + "PluginManager/DisabledFiles.cat::" + fit->GetNameDirectory(this));
1250
		}
1251
		else
1252
			fit->SetFilename ( filename + fit->GetNameDirectory(this) );
1253
 
1254
		if ( !fileEnabled )
1255
		{
1256
			if ( !fit->IsInMod() )
1257
			{
1258
				if ( fit->IsFakePatch() )
1259
					fit->SetFilename ( filename + "PluginManager/Disabled/FakePatches/FakePatch_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );
1260
				else if ( fit->IsAutoTextFile() )
1261
					fit->SetFilename ( filename + "PluginManager/Disabled/TextFiles/Text_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );
1262
				else
1263
					fit->SetFullDir ( filename + "PluginManager/Disabled/" + fit->GetDirectory(this) );
1264
			}
1265
			fit->SetDisabled(true);
1266
		}
1267
 
1268
		C_File *adjustPointer = NULL;
1269
 
1270
		bool checkFile = dofile;
1271
		if ( filelist )
1272
		{
1273
			C_File *cFile = NULL;
1274
			if ( checkFile )
1275
			{
1276
				if ( !fit->IsFakePatch() && fit->GetFileType() != FILETYPE_README )
1277
				{
1278
					for ( cFile = filelist->First(); cFile; cFile = filelist->Next() )
1279
					{
1280
						if ( !cFile->MatchFile ( fit ) )
1281
							continue;
1282
 
1283
						if ( !m_bOverrideFiles && !cFile->CompareNew ( fit ) )
1284
						{
1285
							if ( errorStr )
1286
								errorStr->PushBack(fit->GetNameDirectory(this), ERRORLOG(SPKINSTALL_SKIPFILE));
1287
							dofile = false;
1288
						}
1289
						break;
1290
					}
1291
				}
1292
			}
1293
 
1294
			// no matching file found, adding to main list
1295
			if ( !cFile )
1296
				filelist->push_back ( fit );
1297
			else
1298
			{
1299
				// if the file is not enabled, we need to check for any that might be enabled
1300
				if ( !fileEnabled )
1301
				{
1302
					if ( !cFile->GetUsed() )
1303
					{
1304
						CFileIO rFile(cFile->GetFilePointer());
1305
						if ( rFile.Exists() )
1306
						{
1307
							if ( errorStr )
1308
							{
1309
								if ( rFile.Remove() )
1310
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));
1311
								else
1312
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));
1313
							}
1314
						}
1315
						cFile->SetFilename(fit->GetFilePointer());
1316
						cFile->SetDisabled(true);
1317
					}
1318
					else
1319
					{
1320
						fit->SetFullDir ( filename + fit->GetDirectory(this) );
1321
						fit->SetDisabled(false);
1322
					}
1323
				}
1324
				else
1325
				// move it to enabled
1326
				{
1327
					// found a file, check if its in the disabled directory
1328
					CyString dir = cFile->GetFilePointer();
1329
					dir = dir.GetToken ( 1, dir.NumToken ('/') - 1, '/' );
1330
					CyString lastDir = dir.GetToken ( dir.NumToken('/'), '/' ).ToLower();
1331
 
1332
					// if its disabled, rename it so its enabled
1333
					if ( ((cFile->IsDisabled()) || (lastDir == "disabled") || (dir.ToLower().IsIn ("/disabled/"))) && (enabled) )
1334
					{
1335
						// first check if the directory exists
1336
						if ( cFile->IsInMod() )
1337
						{
1338
							CyString tofile = cFile->GetFilePointer().GetToken("::", 2, 2);
1339
 
1340
							CCatFile tocat;
1341
							int err = tocat.Open ( fit->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, true );
1342
							if ( (err == CATERR_NONE) || (err == CATERR_CREATED) )
1343
							{
1344
								tocat.AppendFile ( cFile->GetFilePointer(), tofile );
1345
							}
1346
 
1347
							CCatFile fromcat;
1348
							err = fromcat.Open ( cFile->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, false );
1349
							if ( err == CATERR_NONE )
1350
							{
1351
								fromcat.RemoveFile(tofile);
1352
							}
1353
 
1354
							cFile->SetFilename ( fit->GetFilePointer() );
1355
							cFile->SetInMod(fit->GetInMod());
1356
						}
1357
						else
1358
						{
1359
							CyString to = cFile->GetDirectory(this);
1360
							CDirIO Dir(destdir);
1361
							if ( !Dir.Exists(to) )
1362
							{
1363
								if ( !Dir.Create ( to ) )
1364
								{
1365
									if ( errorStr )
1366
										errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1367
									return false;
1368
								}
1369
								if ( errorStr )
1370
									errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1371
							}
1372
 
1373
							CyString destfile = destdir + "/" + cFile->GetNameDirectory(this);
1374
							if ( CFileIO(destfile).Exists() )
1375
								CFileIO(destfile).Remove();
1376
							rename ( cFile->GetFilePointer().c_str(), destfile.c_str() );
1377
							cFile->SetFilename ( destdir + "/" + cFile->GetNameDirectory(this) );
1378
						}
1379
						cFile->SetDisabled(false);
1380
 
1381
						if ( !dofile && errorStr )
1382
							errorStr->PushBack(cFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));
1383
					}
1384
				}
1385
 
1386
				adjustPointer = cFile;
1387
				if ( dofile )
1388
					adjustPointer->SetCreationTime ( fit->GetCreationTime() );
1389
			}
1390
		}
1391
 
1392
		if ( dofile )
1393
		{
1394
			// uncompressed to file, rename and move
1395
			if ( uncomprToFile )
1396
			{
1397
				m_iLastError = SPKERR_WRITEFILE;
1398
				CyString to = fit->GetDirectory(this);
1399
				//to = to.GetToken ( 1, to.NumToken ('/') - 1, '/' );
1400
				if ( !fileEnabled )
1401
					to = CyString("PluginManager/Disabled/") + to;
1402
 
1403
				CDirIO Dir(destdir);
1404
				if ( !Dir.Exists(to) )
1405
				{
1406
					if ( !Dir.Create ( to ) )
1407
					{
1408
						if ( errorStr )
1409
							errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1410
						return false;
1411
					}
1412
					if ( errorStr )
1413
						errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1414
				}
1415
 
1416
				int err = 1;
1417
				m_sLastError = to;
1418
				if ( !fit->GetTempFile ().Empty() )
1419
					err = rename ( fit->GetTempFile().c_str(), to.c_str() );
1420
				if ( err )
1421
					return false;
1422
			}
1423
			//otherwise, just extract the file
1424
			else
1425
			{
1426
				// old file is found in list, switch to using new one
1427
				if ( (filelist) && (adjustPointer) )
1428
					adjustPointer->CopyData(fit, false);
1429
 
1430
				CyString fpointer = fit->GetFilePointer();
1431
				m_iLastError = SPKERR_CREATEDIRECTORY;
1432
				CyString dir = fit->GetFilePointer().GetToken ( "/", 1, fit->GetFilePointer().NumToken("/") - 1 );
1433
 
1434
				dir = dir.Remove(destdir);
1435
				if ( dir[0] == '/' || dir[0] == '\\' )
1436
					dir.Erase(0, 1);
1437
 
1438
				m_sLastError = dir;
1439
				if ( !dir.IsIn ( "::" ) )
1440
				{
1441
					if ( !Dir.Exists(dir) )
1442
					{
1443
						if ( !Dir.Create(dir) )
1444
						{
1445
							if ( errorStr )
1446
								errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1447
							return false;
1448
						}
1449
						if ( errorStr )
1450
							errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1451
					}
1452
				}
1453
				else
1454
					fit->SetFilename(CCatFile::PckChangeExtension(fit->GetFilePointer()));
1455
 
1456
				m_iLastError = SPKERR_WRITEFILE;
1457
				m_sLastError = fit->GetFilePointer();
1458
				CyString sInstalledFile = fit->GetNameDirectory(this);
1459
				if ( fit->IsDisabled() )
1460
				{
1461
					sInstalledFile = fit->GetFilePointer().Remove(destdir);
1462
					if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )
1463
						sInstalledFile.Erase(0, 1);
1464
				}
1465
 
1466
				if ( !fit->WriteFilePointer() )
1467
				{
1468
					if ( errorStr )
1469
						errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));
1470
				}
1471
				else
1472
				{
1473
					fit->UpdateSigned();
1474
					if ( errorStr )
1475
						errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));
1476
 
1477
					switch(fit->GetFileType())
1478
					{
1479
						case FILETYPE_SCRIPT:
1480
						case FILETYPE_UNINSTALL:
1481
							fit->UpdateSignature();
1482
							break;
1483
					}
1484
				}
1485
			}
1486
			ClearError ();
1487
		}
1488
 
1489
		if ( adjustPointer )
1490
		{
1491
			node->ChangeData(adjustPointer);
1492
			delete fit;
1493
		}
1494
	}
1495
 
1496
	// now clear or data memory
1497
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1498
	{
1499
		// add plugin manager file to identify fake patches
1500
		/*
1501
		if ( fit->IsFakePatch() && fit->CheckFileExt ("cat") )
1502
		{
1503
			CFileIO plugin("pluginmanager.txt");
1504
			std::vector<CyString> lines;
1505
			CyString version;
1506
			version.FromFloat(GetLibraryVersion(), 2);
1507
			SStringList *strList = lPatches.FindData(fit->GetBaseName());
1508
 
1509
			CyString baseName;
1510
			if ( strList )
1511
				baseName = strList->str;
1512
			else
1513
				baseName = fit->GetBaseName();
1514
 
1515
			lines.push_back(CyString("FakePatch:") + baseName);
1516
			lines.push_back(CyString("spklibrary:") + version);
1517
			lines.push_back(CyString("Package:") + m_sName);
1518
			lines.push_back(CyString("Author:") + m_sAuthor);
1519
			lines.push_back(CyString("OriginalFile:") + fit->GetOriginalName());
1520
			if ( plugin.WriteFile(&lines) )
1521
			{
1522
				CCatFile cat;
1523
				if ( cat.Open(fit->GetFilePointer(), CATREAD_DAT, false) == CATERR_NONE )
1524
				{
1525
					cat.AppendFile(plugin.GetFilename(), plugin.GetFilename(), true);
1526
					cat.WriteCatFile();
1527
				}
1528
				plugin.Remove();
1529
			}
1530
		}
1531
*/
1532
		node->Data()->DeleteData();
1533
	}
1534
 
1535
	return true;
1536
}
1537
 
1538
 
1539
 
1540
/*######################################################################################################*/
1541
 
1542
 
1543
/*
1544
	Func:   ParseHeader
1545
	Input:  Header String - string formated directly from the file
1546
	Return: Boolean - If string is a valid header
1547
	Desc:   Splits up the main header string to get all required settings
1548
*/
1549
bool CBaseFile::ParseHeader ( CyString header )
1550
{
1551
	if ( !this->CheckHeader(header.GetToken ( 1, ';' )) )
1552
		return false;
1553
 
1554
	m_SHeader.fVersion = header.GetToken ( 2, ';' ).ToFloat();
1555
	if ( m_SHeader.fVersion > FILEVERSION )
1556
		return false;
1557
 
1558
	m_SHeader.iValueCompression = header.GetToken ( 3, ';' ).ToInt();
1559
	m_SHeader.lValueCompressSize = header.GetToken ( 4, ';' ).ToLong();
1560
 
1561
	return true;
1562
}
1563
 
1564
bool CSpkFile::CheckHeader ( CyString header )
1565
{
1566
	if ( header.Compare("SPKCycrow") )
1567
		return true;
1568
	return false;
1569
}
1570
bool CBaseFile::CheckHeader ( CyString header )
1571
{
1572
	if ( header.Compare("BaseCycrow") )
1573
		return true;
1574
	return false;
1575
}
1576
 
1577
/*
1578
	Func:   ParseFileHeader
1579
	Input:  Header String - string formated directly from the file
1580
	Return: Boolean - If string is a valid header
1581
	Desc:   Splits up the file header string to get all required settings
1582
*/
1583
bool CBaseFile::ParseFileHeader ( CyString header )
1584
{
1585
	if ( header.GetToken ( 1, ';' ) != "FileHeader" )
1586
		return false;
1587
 
1588
	m_SHeader2.iNumFiles = header.GetToken ( 2, ';' ).ToInt();
1589
	m_SHeader2.lSize = header.GetToken ( 3, ';' ).ToInt();
1590
	m_SHeader2.lFullSize = header.GetToken ( 4, ';' ).ToInt();
1591
	m_SHeader2.iFileCompression = header.GetToken ( 5, ';' ).ToInt();
1592
	m_SHeader2.iDataCompression = header.GetToken ( 6, ';' ).ToInt();
1593
 
1594
	return true;
1595
}
1596
 
1597
 
1598
/*
1599
	Func:   ParseValueLine
1600
	Input:  String - single line from a file to set
1601
	Return: Boolean - returns true if value exists
1602
	Desc:   Reads the line and assigns the parameters for the file
1603
*/
1604
bool CBaseFile::ParseValueLine ( CyString line )
1605
{
1606
	CyString first = line.GetToken ( 1, ' ' );
1607
	CyString rest  = line.GetToken ( 2, -1, ' ' );
1608
 
1609
	if ( first == "Name:" )
1610
		m_sName = rest;
1611
	else if ( first == "Author:" )
1612
		m_sAuthor = rest;
1613
	else if ( first == "Version:" )
1614
		m_sVersion = rest;
1615
	else if ( first == "fGameVersion:" ) {
1616
		if ( m_lGames.Back() ) {
1617
			m_lGames.Back()->Data()->sVersion = rest;
1618
		}
1619
	}
1620
	else if ( first == "GameVersion:" ) {
1621
		if ( m_lGames.Back() ) {
1622
			m_lGames.Back()->Data()->iVersion = rest.ToInt();
1623
		}
1624
	}
1625
	else if ( first == "Game:" )
1626
		this->AddGameCompatability(rest.ToInt(), NullString);
1627
	else if ( first == "GameCompat:" )
1628
		this->AddGameCompatability(rest.GetToken(" ", 1, 1).ToInt(), rest.GetToken(" ", 2, 2));
1629
	else if ( first == "GameCompatExact:" )
1630
		this->AddGameCompatability(rest.GetToken(" ", 1, 1).ToInt(), rest.GetToken(" ", 2));
1631
	else if ( first == "Date:" )
1632
		m_sCreationDate = rest;
1633
	else if ( first == "WebAddress:" )
1634
		m_sWebAddress = rest;
1635
	else if ( first == "WebSite:" )
1636
		m_sWebSite = rest;
1637
	else if ( first == "Email:" )
1638
		m_sEmail = rest;
1639
	else if ( first == "WebMirror1:" || first == "Mirror1:" || first == "WebMirror:" )
1640
		this->AddWebMirror(rest);
1641
	else if ( first == "WebMirror2:" || first == "Mirror2:" )
1642
		this->AddWebMirror(rest);
1643
	else if ( first == "PluginType:" )
1644
		m_iPluginType = rest.ToInt();
1645
	else if ( first == "Desc:" )
1646
	{
1647
		m_sDescription = rest;
1648
		m_sDescription.RemoveFirstChar('\n');
1649
		m_sDescription.RemoveFirstChar('\r');
1650
		m_sDescription.RemoveFirstSpace();
1651
		m_sDescription = m_sDescription.FindReplace("&quot;", "\"");
1652
		m_sDescription = m_sDescription.FindReplace("&gt;", ">");
1653
		m_sDescription = m_sDescription.FindReplace("&lt;", "<");
1654
		m_sDescription = m_sDescription.FindReplace("&amp;", "&");
1655
		m_sDescription = m_sDescription.FindReplace("<newline>", "\n");
1656
		m_sDescription = m_sDescription.FindReplace("<br>", "\n");
1657
 
1658
		if ( m_sDescription.Left(6).lower() == "<html>" )
1659
		{
1660
			int foundFirst = -1;
1661
			int pos = 0;
1662
			while ( foundFirst == -1 )
1663
			{
1664
				pos = m_sDescription.FindPos(">", pos);
1665
 
1666
				pos++;
1667
				if ( pos >= (int)m_sDescription.Length() )
1668
					break;
1669
				char c = m_sDescription[pos];
1670
 
1671
				if ( c != '<' )
1672
					foundFirst = pos;
1673
			}
1674
 
1675
			if ( foundFirst == -1 )
1676
				m_sDescription = "";
1677
			else
1678
			{
1679
				CyString firstStr = m_sDescription.Left(foundFirst);
1680
				firstStr.FindRemove("<br />");
1681
				firstStr.FindRemove("<br/>");
1682
				CyString lastStr = m_sDescription.Right(m_sDescription.Length() - foundFirst);
1683
 
1684
				m_sDescription = firstStr + lastStr;
1685
			}
1686
		}
1687
	}
1688
	else if ( first == "UninstallAfter:" )
1689
		AddUninstallAfterText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
1690
	else if ( first == "UninstallBefore:" )
1691
		AddUninstallBeforeText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
1692
	else if ( first == "InstallAfter:" )
1693
		AddInstallAfterText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
1694
	else if ( first == "InstallBefore:" )
1695
		AddInstallBeforeText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
1696
	else if ( first == "ScriptName:" )
1697
		AddLanguageName ( ParseLanguage(rest.GetToken ( 1, ':' )),  rest.GetToken ( 2, -1, ':' ) );
1698
	else if ( first == "GameChanging:" )
1699
		m_iGameChanging = rest.ToInt();
1700
	else if ( first == "EaseOfUse:" )
1701
		m_iEaseOfUse = rest.ToInt();
1702
	else if ( first == "Recommended:" )
1703
		m_iRecommended = rest.ToInt();
1704
	else if ( first == "NeededLibrary:" )
1705
		this->AddNeededLibrary(rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2), rest.GetToken("||", 3, 3));
1706
	else if ( first == "FakePatchBefore:" )
1707
		this->AddFakePatchOrder(false, rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2));
1708
	else if ( first == "FakePatchAfter:" )
1709
		this->AddFakePatchOrder(true, rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2));
1710
	else if ( first == "ForumLink:" )
1711
		m_sForumLink = rest;
1712
	else
1713
		return false;
1714
 
1715
	return true;
1716
}
1717
 
1718
int CBaseFile::ParseLanguage(CyString lang)
1719
{
1720
	int langID = lang.ToInt();
1721
 
1722
	if ( !langID )
1723
	{
1724
		lang = lang.ToLower();
1725
		if ( lang == "english" )
1726
			return 44;
1727
		else if ( lang == "default" )
1728
			return 0;
1729
		else if ( lang == "german" )
1730
			return 49;
1731
		else if ( lang == "russian" )
1732
			return 7;
1733
		else if ( lang == "spanish" )
1734
			return 34;
1735
		else if ( lang == "french" )
1736
			return 33;
1737
	}
1738
 
1739
	return langID;
1740
}
1741
 
1742
 
1743
int CBaseFile::ParseInstallText(CyString lang)
1744
{
1745
	return this->ParseLanguage(lang);
1746
}
1747
 
1748
/*
1749
	Func:   ParseValueLine
1750
	Input:  String - single line from a file to set
1751
	Return: Boolean - returns true if value exists
1752
	Desc:   Reads the line and assigns the parameters for the file
1753
*/
1754
bool CSpkFile::ParseValueLine ( CyString line )
1755
{
1756
	CyString first = line.GetToken ( 1, ' ' );
1757
	CyString rest  = line.GetToken ( 2, -1, ' ' );
1758
 
1759
	if ( first == "AnotherMod:" )
1760
	{
1761
		m_sOtherAuthor = rest.GetToken ( 1, '|' );
1762
		m_sOtherName = rest.GetToken ( 2, -1, '|' );
1763
	}
1764
	else if ( line == "CustomStart" )
1765
		m_iPackageType = PACKAGETYPE_CUSTOMSTART;
1766
	else if ( line == "PackageUpdate" )
1767
		m_iPackageType = PACKAGETYPE_UPDATE;
1768
	else if ( line == "Patch" )
1769
		m_iPackageType = PACKAGETYPE_PATCH;
1770
	else if ( line == "ForceProfile" )
1771
		m_bForceProfile = true;
1772
	else if ( line == "Signed" )
1773
		m_bSigned = true;
1774
	else if ( first == "ScriptType:" )
1775
		m_sScriptType = rest;
1776
	else if ( first == "ScriptTypeNew:" )
1777
		m_iScriptType = rest.ToInt();
1778
	else if ( first == "PackageType:" )
1779
		m_iPackageType = rest.ToInt();
1780
	else if ( first == "Ware:" )
1781
		AddWare ( rest );
1782
	else if ( (first == "WareText:") && (m_pLastWare) )
1783
		AddWareText ( rest );
1784
	else if ( first == "Setting:" )
1785
	{
1786
		SSettingType *t = AddSetting ( rest.GetToken ( 2, '|' ), rest.GetToken ( 1, '|' ).ToInt() );
1787
		ConvertSetting ( t, rest.GetToken ( 3, -1, '|' ) );
1788
	}
1789
	else
1790
		return CBaseFile::ParseValueLine ( line );
1791
 
1792
	return true;
1793
}
1794
 
1795
/*
1796
	Func:   ReadValues
1797
	Input:  String - values in one long line
1798
	Desc:   splits the values data into each line to read the data
1799
*/
1800
void CBaseFile::ReadValues ( CyString values )
1801
{
1802
	int num = 0;
1803
	CyString *lines = values.SplitToken ( '\n', &num );
1804
 
1805
	for ( int i = 0; i < num; i++ )
1806
		ParseValueLine ( lines[i] );
1807
 
1808
	CLEANSPLIT(lines, num)
1809
}
1810
 
1811
/*
1812
	Func:   ParseFilesLine
1813
	Input:  String - single line from a file to set
1814
	Return: Boolean - returns true if value exists
1815
	Desc:   Reads the line and assigns the parameters for the file
1816
*/
1817
bool CBaseFile::ParseFilesLine ( CyString line )
1818
{
1819
	if ( !line.IsIn(":") )
1820
		return false;
1821
 
1822
	CyString command = line.GetToken ( 1, ':' );
1823
 
1824
	long size = line.GetToken ( 2, ':').ToInt ();
1825
	long usize = line.GetToken ( 3, ':').ToInt ();
1826
	long compression = line.GetToken ( 4, ':').ToInt ();
1827
 
1828
	if ( command == "Icon" )
1829
	{
1830
		m_sIconExt = line.GetToken ( 5, ':' );
1831
		m_pIconFile = new C_File ();
1832
		m_pIconFile->SetDataSize ( size - 4 );
1833
		m_pIconFile->SetDataCompression ( compression );
1834
		m_pIconFile->SetUncompressedDataSize ( usize );
1835
 
1836
		return true;
1837
	}
1838
 
1839
	time_t time = line.GetToken ( 5,':' ).ToLong();
1840
	bool compressToFile = (line.GetToken ( 6, ':').ToInt() == 1) ? true : false;
1841
	CyString name  = line.GetToken ( 7, ':' );
1842
	CyString dir = line.GetToken ( 8, ':' );
1843
 
1844
	if ( name.Empty() )
1845
		return true;
1846
 
1847
	bool shared = false;
1848
	if ( command.Left(1) == "$" )
1849
	{
1850
		shared = true;
1851
		command.Erase ( 0, 1 );
1852
	}
1853
 
1854
	int type = -1;
1855
	if ( command == "Script" )
1856
		type = FILETYPE_SCRIPT;
1857
	else if ( command == "Text" )
1858
		type = FILETYPE_TEXT;
1859
	else if ( command == "Readme" )
1860
		type = FILETYPE_README;
1861
	else if ( command == "Map" )
1862
		type = FILETYPE_MAP;
1863
	else if ( command == "Mod" )
1864
		type = FILETYPE_MOD;
1865
	else if ( command == "Uninstall" )
1866
		type = FILETYPE_UNINSTALL;
1867
	else if ( command == "Sound" )
1868
		type = FILETYPE_SOUND;
1869
	else if ( command == "Mission" )
1870
		type = FILETYPE_MISSION;
1871
	else if ( command == "Extra" )
1872
		type = FILETYPE_EXTRA;
1873
	else if ( command == "Screen" )
1874
		type = FILETYPE_SCREEN;
1875
	else if ( command == "Backup" )
1876
		type = FILETYPE_BACKUP;
1877
	else if ( command == "Advert" )
1878
		type = FILETYPE_ADVERT;
1879
	else if ( command == "ShipScene" )
1880
		type = FILETYPE_SHIPSCENE;
1881
	else if ( command == "CockpitScene" )
1882
		type = FILETYPE_COCKPITSCENE;
1883
	else if ( command == "ShipOther" )
1884
		type = FILETYPE_SHIPOTHER;
1885
	else if ( command == "ShipModel" )
1886
		type = FILETYPE_SHIPMODEL;
1887
 
1888
	if ( type == -1 )
1889
		return false;
1890
 
1891
	C_File *file = new C_File ();
1892
 
1893
	if ( dir.Left(5).Compare("GAME_") ) {
1894
		file->SetGame(dir.GetToken("_", 2, 2).ToInt());
1895
		dir = NullString;
1896
	} 
1897
	else if ( line.NumToken(":") >= 9 ) {
1898
		file->SetGame(line.GetToken(":", 9, 9).GetToken("_", 2, 2).ToInt());
1899
	}
1900
 
1901
	file->SetFileType ( type );
1902
	file->SetCreationTime ( time );
1903
	file->SetName ( name );
1904
	file->SetDir ( dir );
1905
	file->SetDataSize ( size - 4 );
1906
	file->SetDataCompression ( compression );
1907
	file->SetUncompressedDataSize ( usize );
1908
	file->SetShared ( shared );
1909
	file->SetCompressedToFile ( compressToFile );
1910
 
1911
	m_lFiles.push_back ( file );
1912
 
1913
	return true;
1914
}
1915
 
1916
 
1917
/*
1918
	Func:   ParseFiles
1919
	Input:  String - values in one long line
1920
	Desc:   splits the files data into each line to read the data
1921
*/
1922
void CBaseFile::ReadFiles ( CyString values )
1923
{
1924
	int num = 0;
1925
	CyString *lines = values.SplitToken ( '\n', &num );
1926
 
1927
	for ( int i = 0; i < num; i++ )
1928
		ParseFilesLine ( lines[i] );
1929
 
1930
	CLEANSPLIT(lines, num)
1931
}
1932
 
1933
 
1934
 
1935
/*
1936
	Func:   ReadFile
1937
	Input:  filename - the name of the file to open and read
1938
			readdata - If falses, dont read the files to memory, just read the headers and values
1939
	Return: boolean - return ture if acceptable format
1940
	Desc:   Opens and reads the spk file and loads all data into class
1941
*/
1942
bool CBaseFile::ReadFile ( CyString filename, int readtype, CProgressInfo *progress )
1943
{
1944
	FILE *id = fopen ( filename.c_str(), "rb" );
1945
	if ( !id )
1946
		return false;
1947
 
1948
	bool ret = ReadFile ( id, readtype, progress );
1949
	if ( ret )
1950
		m_sFilename = filename;
1951
 
1952
	fclose ( id );
1953
 
1954
	return ret;
1955
}
1956
bool CBaseFile::ReadFile ( FILE *id, int readtype, CProgressInfo *progress )
1957
{
1958
	ClearError ();
1959
 
1960
	// first read the header
1961
	if ( !ParseHeader ( GetEndOfLine ( id, NULL, false ) ) )
1962
		return false;
1963
 
1964
	if ( readtype == SPKREAD_HEADER )
1965
		return true;
1966
 
1967
	// update the progress for each section
1968
	int maxProgress = (readtype == SPKREAD_VALUES) ? 3 : 6;
1969
	if ( readtype != SPKREAD_ALL && progress )
1970
		progress->UpdateProgress(1, maxProgress);
1971
 
1972
	long doneLen = 0;
1973
	// next read the data values for the spk files
1974
	if ( m_SHeader.lValueCompressSize )
1975
	{
1976
		// read data to memory
1977
		unsigned char *readData = new unsigned char[m_SHeader.lValueCompressSize];
1978
		unsigned char size[4];
1979
		fread ( size, 4, 1, id );
1980
		fread ( readData, sizeof(unsigned char), m_SHeader.lValueCompressSize, id );
1981
		unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
1982
 
1983
		// check for zlib compression
1984
		if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB )
1985
		{
1986
			// uncomress the data
1987
			unsigned char *uncompr = new unsigned char[uncomprLen];
1988
 
1989
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );
1990
			// update the progress for each section
1991
			if ( readtype != SPKREAD_ALL && progress )
1992
				progress->UpdateProgress(2, maxProgress);
1993
			if ( err == Z_OK )
1994
				ReadValues ( CyString ((char *)uncompr) );
1995
			doneLen = uncomprLen;
1996
			delete uncompr;
1997
		}
1998
		else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
1999
		{
2000
			long len = uncomprLen;
2001
			unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lValueCompressSize, (size_t*)&len, NULL );
2002
			// update the progress for each section
2003
			if ( readtype != SPKREAD_ALL && progress )
2004
				progress->UpdateProgress(2, maxProgress);
2005
 
2006
			if ( compr )
2007
				ReadValues ( CyString ((char *)compr) );
2008
		}
2009
		// no compression
2010
		else
2011
			ReadValues ( CyString ((char *)readData) );
2012
 
2013
		delete readData;
2014
	}
2015
 
2016
	// update the progress for each section
2017
	if ( readtype != SPKREAD_ALL && progress )
2018
		progress->UpdateProgress(3, maxProgress);
2019
 
2020
	if ( readtype == SPKREAD_VALUES )
2021
		return true;
2022
 
2023
	// next should be the next header
2024
	if ( !ParseFileHeader ( GetEndOfLine (id, NULL, false) ) )
2025
		return false;
2026
 
2027
	// clear the current file list
2028
	m_lFiles.clear(true);
2029
 
2030
	// update the progress for each section
2031
	if ( readtype != SPKREAD_ALL && progress )
2032
		progress->UpdateProgress(4, maxProgress);
2033
 
2034
	if ( m_SHeader2.lSize )
2035
	{
2036
		unsigned char *readData = new unsigned char[m_SHeader2.lSize];
2037
		unsigned char size[4];
2038
		fread ( size, 4, 1, id );
2039
		fread ( readData, sizeof(char), m_SHeader2.lSize, id );
2040
 
2041
		unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
2042
		// check for zlib compression
2043
		if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB )
2044
		{
2045
 
2046
			if ( uncomprLen < (unsigned long)doneLen )
2047
				uncomprLen = doneLen;
2048
 
2049
			unsigned char *uncompr = new unsigned char[uncomprLen];
2050
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );
2051
			// update the progress for each section
2052
			if ( readtype != SPKREAD_ALL && progress )
2053
				progress->UpdateProgress(5, maxProgress);
2054
			if ( err == Z_OK )
2055
				ReadFiles ( CyString ((char *)uncompr) );
2056
			delete uncompr;
2057
		}
2058
		else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
2059
		{
2060
			long len = uncomprLen;
2061
			unsigned char *compr = LZMADecode_C ( readData, m_SHeader2.lSize, (size_t*)&len, NULL );
2062
			// update the progress for each section
2063
			if ( readtype != SPKREAD_ALL && progress )
2064
				progress->UpdateProgress(5, maxProgress);
2065
			if ( compr )
2066
				ReadFiles ( CyString ((char *)compr) );
2067
		}
2068
		else
2069
			ReadFiles ( CyString ((char *)readData) );
2070
 
2071
		delete readData;
2072
	}
2073
 
2074
	// file mismatch
2075
	long numfiles = m_lFiles.size();
2076
	if ( m_pIconFile )
2077
		++numfiles;
2078
	if ( m_SHeader2.iNumFiles != numfiles )
2079
	{
2080
		m_iLastError = SPKERR_FILEMISMATCH;
2081
		return false;
2082
	}
2083
 
2084
	// update the progress for each section
2085
	if ( readtype != SPKREAD_ALL && progress )
2086
		progress->UpdateProgress(6, maxProgress);
2087
 
2088
	if ( readtype == SPKREAD_ALL )
2089
	{
2090
		int fileCount = 2;
2091
		if ( m_pIconFile )
2092
			m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );
2093
 
2094
		// ok finally we need to read all the files
2095
 
2096
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2097
		{
2098
			node->Data()->ReadFromFile ( id, node->Data()->GetDataSize() );
2099
			if ( progress )
2100
				progress->UpdateProgress(fileCount++, m_lFiles.size() + 2);
2101
		}
2102
 
2103
		m_bFullyLoaded = true;
2104
	}
2105
 
2106
	return true;
2107
}
2108
 
2109
bool CBaseFile::IsMod()
2110
{
2111
	// check for any mod files that are not fake patchs
2112
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
2113
	{
2114
		C_File *f = fNode->Data();
2115
		if ( f->GetFileType() != FILETYPE_MOD )
2116
			continue;
2117
 
2118
		if ( !f->IsFakePatch() )
2119
			return true;
2120
	}
2121
 
2122
	return false;
2123
}
2124
 
2125
bool CBaseFile::IsFakePatch()
2126
{
2127
	// check for any mod files that are not fake patchs
2128
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
2129
	{
2130
		C_File *f = fNode->Data();
2131
		if ( f->GetFileType() != FILETYPE_MOD )
2132
			continue;
2133
 
2134
		if ( f->IsFakePatch() )
2135
			return true;
2136
	}
2137
 
2138
	return false;
2139
}
2140
 
2141
CyString CBaseFile::CreateValuesLine ()
2142
{
2143
	CyString values ( "Name: " );
2144
	values += (m_sName + "\n");
2145
	values += (CyString("Author: ") + m_sAuthor + "\n");
2146
	values += (CyString("Version: ") + m_sVersion + "\n");
2147
	if ( !m_sCreationDate.Empty() )
2148
		values += (CyString("Date: ") + m_sCreationDate + "\n");
2149
	if ( !m_sWebAddress.Empty() )
2150
		values += (CyString("WebAddress: ") + m_sWebAddress + "\n");
2151
	if ( !m_sWebSite.Empty() )
2152
		values += (CyString("WebSite: ") + m_sWebSite + "\n");
2153
	if ( !m_sEmail.Empty() )
2154
		values += (CyString("Email: ") + m_sEmail + "\n");
2155
	for ( SStringList *str = m_lMirrors.Head(); str; str = str->next )
2156
		values += (CyString("WebMirror: ") + str->str + "\n");
2157
	if ( !m_sDescription.Empty() )
2158
	{
2159
		CyString desc = m_sDescription;
2160
		desc = desc.FindReplace("<newline>", "<br>");
2161
		desc = desc.FindReplace("\n", "<br>");
2162
		desc.RemoveChar("\r");
2163
		values += (CyString("Desc: ") + desc + "\n");
2164
	}
2165
 
2166
	for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {
2167
		if ( !gc->Data()->sVersion.Empty() )
2168
			values += CyString("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion + "\n";
2169
		else
2170
			values += CyString("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";
2171
	}
2172
	if ( !m_sForumLink.Empty() )
2173
		values += (CyString("ForumLink: ") + m_sForumLink + "\n");
2174
 
2175
	if ( m_bSigned )
2176
		values += "Signed\n";
2177
 
2178
	SInstallText *it;
2179
	for ( it = m_lUninstallText.First(); it; it = m_lUninstallText.Next() )
2180
	{
2181
		if ( !it->sAfter.Empty() )
2182
			values += (CyString("UninstallAfter: ") + CyString::Number(it->iLanguage) + "|" + it->sAfter + "\n");
2183
		if ( !it->sBefore.Empty() )
2184
			values += (CyString("UninstallBefore: ") + CyString::Number(it->iLanguage) + "|" + it->sBefore + "\n");
2185
	}
2186
	for ( it = m_lInstallText.First(); it; it = m_lInstallText.Next() )
2187
	{
2188
		if ( !it->sAfter.Empty() )
2189
			values += (CyString("InstallAfter: ") + CyString::Number(it->iLanguage) + "|" + it->sAfter + "\n");
2190
		if ( !it->sBefore.Empty() )
2191
			values += (CyString("InstallBefore: ") + CyString::Number(it->iLanguage) + "|" + it->sBefore + "\n");
2192
	}
2193
 
2194
	values += CyString("GameChanging: ") + CyString::Number(m_iGameChanging) + "\n";
2195
	values += CyString("EaseOfUse: ") + CyString::Number(m_iEaseOfUse) + "\n";
2196
	values += CyString("Recommended: ") + CyString::Number(m_iRecommended) + "\n";
2197
 
2198
	for ( SNames *sn = m_lNames.First(); sn; sn = m_lNames.Next() )
2199
		values += CyString("ScriptName: ") + CyString::Number(sn->iLanguage) + ":" + sn->sName + "\n";
2200
 
2201
	for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() )
2202
	{
2203
		SNeededLibrary *l = libNode->Data();
2204
		values += (CyString("NeededLibrary: ") + l->sName + "||" + l->sAuthor + "||" + l->sMinVersion + "\n");
2205
	}
2206
 
2207
	for ( SStringList *fpbNode = m_lFakePatchBefore.Head(); fpbNode; fpbNode = fpbNode->next )
2208
		values += (CyString("FakePatchBefore: ") + fpbNode->str + "||" + fpbNode->data + "\n");
2209
	for ( SStringList *fpaNode = m_lFakePatchAfter.Head(); fpaNode; fpaNode = fpaNode->next )
2210
		values += (CyString("FakePatchAfter: ") + fpaNode->str + "||" + fpaNode->data + "\n");
2211
 
2212
	values += (CyString("PluginType: ") + (long)m_iPluginType + "\n");
2213
 
2214
	return values;
2215
}
2216
 
2217
/*
2218
	Func:   CreateValuesLine
2219
	Return: String - returns the full string for values
2220
	Desc:   Creates a single string for all values, this is used when compressing to write to the spk file
2221
*/
2222
CyString CSpkFile::CreateValuesLine ()
2223
{
2224
	CyString values = CBaseFile::CreateValuesLine ();
2225
	// combine all values together
2226
	if ( (!m_sOtherAuthor.Empty()) && (!m_sOtherName.Empty()) )
2227
		values += (CyString("AnotherMod: ") + m_sOtherAuthor + "|" + m_sOtherName + "\n");
2228
	if ( m_bForceProfile )
2229
		values += "ForceProfile\n";
2230
	if ( !m_sScriptType.Empty() )
2231
		values += (CyString("ScriptType: ") + m_sScriptType + "\n");
2232
	values += (CyString("PackageType: ") + (long)m_iPackageType + "\n");
2233
	values += (CyString("ScriptTypeNew: ") + (long)m_iScriptType + "\n");
2234
 
2235
	for ( SSettingType *st = m_lSettings.First(); st; st = m_lSettings.Next() )
2236
		values += (CyString("Setting: ") + CyString::Number(st->iType) + "|" + st->sKey + "|" + GetSetting(st) + "\n");
2237
 
2238
	for ( SWares *ware = m_lWares.First(); ware; ware = m_lWares.Next() )
2239
	{
2240
		if ( ware->iTextID > 0 )
2241
			values += CyString("Ware: ") + ware->cType + ":" + ware->iPrice + ":" + (long)ware->iSize + ":" + (long)ware->iVolumn + ":" + ware->sID + ":" + (long)ware->iNotority + ":" + (long)ware->iTextID + "," + (long)ware->iTextPage + "\n";
2242
		else
2243
			values += CyString("Ware: ") + ware->cType + ":" + ware->iPrice + ":" + (long)ware->iSize + ":" + (long)ware->iVolumn + ":" + ware->sID + ":" + (long)ware->iNotority + "\n";
2244
		for ( SWaresText *wt = ware->lText.First(); wt; wt = ware->lText.Next() )
2245
			values += CyString("WareText: ") + (long)wt->iLang + " " + wt->sName + "|" + wt->sDesc + "\n";
2246
	}
2247
 
2248
	return values;
2249
}
2250
 
2251
CyString CSpkFile::GetCustomScriptType (int lang)
2252
{
2253
	if ( !m_sScriptType.Empty() )
2254
	{
2255
		int max;
2256
		CyString *split = m_sScriptType.SplitToken("<br>", &max);
2257
		if ( max && split )
2258
		{
2259
			for ( int i = 1; i < max; i++ )
2260
			{
2261
				CyString str = split[i];
2262
				int num = str.GetToken(":", 1, 1).ToInt();
2263
				CyString name = str.GetToken(":", 2);
2264
 
2265
				if ( num == lang )
2266
				{
2267
					CLEANSPLIT(split, max)
2268
					return name;
2269
				}
2270
			}
2271
 
2272
			CyString ret = split[0];
2273
			CLEANSPLIT(split, max)
2274
 
2275
			return ret;
2276
		}
2277
		CLEANSPLIT(split, max)
2278
	}
2279
	return m_sScriptType;
2280
}
2281
 
2282
/*
2283
	Func:   WriteFile
2284
	Input:  filename - The filename of the spk file to write to
2285
	Desc:   Writes the data to an spk file
2286
*/
2287
bool CBaseFile::WriteFile ( CyString filename, CProgressInfo *progress )
2288
{
2289
	FILE *id = fopen ( filename.c_str(), "wb" );
2290
	if ( !id )
2291
		return false;
2292
 
2293
	bool ret = WriteData ( id, progress );
2294
	fclose ( id );
2295
 
2296
	return ret;
2297
}
2298
 
2299
bool CSpkFile::WriteHeader(FILE *id, int valueheader, int valueComprLen)
2300
{
2301
	fprintf ( id, "SPKCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );
2302
	if ( ferror(id) )
2303
		return false;
2304
	return true;
2305
}
2306
 
2307
bool CBaseFile::WriteHeader(FILE *id, int valueheader, int valueComprLen)
2308
{
2309
	fprintf ( id, "BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );
2310
	if ( ferror(id) )
2311
		return false;
2312
	return true;
2313
}
2314
 
2315
bool CBaseFile::WriteData ( FILE *id, CProgressInfo *progress )
2316
{
2317
	int valueheader = m_SHeader.iValueCompression, fileheader = m_SHeader.iValueCompression;
2318
	if ( valueheader == SPKCOMPRESS_7ZIP )
2319
		valueheader = SPKCOMPRESS_ZLIB;
2320
	if ( fileheader == SPKCOMPRESS_7ZIP )
2321
		fileheader = SPKCOMPRESS_ZLIB;
2322
 
2323
	// get the script values
2324
	this->UpdateSigned(true);
2325
	CyString values = this->CreateValuesLine();
2326
 
2327
	// compress the values
2328
	int valueUncomprLen = (int)values.Length();
2329
	unsigned long valueComprLen = 0;
2330
	unsigned char *valueCompr = NULL;
2331
	bool compressed = false;
2332
	if ( valueheader == SPKCOMPRESS_ZLIB )
2333
	{
2334
		valueComprLen = valueUncomprLen;
2335
		if ( valueComprLen < 100 )
2336
			valueComprLen = 200;
2337
		else if ( valueComprLen < 1000 )
2338
			valueComprLen *= 2;
2339
 
2340
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
2341
		int err = compress ( (unsigned char *)valueCompr, &valueComprLen, (const unsigned char *)values.c_str(), (unsigned long)values.Length(), 0 );
2342
		if ( err == Z_OK )
2343
			compressed = true;
2344
	}
2345
 
2346
	if ( !compressed )
2347
	{
2348
		valueComprLen = valueUncomprLen;
2349
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
2350
		memcpy ( valueCompr, values.c_str(), valueComprLen );
2351
		valueheader = SPKCOMPRESS_NONE;
2352
	}
2353
 
2354
	// write the main header to the file
2355
	if ( !this->WriteHeader(id, valueheader, valueComprLen) )
2356
		return false;
2357
 
2358
	// write the compressed data to file
2359
	fputc ( (unsigned char)(valueUncomprLen >> 24), id );
2360
	fputc ( (unsigned char)(valueUncomprLen >> 16), id );
2361
	fputc ( (unsigned char)(valueUncomprLen >> 8), id );
2362
	fputc ( (unsigned char)valueUncomprLen, id );
2363
	fwrite ( valueCompr, sizeof(char), valueComprLen, id );
2364
 
2365
	free ( valueCompr );
2366
 
2367
	// now compress the files header
2368
	// create the files values
2369
	CyString files = CreateFilesLine ( true, progress );
2370
 
2371
	// compress the files values
2372
	long fileUncomprLen = (long)files.Length(), fileComprLen = fileUncomprLen;
2373
	unsigned char *fileCompr = NULL;
2374
 
2375
	compressed = false;
2376
	if ( fileUncomprLen )
2377
	{
2378
		if ( fileheader == SPKCOMPRESS_ZLIB )
2379
		{
2380
			if ( fileComprLen < 100 )
2381
				fileComprLen = 200;
2382
			else if ( fileComprLen < 1000 )
2383
				fileComprLen *= 2;
2384
			fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
2385
			int err = compress ( (unsigned char *)fileCompr, (unsigned long *)&fileComprLen, (const unsigned char *)files.c_str(), (unsigned long)files.Length(), 0 );
2386
			if ( err == Z_OK )
2387
				compressed = true;
2388
		}
2389
	}
2390
 
2391
	// if unable to compress, store it as plain text
2392
	if ( !compressed )
2393
	{
2394
		fileComprLen = fileUncomprLen;
2395
		fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
2396
		memcpy ( fileCompr, files.c_str(), fileComprLen );
2397
		fileheader = SPKCOMPRESS_NONE;
2398
	}
2399
 
2400
	// now write the file header
2401
	m_SHeader2.lSize = fileComprLen;
2402
	fprintf ( id, "FileHeader;%d;%ld;%ld;%d;%d\n", m_SHeader2.iNumFiles, m_SHeader2.lSize, m_SHeader2.lFullSize, fileheader, m_SHeader2.iDataCompression );
2403
 
2404
	fputc ( (unsigned char)(fileUncomprLen >> 24), id );
2405
	fputc ( (unsigned char)(fileUncomprLen >> 16), id );
2406
	fputc ( (unsigned char)(fileUncomprLen >> 8), id );
2407
	fputc ( (unsigned char)fileUncomprLen, id );
2408
	fwrite ( fileCompr, sizeof(char), fileComprLen, id );
2409
 
2410
	free ( fileCompr );
2411
 
2412
	if ( progress )
2413
	{
2414
		progress->UpdateStatus(STATUS_WRITE);
2415
		progress->SetDone(0);
2416
		long max = 0;
2417
		for ( C_File *file = m_lFiles.First(); file; file = m_lFiles.Next() )
2418
			max += file->GetDataSize();
2419
		if ( m_pIconFile )
2420
			max += m_pIconFile->GetDataSize();
2421
		progress->SetMax(max);
2422
	}
2423
 
2424
	// now finally, write all the file data
2425
	if ( m_pIconFile )
2426
	{
2427
		if ( progress )
2428
			progress->UpdateFile(m_pIconFile);
2429
		fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 24), id );
2430
		fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 16), id );
2431
		fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 8), id );
2432
		fputc ( (unsigned char)m_pIconFile->GetUncompressedDataSize(), id );
2433
		fwrite ( m_pIconFile->GetData(), sizeof(char), m_pIconFile->GetDataSize(), id );
2434
		if ( progress )
2435
			progress->IncDone(m_pIconFile->GetDataSize());
2436
	}
2437
 
2438
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2439
	{
2440
		C_File *file = node->Data();
2441
		if ( progress )
2442
			progress->UpdateFile(file);
2443
		fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 24), id );
2444
		fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 16), id );
2445
		fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 8), id );
2446
		fputc ( (unsigned char)file->GetUncompressedDataSize(), id );
2447
		unsigned char *data = file->GetData();
2448
		size_t remaining = file->GetDataSize();
2449
		while ( remaining )
2450
		{
2451
			size_t writeSize = WRITECHUNK;
2452
			if ( writeSize > remaining )
2453
				writeSize = remaining;
2454
 
2455
			size_t written = fwrite ( data, sizeof(char), writeSize, id );
2456
			data += written;
2457
			remaining -= written;
2458
 
2459
			if ( progress )
2460
				progress->IncDone((int)written);
2461
		}
2462
 
2463
	}
2464
 
2465
	m_bChanged = false;
2466
 
2467
	return true;
2468
}
2469
 
2470
 
2471
 
2472
 
2473
void CSpkFile::AddWareText ( CyString rest )
2474
{
2475
	if ( !m_pLastWare )
2476
		return;
2477
 
2478
	SWaresText *wt = new SWaresText;
2479
	wt->iLang = rest.GetToken ( 1, ' ' ).ToInt();
2480
	wt->sName = rest.GetToken ( 2, -1, ' ' ).GetToken ( 1, '|' );
2481
	wt->sDesc = rest.GetToken ( 2, -1, ' ' ).GetToken ( 2, -1, '|' );
2482
	m_pLastWare->lText.push_back ( wt );
2483
 
2484
	m_bChanged = true;
2485
}
2486
 
2487
void CSpkFile::AddWare ( CyString rest )
2488
{
2489
	SWares *ware = new SWares;
2490
	ware->iTextID = -1;
2491
	ware->iTextPage = 0;
2492
	ware->cType = rest.GetToken ( 1, ':' )[0];
2493
	ware->iPrice = rest.GetToken ( 2, ':' ).ToLong();
2494
	ware->iSize = rest.GetToken ( 3, ':' ).ToInt();
2495
	ware->iVolumn = rest.GetToken ( 4, ':' ).ToInt();
2496
	ware->sID = rest.GetToken ( 5, ':' );
2497
	ware->iNotority = rest.GetToken ( 6, ':' ).ToInt();
2498
	if ( !rest.GetToken( 7, ':' ).Empty() )
2499
	{
2500
		CyString r = rest.GetToken ( 7, ':' );
2501
		ware->iTextID = r.GetToken(",", 1, 1).ToInt();
2502
		ware->iTextPage = r.GetToken(",", 2, 2).ToInt();
2503
	}
2504
	m_lWares.push_back ( ware );
2505
	m_pLastWare = ware;
2506
 
2507
	m_bChanged = true;
2508
}
2509
 
2510
 
2511
 
2512
bool CSpkFile::ReadFileToMemory ( C_File *file )
2513
{
2514
	if ( !file )
2515
		return false;
2516
 
2517
	// check if data is already extracted
2518
	if ( (file->GetDataSize ()) && (file->GetData()) )
2519
		return true;
2520
 
2521
	// no file to read from
2522
	if ( m_sFilename.Empty() )
2523
		return false;
2524
 
2525
	// now open the file
2526
	FILE *id = fopen ( m_sFilename.c_str(), "rb" );
2527
	if ( !id )
2528
		return false;
2529
 
2530
	// read the header
2531
	GetEndOfLine ( id, NULL, false );
2532
	// skip past values
2533
	fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );
2534
 
2535
	// read the next header
2536
	GetEndOfLine ( id, NULL, false );
2537
	// skip past files
2538
	fseek ( id, 4, SEEK_CUR );
2539
	fseek ( id, m_SHeader2.lSize, SEEK_CUR );
2540
 
2541
	// skip the icon file
2542
	if ( m_pIconFile )
2543
	{
2544
		fseek ( id, 4, SEEK_CUR );
2545
		fseek ( id, m_pIconFile->GetDataSize (), SEEK_CUR );
2546
	}
2547
 
2548
	// now were in the file section
2549
	// skip past each one
2550
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2551
	{
2552
		C_File *fit = node->Data();
2553
		if ( fit == file )
2554
			break;
2555
 
2556
		fseek ( id, 4, SEEK_CUR );
2557
		fseek ( id, fit->GetDataSize(), SEEK_CUR );
2558
	}
2559
 
2560
	// now we should be at the start of the file
2561
	// read the data into memory
2562
	if ( !file->ReadFromFile ( id, file->GetDataSize() ) )
2563
	{
2564
		fclose ( id );
2565
		return false;
2566
	}
2567
	fclose ( id );
2568
 
2569
	return true;
2570
}
2571
 
2572
bool CBaseFile::ExtractFile ( C_File *file, CyString dir, bool includedir, CProgressInfo *progress )
2573
{
2574
	if ( ReadFileToMemory ( file ) )
2575
	{
2576
		// now finally, uncompress the file
2577
		long len = 0;
2578
		unsigned char *data = file->UncompressData ( &len, progress );
2579
		if ( !data )
2580
		{
2581
			// attempt a file decompress
2582
			if ( file->GetCompressionType() == SPKCOMPRESS_7ZIP )
2583
			{
2584
				if ( file->UncompressToFile ( dir, this, includedir, progress ) )
2585
					return true;
2586
			}
2587
			return false;
2588
		}
2589
 
2590
		if ( !file->WriteToDir ( dir, this, includedir, NullString, data, len ) )
2591
			return false;
2592
 
2593
		return true;
2594
 
2595
	}
2596
	else
2597
		return false;
2598
}
2599
 
2600
bool CBaseFile::ExtractFile ( int filenum, CyString dir, bool includedir, CProgressInfo *progress )
2601
{
2602
	// invalid valus
2603
	if ( filenum < 0 )
2604
		return false;
2605
	// out of range
2606
	if ( filenum > m_lFiles.size() )
2607
		return false;
2608
 
2609
	// get the file pointer
2610
	C_File *file = m_lFiles.Get ( filenum );
2611
	return ExtractFile ( file, dir, includedir, progress );
2612
}
2613
 
2614
 
2615
 
2616
bool CBaseFile::ExtractAll ( CyString dir, int game, bool includedir, CProgressInfo *progress )
2617
{
2618
	// no file to read from
2619
	if ( m_sFilename.Empty() )
2620
		return false;
2621
 
2622
	// now open the file
2623
	FILE *id = fopen ( m_sFilename.c_str(), "rb" );
2624
	if ( !id )
2625
		return false;
2626
 
2627
	fseek ( id, 0, SEEK_SET );
2628
	// read the header
2629
	GetEndOfLine ( id, NULL, false );
2630
	// skip past values
2631
	fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );
2632
 
2633
	// read the next header
2634
	GetEndOfLine ( id, NULL, false );
2635
	// skip past files
2636
	fseek ( id, 4, SEEK_CUR );
2637
	fseek ( id, m_SHeader2.lSize, SEEK_CUR );
2638
 
2639
	// now were in the file section
2640
	// skip past each one
2641
	if ( m_pIconFile )
2642
	{
2643
		fseek ( id, 4, SEEK_CUR );
2644
		fseek ( id, m_pIconFile->GetDataSize (), SEEK_CUR );
2645
	}
2646
 
2647
	CDirIO Dir(dir);
2648
 
2649
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2650
	{
2651
		C_File *fit = node->Data();
2652
 
2653
		if ( progress )
2654
			progress->UpdateFile ( fit );
2655
 
2656
		if ( (!fit->GetDataSize ()) || (!fit->GetData()) )
2657
		{
2658
			if ( !fit->ReadFromFile ( id, fit->GetDataSize() ) )
2659
			{
2660
				fclose ( id );
2661
				return false;
2662
			}
2663
		}
2664
		else
2665
			fseek ( id, fit->GetDataSize(), SEEK_CUR );
2666
 
2667
		if ( game ) {
2668
			if ( fit->GetGame() && fit->GetGame() != game )
2669
				continue;
2670
		}
2671
 
2672
		// create directory first
2673
		Dir.Create(fit->GetDirectory(this));
2674
 
2675
		long size = 0;
2676
		unsigned char *data = fit->UncompressData (&size, progress);
2677
		if ( (!data) && (fit->GetCompressionType() == SPKCOMPRESS_7ZIP) )
2678
		{
2679
			if ( !fit->UncompressToFile ( dir, this, includedir, progress ) )
2680
			{
2681
				fclose ( id );
2682
				return false;
2683
			}
2684
		}
2685
		else if ( (!data) || (!fit->WriteToDir ( dir, this, includedir, NullString, data, size )) )
2686
		{
2687
			fclose ( id );
2688
			return false;
2689
		}
2690
	}
2691
 
2692
	fclose ( id );
2693
 
2694
	return true;
2695
}
2696
 
2697
 
2698
 
2699
bool CSpkFile::CheckValidReadmes ()
2700
{
2701
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2702
	{
2703
		C_File *file = node->Data();
2704
		if ( file->GetFileType() != FILETYPE_README )
2705
			continue;
2706
		if ( !file->CheckValidFilePointer() )
2707
			continue;
2708
		return true;
2709
	}
2710
 
2711
	return false;
2712
}
2713
 
2714
 
2715
 
2716
void CSpkFile::ClearWares()
2717
{
2718
	for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() )
2719
	{
2720
		node->Data()->lText.clear(true);
2721
		node->DeleteData();
2722
	}
2723
	m_bChanged = true;
2724
	m_lWares.clear(true);
2725
}
2726
 
2727
SWares *CSpkFile::FindWare ( CyString id )
2728
{
2729
	for ( SWares *w = m_lWares.First(); w; w = m_lWares.Next() )
2730
	{
2731
		if ( w->sID.ToUpper() == id.ToUpper() )
2732
			return w;
2733
	}
2734
	return NULL;
2735
}
2736
 
2737
void CSpkFile::RemoveWare ( CyString id )
2738
{
2739
	for ( SWares *w = m_lWares.First(); w; w = m_lWares.Next() )
2740
	{
2741
		if ( w->sID.ToUpper() == id.ToUpper() )
2742
		{
2743
			m_lWares.RemoveCurrent ();
2744
			delete w;
2745
			m_bChanged = true;
2746
			return;
2747
		}
2748
	}
2749
}
2750
 
2751
void CSpkFile::AddWare ( SWares *ware )
2752
{
2753
	ware->sID.RemoveChar ( ' ' );
2754
	ware->sID = ware->sID.ToUpper();
2755
 
2756
	SWares *newware = FindWare ( ware->sID );
2757
	if ( newware )
2758
		m_lWares.remove ( newware );
2759
 
2760
	m_lWares.push_back ( ware );
2761
	m_bChanged = true;
2762
}
2763
 
2764
void CSpkFile::AddWareText ( SWares *w, int lang, CyString name, CyString desc )
2765
{
2766
	SWaresText *wt;
2767
	for ( wt = w->lText.First(); wt; wt = w->lText.Next() )
2768
	{
2769
		if ( wt->iLang == lang )
2770
		{
2771
			wt->sDesc = desc;
2772
			wt->sName = name;
2773
			return;
2774
		}
2775
	}
2776
 
2777
	wt = new SWaresText;
2778
	wt->iLang = lang;
2779
	wt->sName = name;
2780
	wt->sDesc = desc;
2781
 
2782
	w->lText.push_back ( wt );
2783
	m_bChanged = true;
2784
}
2785
 
2786
 
2787
void CSpkFile::ClearWareText ( CyString id )
2788
{
2789
	SWares *w = FindWare ( id );
2790
	ClearWareText ( w );
2791
}
2792
 
2793
void CSpkFile::ClearWareText ( SWares *w )
2794
{
2795
	if ( !w ) return;
2796
 
2797
	w->lText.clear(true);
2798
	m_bChanged = true;
2799
}
2800
 
2801
void CSpkFile::RemoveWareText ( CyString wid, int lang )
2802
{
2803
	SWares *w = FindWare ( wid );
2804
	if ( w )
2805
	{
2806
		for ( SWaresText *wt = w->lText.First(); wt; wt = w->lText.Next() )
2807
		{
2808
			if ( wt->iLang == lang )
2809
			{
2810
				w->lText.RemoveCurrent();
2811
				m_bChanged = true;
2812
				delete wt;
2813
				break;
2814
			}
2815
		}
2816
	}
2817
}
2818
 
2819
int CSpkFile::CheckValidCustomStart ()
2820
{
2821
 
2822
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2823
	{
2824
		C_File *file = node->Data();
2825
		if ( file->GetFileType() != FILETYPE_SCRIPT )
2826
			continue;
2827
 
2828
		CyString basename = file->GetName().GetToken ( 1, file->GetName().NumToken('.') - 1, '.' );
2829
		if ( basename.ToLower().Right(15) == ".initplayership" )
2830
			return 0;
2831
	}
2832
	if ( !IsAnotherMod() )
2833
		return 1;
2834
	else
2835
		return 2;
2836
}
2837
 
2838
bool CBaseFile::UpdateSigned (bool updateFiles)
2839
{
2840
	m_bSigned = true;
2841
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2842
	{
2843
		C_File *file = node->Data();
2844
		if ( updateFiles )
2845
			file->UpdateSigned();
2846
		// extra, text, soundtrack, readmes and screen files do not require a modified game directly
2847
		if ( (file->GetFileType() == FILETYPE_EXTRA) || (file->GetFileType() == FILETYPE_TEXT) || (file->GetFileType() == FILETYPE_SOUND) || (file->GetFileType() == FILETYPE_SCREEN) || (file->GetFileType() == FILETYPE_README) )
2848
			continue;
2849
		// mods and maps always need modified game
2850
		else if ( (file->GetFileType() == FILETYPE_MOD) || (file->GetFileType() == FILETYPE_MAP) )
2851
		{
2852
			m_bSigned = false;
2853
			break;
2854
		}
2855
 
2856
		// else should be a script file, script or uninstall type
2857
		// all scripts must be signed, if any are not, then no signed status
2858
		if ( !file->IsSigned () )
2859
		{
2860
			m_bSigned = false;
2861
			break;
2862
		}
2863
	}
2864
 
2865
	return m_bSigned;
2866
}
2867
 
2868
bool CSpkFile::UpdateSigned (bool updateFiles)
2869
{
2870
	// check for any custom wares
2871
	// patch mods and custom starts are also not signed
2872
	if ( (!m_lWares.empty()) || (this->IsPatch()) || (this->IsCustomStart()) )
2873
	{
2874
		m_bSigned = false;
2875
		return false;
2876
	}
2877
 
2878
	return CBaseFile::UpdateSigned(updateFiles);
2879
}
2880
 
2881
SSettingType *CSpkFile::AddSetting ( CyString key, int type )
2882
{
2883
	key.RemoveChar ( '|' );
2884
	SSettingType *t;
2885
	for ( t = m_lSettings.First(); t; t = m_lSettings.Next() )
2886
	{
2887
		if ( t->sKey.upper() == key.lower() )
2888
			return NULL;
2889
	}
2890
 
2891
	switch ( type )
2892
	{
2893
		case SETTING_STRING:
2894
			t = new SSettingString;
2895
			break;
2896
		case SETTING_INTEGER:
2897
			t = new SSettingInteger;
2898
			break;
2899
		case SETTING_CHECK:
2900
			t = new SSettingCheck;
2901
			break;
2902
	}
2903
 
2904
	if ( !t )
2905
		return NULL;
2906
 
2907
	t->sKey = key;
2908
	t->iType = type;
2909
 
2910
	m_lSettings.push_back ( t );
2911
	m_bChanged = true;
2912
 
2913
	return t;
2914
}
2915
 
2916
void CSpkFile::ConvertSetting ( SSettingType *t, CyString set )
2917
{
2918
	if ( !t )
2919
		return;
2920
 
2921
	switch ( t->iType )
2922
	{
2923
		case SETTING_STRING:
2924
			((SSettingString *)t)->sValue = set;
2925
			break;
2926
		case SETTING_INTEGER:
2927
			((SSettingInteger *)t)->iValue = set.ToInt();
2928
			break;
2929
		case SETTING_CHECK:
2930
			((SSettingCheck *)t)->bValue = set.ToBool();
2931
			break;
2932
	}
2933
}
2934
CyString CSpkFile::GetSetting ( SSettingType *t )
2935
{
2936
	if ( !t )
2937
		return "";
2938
 
2939
	switch ( t->iType )
2940
	{
2941
		case SETTING_STRING:
2942
			return ((SSettingString *)t)->sValue;
2943
		case SETTING_INTEGER:
2944
			return CyString::Number(((SSettingInteger *)t)->iValue);
2945
		case SETTING_CHECK:
2946
			return (((SSettingInteger *)t)->iValue) ? "1" : "0";
2947
	}
2948
 
2949
	return "";
2950
}
2951
 
2952
void CSpkFile::ClearSettings ()
2953
{
2954
	m_lSettings.clear(true);
2955
	m_bChanged = true;
2956
}
2957
 
2958
 
2959
bool CSpkFile::IsMatchingMod ( CyString mod )
2960
{
2961
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2962
	{
2963
		C_File *file = node->Data();
2964
		if ( file->GetFileType() != FILETYPE_MOD )
2965
			continue;
2966
 
2967
		if ( file->IsFakePatch() )
2968
			continue;
2969
 
2970
		CyString filename = file->GetBaseName();
2971
		if ( filename.lower() == mod.lower() )
2972
			return true;
2973
	}
2974
	return false;
2975
}
2976
 
2977
CyString CSpkFile::GetScriptTypeString(int lang)
2978
{
2979
	int iType = m_iScriptType;
2980
 
2981
	if ( this->IsLibrary() )
2982
		return "Library";
2983
	else if ( this->IsPackageUpdate() )
2984
		return "Package Update";
2985
	else if ( this->IsCustomStart() )
2986
		return "Custom Start";
2987
	else if ( this->IsPatch() )
2988
		return "Patch";
2989
	else if ( m_iScriptType == SCRIPTTYPE_CUSTOM )
2990
	{
2991
		CyString type = this->GetCustomScriptType(lang);
2992
		if ( !type.Empty() )
2993
			return type;
2994
		iType = -1;
2995
	}
2996
 
2997
	if (iType == -1)  // no script type
2998
	{
2999
		if ( this->IsFakePatch() )
3000
			return "Fake Patch";
3001
	}
3002
 
3003
	CyString sType = CSpkFile::GetScriptTypeStringStatic(m_iScriptType);
3004
 
3005
	if ( sType.Empty() )
3006
		return "Other";
3007
 
3008
	return sType;	
3009
}
3010
 
3011
int CSpkFile::ConvertScriptType(CyString sType)
3012
{
3013
	for ( int i = 0; i < SCRIPTTYPE_MAX; i++ )
3014
	{
3015
		if ( sType.Compare(CSpkFile::GetScriptTypeStringStatic(i)) )
3016
			return i;
3017
	}
3018
 
3019
	return -1;
3020
}
3021
 
3022
CyString CSpkFile::GetScriptTypeStringStatic(int type)
3023
{
3024
	switch ( type )
3025
	{
3026
		case SCRIPTTYPE_CUSTOM:
3027
			return "Custom";
3028
		case SCRIPTTYPE_NAVIGATION:
3029
			return "Navigation";
3030
		case SCRIPTTYPE_COMBAT:
3031
			return "Combat";
3032
		case SCRIPTTYPE_MISSION:
3033
			return "Mission";
3034
		case SCRIPTTYPE_ALPLUGIN:
3035
			return "AL Plugin";
3036
		case SCRIPTTYPE_HOTKEY:
3037
			return "Hotkey";
3038
		case SCRIPTTYPE_SHIPUPGRADE:
3039
			return "Ship Upgrade";
3040
		case SCRIPTTYPE_SHIPCOMMAND:
3041
			return "Ship Command";
3042
		case SCRIPTTYPE_STATIONCOMMAND:
3043
			return "Station Command";
3044
		case SCRIPTTYPE_FLEET:
3045
			return "Fleet Management";
3046
		case SCRIPTTYPE_TRADE:
3047
			return "Trade";
3048
		case SCRIPTTYPE_PIRACY:
3049
			return "Piracy";
3050
		case SCRIPTTYPE_CHEAT:
3051
			return "Cheat";
3052
		case SCRIPTTYPE_EXTENSION:
3053
			return "Extension Mods";
3054
		case SCRIPTTYPE_REBALANCE:
3055
			return "Rebalance";
3056
		case SCRIPTTYPE_FIX:
3057
			return "Vanilla Fix";
3058
		case SCRIPTTYPE_GENERALMOD:
3059
			return "General Mod";
3060
		case SCRIPTTYPE_TOTAL:
3061
			return "Totel Conversion";
3062
		case SCRIPTTYPE_WINGCOMMAND:
3063
			return "Wing Command";
3064
	}
3065
 
3066
	return "Other";
3067
}
3068
 
3069
bool CBaseFile::IsPackageNeeded(CyString scriptName, CyString author)
3070
{
3071
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
3072
	{
3073
		SNeededLibrary *l = node->Data();
3074
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
3075
			return true;
3076
	}
3077
 
3078
	return false;
3079
}
3080
 
3081
SNeededLibrary *CBaseFile::FindPackageNeeded(CyString scriptName, CyString author)
3082
{
3083
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
3084
	{
3085
		SNeededLibrary *l = node->Data();
3086
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
3087
			return l;
3088
	}
3089
 
3090
	return NULL;
3091
}
3092
 
3093
void CBaseFile::RemoveFakePatchOrder(CyString scriptName, CyString author)
3094
{
3095
	RemoveFakePatchOrder(true, scriptName, author);
3096
	RemoveFakePatchOrder(false, scriptName, author);
3097
}
3098
void CBaseFile::RemoveFakePatchOrder(bool after, CyString scriptName, CyString author)
3099
{
3100
	CyStringList *list;
3101
	if ( after )
3102
		list = &m_lFakePatchAfter;
3103
	else
3104
		list = &m_lFakePatchBefore;
3105
 
3106
	for ( SStringList *str = list->Head(); str; str = str->next )
3107
	{
3108
		// already added
3109
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
3110
			str->remove = true;
3111
	}
3112
 
3113
	list->RemoveMarked();
3114
}
3115
 
3116
void CBaseFile::AddFakePatchOrder(bool after, CyString scriptName, CyString author)
3117
{
3118
	CyStringList *list;
3119
	if ( after )
3120
		list = &m_lFakePatchAfter;
3121
	else
3122
		list = &m_lFakePatchBefore;
3123
 
3124
	// check if the package already exists
3125
	for ( SStringList *str = list->Head(); str; str = str->next )
3126
	{
3127
		// already added
3128
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
3129
			return;
3130
	}
3131
 
3132
	// cant have it on both list
3133
	RemoveFakePatchOrder(!after, scriptName, author);
3134
 
3135
	list->PushBack(scriptName, author);
3136
}
3137
void CBaseFile::AddNeededLibrary(CyString scriptName, CyString author, CyString minVersion)
3138
{
3139
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
3140
	if ( !l )
3141
	{
3142
		l = new SNeededLibrary;
3143
		l->sName = scriptName;
3144
		l->sAuthor = author;
3145
		m_lNeededLibrarys.push_back(l);
3146
	}
3147
	l->sMinVersion = minVersion;
3148
}
3149
 
3150
void CBaseFile::RemovePackageNeeded(CyString scriptName, CyString author)
3151
{
3152
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
3153
	if ( l )
3154
	{
3155
		m_lNeededLibrarys.remove(l);
3156
		delete l;
3157
	}
3158
}
3159
 
3160
void CBaseFile::ClearNeededPackages()
3161
{
3162
	SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");
3163
	CyString version;
3164
	if ( ns )
3165
		version = ns->sMinVersion;
3166
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
3167
		node->DeleteData();
3168
	m_lNeededLibrarys.clear();
3169
 
3170
	if ( !version.Empty() )
3171
		this->AddNeededLibrary("<package>", "<author>", version);
3172
}
3173
 
3174
bool CSpkFile::LoadPackageData(CyString first, CyString rest)
3175
{
3176
	if ( first.Compare("ScriptType") )
3177
	{
3178
		if ( rest.Compare("Library") || rest.Compare("Library Script") )
3179
			this->SetLibrary();
3180
		else if ( rest.Compare("Update") || rest.Compare("Package Update") || rest.Compare("Mod Update") )
3181
			this->SetPackageUpdate();
3182
		else if ( rest.Compare("Start") || rest.Compare("Custom Start") )
3183
			this->SetCustomStart();
3184
		else if ( rest.Compare("Patch") || rest.Compare("Patch Mod") )
3185
			this->SetPatch();
3186
		else
3187
		{
3188
			int check = rest.ToInt();
3189
			if ( check || rest == "0" )
3190
				m_iScriptType = check;
3191
			else
3192
			{
3193
				m_iScriptType = CSpkFile::ConvertScriptType(rest);
3194
				if ( m_iScriptType == -1 )
3195
					m_sScriptType = rest;
3196
			}
3197
		}
3198
	}
3199
	else if ( first.Compare("AnotherMod") )
3200
	{
3201
		m_sOtherName = rest.GetToken("|", 1, 1);
3202
		m_sOtherAuthor = rest.GetToken("|", 2);
3203
	}
3204
	else if ( first.Compare("WareName") || first.Compare("WareDesc") )
3205
	{
3206
		// find the ware to use
3207
		SWares *useWare = m_pLastWare;
3208
		CyString id = rest.GetToken(" ", 1, 1);
3209
		for ( CListNode<SWares> *wNode = m_lWares.Front(); wNode; wNode = wNode->next() )
3210
		{
3211
			if ( wNode->Data()->sID.Compare(id) )
3212
			{
3213
				useWare = wNode->Data();
3214
				break;
3215
			}
3216
		}
3217
 
3218
		// check if we have the id already
3219
		if ( useWare )
3220
		{
3221
			int lang = rest.GetToken(" ", 2, 2).ToInt();
3222
			SWaresText *wt = NULL;
3223
			for ( CListNode<SWaresText> *tNode = useWare->lText.Front(); tNode; tNode = tNode->next() )
3224
			{
3225
				if ( tNode->Data()->iLang == lang )
3226
				{
3227
					wt = tNode->Data();
3228
					break;
3229
				}
3230
			}
3231
 
3232
			if ( !wt )
3233
			{
3234
				wt = new SWaresText;
3235
				wt->iLang = lang;
3236
				useWare->lText.push_back(wt);
3237
			}
3238
 
3239
			if ( first.Compare("WareName") )
3240
				wt->sName = rest.GetToken(" ", 3);
3241
			else
3242
				wt->sDesc = rest.GetToken(" ", 3);
3243
		}
3244
	}
3245
	else if ( first.Left(4).Compare("Ware") )
3246
	{
3247
		SWares *ware = new SWares;
3248
		ware->iTextID = -1;
3249
		ware->iTextPage = 0;
3250
		ware->cType = first[4];
3251
		ware->iPrice = rest.GetToken ( " ", 2, 2 ).ToLong();
3252
		ware->iSize = rest.GetToken ( " ", 3, 3 ).ToInt();
3253
		ware->iVolumn = rest.GetToken ( " ", 4, 4 ).ToInt();
3254
		ware->sID = rest.GetToken ( " ", 1, 1 );
3255
		ware->iNotority = rest.GetToken ( " ", 5, 5 ).ToInt();
3256
		if ( !rest.GetToken(" ", 6, 6).Empty() )
3257
		{
3258
			ware->iTextID = rest.GetToken ( " ", 6, 6 ).GetToken(",", 2, 2).ToInt();
3259
			ware->iTextPage = rest.GetToken ( " ", 6, 6 ).GetToken(",", 1, 1).ToInt();
3260
		}
3261
		m_lWares.push_back ( ware );
3262
		m_pLastWare = ware;
3263
	}
3264
 
3265
	else if ( CBaseFile::LoadPackageData(first, rest) )
3266
		return true;
3267
	else
3268
		return false;
3269
 
3270
	return true;
3271
}
3272
 
3273
bool CSpkFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
3274
{
3275
	if ( !CBaseFile::GeneratePackagerScript(wildcard, list, datafile) )
3276
		return false;
3277
 
3278
	list->PushBack("# Script Type, the type of package file, some are special types, others are just for show");
3279
	if ( this->IsLibrary() )
3280
		list->PushBack("ScriptType: Library");
3281
	else if ( this->IsPackageUpdate() )
3282
		list->PushBack("ScriptType: Package Update");
3283
	else if ( this->IsCustomStart() )
3284
		list->PushBack("ScriptType: Custom Start");
3285
	else if ( this->IsPatch() )
3286
		list->PushBack("ScriptType: Patch");
3287
	else
3288
		list->PushBack(CyString("ScriptType: ") + this->GetScriptTypeString(44));
3289
	list->PushBack("");
3290
 
3291
	if ( this->IsAnotherMod() )
3292
	{
3293
		list->PushBack("# For another mod/package, this is a child package");
3294
		list->PushBack(CyString("AnotherMod: ") + m_sOtherName + "|" + m_sOtherAuthor);
3295
		list->PushBack("");
3296
	}
3297
 
3298
	if ( !m_lWares.empty() )
3299
	{
3300
		list->PushBack("# Custom Wares, Ware<type>: <id> <price> <size> <volumn> <notority>");
3301
		for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() )
3302
		{
3303
			SWares *w = node->Data();
3304
			if ( w->iTextID > 0 )
3305
				list->PushBack(CyString("Ware") + (char)w->cType + ": " + w->sID + " " + (long)w->iPrice + " " + (long)w->iSize + " " + (long)w->iVolumn + " " + (long)w->iNotority + " " + (long)w->iTextPage + "," + (long)w->iTextID);
3306
			else
3307
				list->PushBack(CyString("Ware") + (char)w->cType + ": " + w->sID + " " + (long)w->iPrice + " " + (long)w->iSize + " " + (long)w->iVolumn + " " + (long)w->iNotority);
3308
			for ( CListNode<SWaresText> *wNode = w->lText.Front(); wNode; wNode = wNode->next() )
3309
			{
3310
				SWaresText *wt = wNode->Data();
3311
				if ( !wt->sName.Empty() )
3312
					list->PushBack(CyString("WareName: ") + w->sID + " " + (long)wt->iLang + " " + wt->sName);
3313
				if ( !wt->sDesc.Empty() )
3314
					list->PushBack(CyString("WareDesc: ") + w->sID + " " + (long)wt->iLang + " " + wt->sDesc);
3315
			}
3316
			list->PushBack("");
3317
		}
3318
	}
3319
 
3320
	if ( !datafile )
3321
	{
3322
		if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list) )
3323
			return false;
3324
	}
3325
 
3326
	return true;
3327
 
3328
}
3329
 
3330
bool CBaseFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
3331
{
3332
	list->PushBack("#");
3333
	list->PushBack(CyString("# Packager Script"));
3334
	list->PushBack(CyString("# -- Generated by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2) + " --");
3335
	list->PushBack("#");
3336
	list->PushBack("");
3337
	if ( !datafile )
3338
	{
3339
		list->PushBack("# Variable for your game directory, where to get files from");
3340
		list->PushBack("# $PATH variable is used to get the current path");
3341
		list->PushBack("Variable: $GAMEDIR $PATH");
3342
		list->PushBack("");
3343
	}
3344
	list->PushBack("# The name of the script");
3345
	list->PushBack(CyString("Name: ") + m_sName);
3346
	list->PushBack("");
3347
	list->PushBack("# The author of the script, ie, you");
3348
	list->PushBack(CyString("Author: ") + m_sAuthor);
3349
	list->PushBack("");
3350
	list->PushBack("# The creation data, when it was created");
3351
	if ( datafile )
3352
		list->PushBack(CyString("Date: ") + m_sCreationDate);
3353
	else
3354
	{
3355
		list->PushBack("# $DATE variable is used to get the current date");
3356
		list->PushBack("Date: $DATE");
3357
	}
3358
	list->PushBack("");
3359
	list->PushBack("# The version of script");
3360
	if ( datafile )
3361
		list->PushBack(CyString("Version: ") + m_sVersion);
3362
	else
3363
	{
3364
		list->PushBack("# $ASK variable is used to get an input when creating");
3365
		list->PushBack("Version: $ASK");
3366
	}
3367
	list->PushBack("");
3368
 
3369
	if ( !m_lGames.empty() ) {
3370
		list->PushBack("# The game version the script is for <game> <version> (can have multiple games)");
3371
		for ( SGameCompat *g = m_lGames.First(); g; g = m_lGames.Next() ) {
3372
			CyString game = CBaseFile::ConvertGameToString(g->iGame);
3373
 
3374
			if ( !g->sVersion.Empty() )
3375
			{
3376
				game += " ";
3377
				game += g->sVersion;
3378
			}
3379
			else
3380
			{
3381
				game += " ";
3382
				game += (long)g->iVersion;
3383
			}
3384
 
3385
			list->PushBack(CyString("Game: ") + game);
3386
		}
3387
 
3388
		list->PushBack("");
3389
	}
3390
 
3391
	if ( !m_sDescription.Empty() )
3392
	{
3393
		list->PushBack("# The description of the script, displays when installing");
3394
		list->PushBack(CyString("Description: ") + m_sDescription);
3395
		list->PushBack("");
3396
	}
3397
 
3398
	if ( !m_sWebSite.Empty() )
3399
	{
3400
		list->PushBack("# A link to the website for the script, ie for an online help page");
3401
		list->PushBack(CyString("WebSite: ") + m_sWebSite);
3402
		list->PushBack("");
3403
	}
3404
 
3405
	if ( !m_sForumLink.Empty() )
3406
	{
3407
		list->PushBack("# A direct link to the thread in the egosoft forum");
3408
		list->PushBack(CyString("ForumLink: ") + m_sForumLink);
3409
		list->PushBack("");
3410
	}
3411
 
3412
	if ( !m_sWebAddress.Empty() )
3413
	{
3414
		list->PushBack("# A link to the address for the update file");
3415
		list->PushBack(CyString("WebAddress: ") + m_sWebAddress);
3416
		list->PushBack("");
3417
	}
3418
 
3419
	if ( !m_sEmail.Empty() )
3420
	{
3421
		list->PushBack("# The email address of the author, to allow users to contract if needed");
3422
		list->PushBack(CyString("Email: ") + m_sEmail);
3423
		list->PushBack("");
3424
	}
3425
 
3426
	if ( m_lMirrors.Count() )
3427
	{
3428
		list->PushBack("# A link to the mirror address for the update file, can have many of these");
3429
		for ( SStringList *node = m_lMirrors.Head(); node; node = node->next )
3430
			list->PushBack(CyString("WebMirror: ") + node->str);
3431
		list->PushBack("");
3432
	}
3433
 
3434
	if ( m_bAutoGenerateUpdateFile )
3435
	{
3436
		list->PushBack("# Auto generate the package update file when created");
3437
		list->PushBack("GenerateUpdateFile");
3438
	}
3439
 
3440
	if ( m_lNeededLibrarys.size() )
3441
	{
3442
		list->PushBack("# Needed Library dependacies, require these to be installed");
3443
		for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
3444
			list->PushBack(CyString("Depend: ") + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);
3445
 
3446
		list->PushBack("");
3447
	}
3448
 
3449
	if ( m_iEaseOfUse != -1 && m_iRecommended != -1 && m_iGameChanging != -1 )
3450
	{
3451
		list->PushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");
3452
		list->PushBack(CyString("Ratings: ") + (long)m_iEaseOfUse + " " + (long)m_iGameChanging + " " + (long)m_iRecommended);
3453
		list->PushBack("");
3454
	}
3455
 
3456
	if ( m_lNames.size() )
3457
	{
3458
		list->PushBack("# Package names, uses different names for different languages");
3459
		for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
3460
			list->PushBack(CyString("ScriptName: ") + (long)node->Data()->iLanguage + " " + node->Data()->sName);
3461
		list->PushBack("");
3462
	}
3463
 
3464
	if ( m_lInstallText.size() )
3465
	{
3466
		list->PushBack("# Install Texts, display text before and/or after installing to inform the use of special conditions");
3467
		for ( CListNode<SInstallText> *node = m_lInstallText.Front(); node; node = node->next() )
3468
		{
3469
			if ( !node->Data()->sBefore.Empty() )
3470
				list->PushBack(CyString("InstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);
3471
			if ( !node->Data()->sAfter.Empty() )
3472
				list->PushBack(CyString("InstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);
3473
		}
3474
		list->PushBack("");
3475
	}
3476
 
3477
	if ( m_lUninstallText.size() )
3478
	{
3479
		list->PushBack("# Uninstall Texts, display text before and/or after uninstalling to inform the use of special conditions");
3480
		for ( CListNode<SInstallText> *node = m_lUninstallText.Front(); node; node = node->next() )
3481
		{
3482
			if ( !node->Data()->sBefore.Empty() )
3483
				list->PushBack(CyString("UninstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);
3484
			if ( !node->Data()->sAfter.Empty() )
3485
				list->PushBack(CyString("UninstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);
3486
		}
3487
		list->PushBack("");
3488
	}
3489
 
3490
	list->PushBack("# Plugin Type, the type the plugin is, mainly used to show users the type, types include: Normal, Stable, Experimental, Cheat, Mod");
3491
	switch ( this->GetPluginType() )
3492
	{
3493
		case PLUGIN_NORMAL:
3494
			list->PushBack("PluginType: Normal");
3495
			break;
3496
		case PLUGIN_STABLE:
3497
			list->PushBack("PluginType: Stable");
3498
			break;
3499
		case PLUGIN_EXPERIMENTAL:
3500
			list->PushBack("PluginType: Experimental");
3501
			break;
3502
		case PLUGIN_CHEAT:
3503
			list->PushBack("PluginType: Cheat");
3504
			break;
3505
		case PLUGIN_MOD:
3506
			list->PushBack("PluginType: Mod");
3507
			break;
3508
	}
3509
	list->PushBack("");
3510
 
3511
	return true;
3512
}
3513
 
3514
bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, CyStringList *list)
3515
{
3516
	// now do files and wildcards
3517
	CyStringList files;
3518
	for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
3519
	{
3520
		CyString name = "$GAMEDIR/";
3521
 
3522
		bool done = false;
3523
		if ( wildcard )
3524
		{
3525
			CyString base = f->Data()->GetBaseName();
3526
			if ( f->Data()->GetFileType() == FILETYPE_SCRIPT )
3527
			{
3528
				if ( base.GetToken(".", 1, 1).Compare("plugin") || base.GetToken(".", 1, 1).Compare("lib") )
3529
				{
3530
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
3531
					done = true;
3532
				}
3533
				else if ( base.GetToken(".", 1, 1).Compare("al") && !base.GetToken(".", 2, 2).Compare("plugin") )
3534
				{
3535
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
3536
					done = true;
3537
				}
3538
			}
3539
			else if ( f->Data()->GetFileType() == FILETYPE_TEXT )
3540
			{
3541
				if ( base.IsIn("-L") )
3542
				{
3543
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken("-L", 1, 1) + "-L*";
3544
					done = true;
3545
				}
3546
				else
3547
				{
3548
					name += f->Data()->GetDirectory(this) + "/*" + base.Right(4) + ".*";
3549
					done = true;
3550
				}
3551
			}
3552
		}
3553
 
3554
		if ( !done )
3555
			name += f->Data()->GetNameDirectory(this);
3556
 
3557
		if ( !f->Data()->GetDir().Empty() )
3558
		{
3559
			name += "|";
3560
			name += f->Data()->GetDir();
3561
		}
3562
		files.PushBack(CyString("GAME ") + CBaseFile::ConvertGameToString(f->Data()->GetGame()) + " " + name, f->Data()->GetFileTypeString(), true);
3563
	}
3564
 
3565
 
3566
	if ( !files.Empty() )
3567
	{
3568
		list->PushBack("# Files List, all the files to add, can include wild cards");
3569
		for ( SStringList *node = files.Head(); node; node = node->next )
3570
			list->PushBack(node->data + ": " + node->str);
3571
		list->PushBack("");
3572
	}
3573
 
3574
	return true;
3575
}
3576
 
3577
CyString CBaseFile::GetAutosaveName()
3578
{
3579
	CyString cdate = m_sCreationDate;
3580
	cdate = cdate.FindReplace("/", ".");
3581
	CyString name = m_sName + "-V" + m_sVersion + "-" + cdate;
3582
 
3583
	return name;
3584
}
3585
 
3586
bool CBaseFile::CheckGameCompatability(int game)
3587
{
3588
	if ( m_lGames.empty() )
3589
		return true; // no game compatability added, assume its ok for all
3590
 
3591
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
3592
		if ( node->Data()->iGame == 0 || node->Data()->iGame == game )
3593
			return true;
3594
	}
3595
	return false;
3596
}
3597
 
3598
bool CBaseFile::CheckGameVersionCompatability(int game, CyString sVersion, int iVersion)
3599
{
3600
	if ( m_lGames.empty() )
3601
		return true; // no game compatability added, assume its ok for all
3602
 
3603
	bool foundAll = false;
3604
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
3605
		if ( node->Data()->iGame == 0 )
3606
			foundAll = true;
3607
		else if ( node->Data()->iGame == game ) { // now check the version
3608
			if ( node->Data()->sVersion.Empty() ) {
3609
				if ( node->Data()->sVersion.CompareVersion(sVersion) == COMPARE_OLDER )
3610
					return false;
3611
				return true;
3612
			}
3613
			else {
3614
				if ( node->Data()->iVersion > iVersion )
3615
					return false;
3616
				return true;
3617
			}
3618
		}
3619
	}
3620
	return foundAll;
3621
}
3622
 
3623
bool CBaseFile::RemoveGameCompatability(int game)
3624
{
3625
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
3626
		if ( node->Data()->iGame == game ) {
3627
			m_lGames.remove(node);
3628
			m_bChanged = true;
3629
			return true;
3630
		}
3631
	}
3632
 
3633
	return false;
3634
}
3635
 
3636
SGameCompat *CBaseFile::GetGameCompatability(int game)
3637
{
3638
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
3639
		if ( node->Data()->iGame == game ) {
3640
			return node->Data();
3641
		}
3642
	}
3643
 
3644
	return NULL;
3645
}
3646
 
3647
void CBaseFile::AddGameCompatability(int game, CyString version)
3648
{
3649
	// first check if we already have it on the list
3650
	SGameCompat *Found = this->GetGameCompatability(game);
3651
	if ( !Found ) {
3652
		Found = new SGameCompat;
3653
		m_lGames.push_back(Found);
3654
	}
3655
 
3656
	Found->iGame = game;
3657
	Found->iVersion = -1;
3658
	Found->sVersion = NullString;
3659
 
3660
	if ( version.IsIn(".") || !version.IsNumber() )
3661
		Found->sVersion = version;
3662
	else
3663
		Found->iVersion = version.ToInt();
3664
	m_bChanged = true;
3665
}
3666
 
3667
bool CBaseFile::LoadPackageData(CyString first, CyString rest)
3668
{
3669
	if ( first.Compare("Name") )
3670
		m_sName = rest;
3671
	else if ( first.Compare("Author") )
3672
		m_sAuthor = rest;
3673
	else if ( first.Compare("ScriptName") )
3674
		AddLanguageName(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
3675
	else if ( first.Compare("UninstallBefore") )
3676
		this->AddUninstallBeforeText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
3677
	else if ( first.Compare("UninstallAfter") )
3678
		this->AddUninstallAfterText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
3679
	else if ( first.Compare("InstallBefore") )
3680
		this->AddInstallBeforeText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
3681
	else if ( first.Compare("InstallAfter") )
3682
		this->AddInstallAfterText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
3683
	else if ( first.Compare("Date") )
3684
		m_sCreationDate = rest;
3685
	else if ( first.Compare("Version") )
3686
		m_sVersion = rest;
3687
	// old version
3688
	else if ( first.Compare("GameVersion") )
3689
		this->AddGameCompatability(-1, rest);
3690
	else if ( first.Compare("PluginType") )
3691
	{
3692
		if ( rest.IsNumber() )
3693
			this->SetPluginType(rest.ToInt());
3694
		else if ( rest.Compare("Normal") )
3695
			this->SetPluginType(PLUGIN_NORMAL);
3696
		else if ( rest.Compare("Stable") )
3697
			this->SetPluginType(PLUGIN_STABLE);
3698
		else if ( rest.Compare("Experimental") )
3699
			this->SetPluginType(PLUGIN_EXPERIMENTAL);
3700
		else if ( rest.Compare("Cheat") )
3701
			this->SetPluginType(PLUGIN_CHEAT);
3702
		else if ( rest.Compare("Mod") )
3703
			this->SetPluginType(PLUGIN_MOD);
3704
	}
3705
	// new version
3706
	else if ( first.Compare("GenerateUpdateFile") )
3707
		m_bAutoGenerateUpdateFile = true;
3708
	else if ( first.Compare("Game") )
3709
	{
3710
		CyString sGame = rest.GetToken(" ", 1, 1);
3711
		this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), rest.GetToken(" ", 2, 2));
3712
	}
3713
	else if ( first.Compare("Description") )
3714
		m_sDescription = rest;
3715
	else if ( first.Compare("AutoSave") || first.Compare("AutoExport") || first.Compare("AutoRarExport") || first.Compare("AutoZipExport") )
3716
	{
3717
		CyString filename = rest;
3718
		CyString name = m_sName;
3719
		CyString author = m_sAuthor;
3720
		CyString cdate = m_sCreationDate;
3721
		cdate = cdate.FindReplace("/", ".").Remove(" ");
3722
		if ( filename.IsIn("$AUTOSAVE") )
3723
		{
3724
			if ( m_iType == TYPE_XSP )
3725
				filename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");
3726
			else
3727
				filename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");
3728
		}
3729
		if ( filename.IsIn("$NAME") )
3730
			filename.FindReplace("$NAME", name.Remove(" "));
3731
		if ( filename.IsIn("$AUTHOR") )
3732
			filename.FindReplace("$AUTHOR", author.Remove(" "));
3733
		if ( filename.IsIn("$DATE") )
3734
			filename.FindReplace("$DATE", cdate);
3735
		if ( filename.IsIn("$CDATE") )
3736
			filename.FindReplace("$CDATE", cdate);
3737
		if ( filename.IsIn("$VERSION") )
3738
			filename.FindReplace("$VERSION", m_sVersion);
3739
 
3740
		if ( first.Compare("AutoZipExport") || first.Compare("AutoExport") )
3741
			m_sExportFilename = CFileIO(filename).ChangeFileExtension("zip");
3742
		else if ( first.Compare("AutoRarExport") )
3743
			m_sExportFilename = CFileIO(filename).ChangeFileExtension("rar");
3744
		else
3745
			m_sFilename = filename;
3746
	}
3747
	else if ( first.Compare("WebSite") )
3748
		m_sWebSite = rest;
3749
	else if ( first.Compare("ForumLink") || first.Compare("Forum") )
3750
		m_sForumLink = rest;
3751
	else if ( first.Compare("Email") )
3752
		m_sEmail = rest;
3753
	else if ( first.Compare("WebAddress") )
3754
		m_sWebAddress = rest;
3755
	else if ( first.Compare("WebMirror") )
3756
		this->AddWebMirror(rest);
3757
	else if ( first.Compare("WebMirror1") )
3758
		this->AddWebMirror(rest);
3759
	else if ( first.Compare("WebMirror2") )
3760
		this->AddWebMirror(rest);
3761
	else if ( first.Compare("Ftp") )
3762
		m_sFtpAddr = rest;
3763
	else if ( first.Compare("Ratings") )
3764
	{
3765
		m_iEaseOfUse = rest.GetToken(" ", 1, 1).ToInt();
3766
		m_iGameChanging = rest.GetToken(" ", 2, 2).ToInt();
3767
		m_iRecommended = rest.GetToken(" ", 3, 3).ToInt();
3768
	}
3769
	else if ( first.Compare("EaseOfUse") )
3770
		m_iEaseOfUse = rest.ToInt();
3771
	else if ( first.Compare("GameChanging") )
3772
		m_iGameChanging = rest.ToInt();
3773
	else if ( first.Compare("Recommended") )
3774
		m_iRecommended = rest.ToInt();
3775
	else if ( first.Compare("Depend") )
3776
	{
3777
		CyString version = rest.GetToken("|", 2, 2);
3778
		CyString name = rest.GetToken("|", 1, 1);
3779
		CyString author = rest.GetToken("|", 3);
3780
 
3781
		this->AddNeededLibrary(name, author, version);
3782
	}
3783
	else if ( first.Compare("DependPackage") )
3784
	{
3785
		CPackages p;
3786
		CBaseFile *spk =  p.OpenPackage(rest, 0, 0, SPKREAD_VALUES);
3787
		if ( spk )
3788
		{
3789
			this->AddNeededLibrary(spk->GetName(), spk->GetAuthor(), spk->GetVersion());
3790
			delete spk;
3791
		}
3792
	}
3793
	else if ( first.Compare("Icon") )
3794
	{
3795
		C_File *icon = new C_File(rest);
3796
		if ( icon->ReadFromFile() )
3797
			this->SetIcon(icon, CFileIO(rest).GetFileExtension());
3798
	}
3799
	else
3800
	{
3801
		CyString checkType = first;
3802
		bool shared = false;
3803
		if ( checkType.Left(6).Compare("Shared") )
3804
		{
3805
			checkType = first.Right(-6);
3806
			shared = true;
3807
		}
3808
 
3809
		// now check type name
3810
		int filetype = GetFileTypeFromString(checkType);
3811
		if ( filetype != -1 )
3812
			this->AddFileScript(filetype, shared, rest);
3813
		else if ( !checkType.Compare("changelog") )
3814
			return false;
3815
	}
3816
 
3817
	return true;
3818
}
3819
 
3820
void CBaseFile::AddFileScript(int filetype, bool shared, CyString rest)
3821
{
3822
	CyString dir;
3823
	if ( rest.IsIn("|") )
3824
	{
3825
		dir = rest.GetToken("|", 2);
3826
		rest = rest.GetToken("|", 1, 1);
3827
	}
3828
 
3829
	int game = 0;
3830
	if ( rest.GetToken(" ", 1, 1).Left(4).Compare("GAME") ) {
3831
		game = CBaseFile::GetGameFromString(rest.GetToken(" ", 2, 2));
3832
		rest = rest.GetToken(" ", 3);
3833
	}
3834
 
3835
	rest = rest.FindReplace("\\", "/");
3836
 
3837
	// wild cards
3838
	if ( rest.IsAnyIn("*?") )
3839
	{
3840
		CDirIO Dir(CFileIO(rest).GetDir());
3841
		CyStringList *dirList = Dir.DirList();
3842
		if ( dirList )
3843
		{
3844
			for ( SStringList *strNode = dirList->Head(); strNode; strNode = strNode->next )
3845
			{
3846
				CyString file = Dir.File(strNode->str);
3847
				if ( file.WildMatch(rest) )
3848
				{
3849
					C_File *newfile = this->AppendFile(file, filetype, game, dir);
3850
					if ( newfile )
3851
						newfile->SetShared(shared);
3852
				}
3853
			}
3854
			delete dirList;
3855
		}
3856
	}
3857
	else
3858
	{
3859
		C_File *file = this->AppendFile(rest, filetype, game, dir);
3860
		if ( file )
3861
			file->SetShared(shared);
3862
	}
3863
}
3864
 
3865
CyString CSpkFile::GetWareText(SWares *w, int lang)
3866
{
3867
	// return the text page if being used
3868
	if ( w->iTextID > 0 && w->iTextPage > 0 )
3869
		return CyString("{") + (long)w->iTextPage + "," + (long)w->iTextID + "}";
3870
 
3871
	CyString name;
3872
	for ( CListNode<SWaresText> *wt = w->lText.Front(); wt; wt = wt->next() )
3873
	{
3874
		if ( wt->Data()->sName.Empty() )
3875
			continue;
3876
		if ( wt->Data()->iLang == lang )
3877
			name = wt->Data()->sName;
3878
		else if ( name.Empty() && wt->Data()->iLang == 44 )
3879
			name = wt->Data()->sName;
3880
		else if ( name.Empty() )
3881
			name = wt->Data()->sName;
3882
	}
3883
 
3884
	return name;
3885
}
3886
CyString CSpkFile::GetWareDesc(SWares *w, int lang)
3887
{
3888
	// return the text page if being used
3889
	if ( w->iTextID > 0 && w->iTextPage > 0 )
3890
		return CyString("{") + (long)w->iTextPage + "," + ((long)w->iTextID + 1) + "}";
3891
 
3892
	CyString name;
3893
	for ( CListNode<SWaresText> *wt = w->lText.Front(); wt; wt = wt->next() )
3894
	{
3895
		if ( wt->Data()->sDesc.Empty() )
3896
			continue;
3897
 
3898
		if ( wt->Data()->iLang == lang )
3899
			name = wt->Data()->sDesc;
3900
		else if ( name.Empty() && wt->Data()->iLang == 44 )
3901
			name = wt->Data()->sDesc;
3902
		else if ( name.Empty() )
3903
			name = wt->Data()->sDesc;
3904
	}
3905
 
3906
	return name;
3907
}
3908
 
3909
CyString CSpkFile::GetCustomStartName()
3910
{
3911
	if ( !this->IsCustomStart() )
3912
		return NullString;
3913
 
3914
	// else find the custom start script
3915
	C_File *file = NULL;
3916
	for ( file = this->GetFirstFile(FILETYPE_SCRIPT); file; file = this->GetNextFile(file) )
3917
	{
3918
		if ( file->GetFilename().IsIn("initplayership")	&& file->GetFilename().GetToken(".", 1, 1).Compare("galaxy") )
3919
			break;
3920
	}
3921
 
3922
	if ( !file )
3923
		return NullString;
3924
 
3925
	return file->GetFilename().GetToken(".", 2, 2);
3926
}
3927
 
3928
CyString CBaseFile::GetFullFileSizeString() { return SPK::GetSizeString ( this->GetFullFileSize() ); }
3929
 
3930
unsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress)
3931
{
3932
	if ( this->WriteFile("temp.dat", progress) )
3933
	{
3934
		FILE *id = fopen("temp.dat", "rb");
3935
		if ( id )
3936
		{
3937
			fseek(id, 0, SEEK_END);
3938
			*size = ftell(id);
3939
			fseek(id, 0, SEEK_SET);
3940
			unsigned char *data = new unsigned char[*size];
3941
			fread(data, sizeof(unsigned char), *size, id);
3942
			fclose(id);
3943
 
3944
			remove("temp.dat");
3945
			return data;
3946
		}
3947
	}
3948
 
3949
	remove("temp.dat");
3950
	return NULL;
3951
}
3952
 
3953
void CSpkFile::MergePackage(CBaseFile *base)
3954
{
3955
	// update version information
3956
	m_sVersion = base->GetVersion();
3957
	m_sCreationDate = base->GetCreationDate();
3958
	m_iPluginType = base->GetPluginType();
3959
 
3960
	// update possible changes
3961
	if ( base->GetType() == TYPE_SPK )
3962
	{
3963
		CSpkFile *spk = (CSpkFile *)base;
3964
		m_bForceProfile = spk->IsForceProfile();
3965
 
3966
		// add any new wares
3967
		if ( spk->AnyWares() )
3968
		{
3969
			for ( CListNode<SWares> *node = spk->GetWaresList()->Front(); node; node = node->next() )
3970
				this->AddWare(node->Data());
3971
			spk->GetWaresList()->clear(); // remove wares so they aren't deleted
3972
		}
3973
 
3974
		// add any settings
3975
		if ( spk->AnySettings() )
3976
		{
3977
			for ( CListNode<SSettingType> *node = spk->GetSettingsList()->Front(); node; node = node->next() )
3978
				this->AddSetting(node->Data()->sKey, node->Data()->iType);
3979
		}
3980
 
3981
		if ( !spk->GetOtherName().Empty() )
3982
		{
3983
			m_sOtherName = spk->GetOtherName();
3984
			m_sOtherAuthor = spk->GetOtherAuthor();
3985
		}
3986
	}
3987
 
3988
	// copy settings from base class
3989
	m_iGameChanging = base->GetGameChanging();
3990
	m_iRecommended = base->GetRecommended();
3991
	m_iEaseOfUse = base->GetEaseOfUse();
3992
 
3993
	for ( CListNode<SGameCompat> *gNode = base->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {
3994
		if ( !gNode->Data()->sVersion.Empty() )
3995
			this->AddGameCompatability(gNode->Data()->iGame, gNode->Data()->sVersion);
3996
		else
3997
			this->AddGameCompatability(gNode->Data()->iGame, CyString::Number(gNode->Data()->iVersion));
3998
	}
3999
 
4000
	if ( !base->GetWebAddress().Empty() )
4001
		m_sWebAddress = base->GetWebAddress();
4002
	if ( !base->GetWebSite().Empty() )
4003
		m_sWebSite = base->GetWebSite();
4004
	if ( !base->GetEmail().Empty() )
4005
		m_sEmail = base->GetEmail();
4006
	if ( !base->GetForumLink().Empty() )
4007
		m_sForumLink = base->GetForumLink();
4008
 
4009
	m_sDescription = base->GetDescription();
4010
 
4011
	// copy over needed librarys
4012
	for ( CListNode<SNeededLibrary> *lNode = base->GetNeededLibraries()->Front(); lNode; lNode = lNode->next() )
4013
		this->AddNeededLibrary(lNode->Data()->sName, lNode->Data()->sAuthor, lNode->Data()->sMinVersion);
4014
 
4015
	// web mirror address, add any new ones
4016
	for ( SStringList *str = base->GetWebMirrors()->Head(); str; str = str->next )
4017
		this->AddWebMirror(str->str);
4018
 
4019
	// copy over any install text
4020
	for ( CListNode<SInstallText> *iNode = base->GetInstallTextList()->Front(); iNode; iNode = iNode->next() )
4021
	{
4022
		if ( !iNode->Data()->sAfter.Empty() )
4023
			this->AddInstallAfterText(iNode->Data()->iLanguage, iNode->Data()->sAfter);
4024
		if ( !iNode->Data()->sBefore.Empty() )
4025
			this->AddInstallBeforeText(iNode->Data()->iLanguage, iNode->Data()->sBefore);
4026
	}
4027
 
4028
	for ( CListNode<SInstallText> *iNode = base->GetUninstallTextList()->Front(); iNode; iNode = iNode->next() )
4029
	{
4030
		if ( !iNode->Data()->sAfter.Empty() )
4031
			this->AddUninstallAfterText(iNode->Data()->iLanguage, iNode->Data()->sAfter);
4032
		if ( !iNode->Data()->sBefore.Empty() )
4033
			this->AddUninstallBeforeText(iNode->Data()->iLanguage, iNode->Data()->sBefore);
4034
	}
4035
 
4036
	// copy over package names
4037
	for ( CListNode<SNames> *nNode = base->GetNamesList()->Front(); nNode; nNode = nNode->next() )
4038
		this->AddLanguageName(nNode->Data()->iLanguage, nNode->Data()->sName);
4039
 
4040
	// finally do all the files
4041
	for ( CListNode<C_File> *node = base->GetFileList()->Front(); node; node = node->next() )
4042
	{
4043
		C_File *f = node->Data();
4044
		// if it exists, remove the old
4045
		for ( CListNode<C_File> *thisNode = m_lFiles.Front(); thisNode; thisNode = thisNode->next() )
4046
		{
4047
			if ( thisNode->Data()->GetFileType() == f->GetFileType() && thisNode->Data()->GetFilename().Compare(f->GetFilename()) && thisNode->Data()->GetDir().Compare(f->GetDir()) )
4048
			{
4049
				m_lFiles.remove(thisNode);
4050
				break;
4051
			}
4052
		}
4053
 
4054
		m_lFiles.push_back(f);
4055
	}
4056
 
4057
	// clear the files so we dont delete them later
4058
	base->GetFileList()->clear();
4059
}
4060
 
4061
void CBaseFile::ConvertNormalMod(C_File *f, CyString to)
4062
{
4063
	C_File *match = this->FindMatchingMod(f);
4064
	if ( match )
4065
	{
4066
		// file link
4067
		if ( !match->GetData() )
4068
			match->ReadFromFile();
4069
		match->ChangeBaseName(to);
4070
	}
4071
 
4072
	// file link
4073
	if ( !f->GetData() )
4074
		f->ReadFromFile();
4075
 
4076
	f->ChangeBaseName(to);
4077
}
4078
 
4079
void CBaseFile::ConvertAutoText(C_File *f)
4080
{
4081
	CyString to;
4082
	if ( f->GetBaseName().IsIn("-L") )
4083
		to = CyString("0000-L") + f->GetBaseName().GetToken("-L", 2, 2);
4084
	else if ( f->GetBaseName().IsIn("-l") )
4085
		to = CyString("0000-L") + f->GetBaseName().GetToken("-l", 2, 2);
4086
	else
4087
		to = f->GetBaseName().Left(-4) + "0000";
4088
 
4089
	// file link
4090
	if ( !f->GetData() )
4091
		f->ReadFromFile();
4092
 
4093
	f->ChangeBaseName(to);
4094
 
4095
}
4096
 
4097
void CBaseFile::ConvertFakePatch(C_File *f)
4098
{
4099
	// find next available fake patch
4100
	int num = 0;
4101
 
4102
	bool found = true;
4103
	while ( found )
4104
	{
4105
		++num;
4106
		found = false;
4107
		CyString find = CyString::Number(num).PadNumber(2);
4108
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
4109
		{
4110
			if ( node->Data()->GetFileType() != FILETYPE_MOD )
4111
				continue;
4112
			if ( !node->Data()->IsFakePatch() )
4113
				continue;
4114
			if ( node->Data()->GetBaseName().Compare(find) )
4115
			{
4116
				found = true;
4117
				break;
4118
			}
4119
		}
4120
	}
4121
 
4122
	CyString to = CyString::Number(num).PadNumber(2);
4123
	C_File *match = this->FindMatchingMod(f);
4124
 
4125
	// file link
4126
	if ( !f->GetData() )
4127
		f->ReadFromFile();
4128
 
4129
	f->ChangeBaseName(to);
4130
	if ( match )
4131
	{
4132
		// file link
4133
		if ( !match->GetData() )
4134
			match->ReadFromFile();
4135
		match->ChangeBaseName(to);
4136
	}
4137
}
4138
 
4139
C_File *CBaseFile::FindMatchingMod(C_File *f)
4140
{
4141
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
4142
	{
4143
		if ( node->Data()->GetFileType() != FILETYPE_MOD )
4144
			continue;
4145
 
4146
		if ( f->GetFileExt().Compare(node->Data()->GetFileExt()) )
4147
			continue;
4148
 
4149
		if ( f->GetBaseName().Compare(node->Data()->GetBaseName()) )
4150
			return node->Data();
4151
	}
4152
 
4153
	return NULL;
4154
}
4155
 
4156
void CBaseFile::RenameFile(C_File *f, CyString baseName)
4157
{
4158
	if ( f->GetFileType() == FILETYPE_MOD )
4159
	{
4160
		C_File *match = this->FindMatchingMod(f);
4161
		if ( match )
4162
			match->ChangeBaseName(baseName);
4163
	}
4164
 
4165
	// need to edit the file
4166
	if ( f->GetFileType() == FILETYPE_SCRIPT || f->GetFileType() == FILETYPE_UNINSTALL )
4167
		f->RenameScript(baseName);
4168
 
4169
	f->ChangeBaseName(baseName);
4170
}
4171
 
4172
CyString CBaseFile::CreateUpdateFile(CyString dir)
4173
{
4174
	CyString file = this->GetNameValidFile() + "_" + m_sAuthor + ".dat";
4175
	file.RemoveChar(' ');
4176
 
4177
	CyStringList write;
4178
	write.PushBack(CyString("Package: ") + m_sName);
4179
	write.PushBack(CyString("Author: ") + m_sAuthor);
4180
	write.PushBack(CyString("Version: ") + m_sVersion);
4181
	write.PushBack(CyString("File: ") + CFileIO(m_sFilename).GetFilename());
4182
 
4183
	CFileIO File(dir + "/" + file);
4184
	if ( File.WriteFile(&write) )
4185
		return File.GetFullFilename();
4186
	return NullString;
4187
}
4188
 
4189
CyString CBaseFile::ErrorString(int error, CyString errorStr)
4190
{
4191
	if ( error == SPKERR_NONE ) return NullString;
4192
 
4193
	CyString err;
4194
 
4195
	switch(error)
4196
	{
4197
		case SPKERR_MALLOC:
4198
			err = "Memory Failed";
4199
			break;
4200
		case SPKERR_FILEOPEN:
4201
			err = "Failed to open file";
4202
			break;
4203
		case SPKERR_FILEREAD:
4204
			err = "Failed to read file";
4205
			break;
4206
		case SPKERR_UNCOMPRESS:
4207
			err = "Failed to Uncompress";
4208
			break;
4209
		case SPKERR_WRITEFILE:
4210
			err = "Failed to write file";
4211
			break;
4212
		case SPKERR_CREATEDIRECTORY:
4213
			err = "Failed to create directory";
4214
			break;
4215
		case SPKERR_FILEMISMATCH:
4216
			err = "File count mismatch";
4217
			break;
4218
	}
4219
 
4220
	if ( !err.Empty() )
4221
	{
4222
		if ( !errorStr.Empty() )
4223
		{
4224
			err += " (";
4225
			err += errorStr + ")";
4226
		}
4227
		return err;
4228
	}
4229
 
4230
	return CyString((long)error);
4231
}
4232
 
4233
bool CBaseFile::SaveToArchive(CyString filename, int game, CProgressInfo *progress)
4234
{
4235
	TCHAR buf[5000];
4236
	wsprintf(buf, L"%hs", filename.c_str());
4237
 
4238
	HZIP hz = CreateZip(buf, 0);
4239
	if ( !hz ) return false;
4240
 
4241
	// read files and compress
4242
	ReadAllFilesToMemory();
4243
	if ( !UncompressAllFiles(progress) )
4244
	{
4245
		CloseZip(hz);
4246
		return false;
4247
	}
4248
 
4249
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
4250
	{
4251
		if ( game != -1 ) {
4252
			if ( game && node->Data()->GetGame() && node->Data()->GetGame() != game )
4253
				continue;
4254
			if ( !game && node->Data()->GetGame() )
4255
				continue;
4256
		}
4257
		CyString fname = node->Data()->GetNameDirectory(this);
4258
		// create the directory
4259
		wsprintf(buf, L"%hs", fname.c_str());
4260
		ZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());
4261
	}
4262
 
4263
	// add the data file
4264
	CyStringList list;
4265
	if ( this->GeneratePackagerScript(false, &list, true) )
4266
	{
4267
		if ( CFileIO("test.tmp").WriteFile(&list) )
4268
		{
4269
			ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");
4270
			CFileIO("test.tmp").Remove();
4271
		}
4272
	}
4273
 
4274
	CloseZip(hz);
4275
 
4276
	return true;
4277
}
4278
 
4279
int CBaseFile::GetGameFromString(CyString sGame)
4280
{
4281
	int iGame = GAME_ALL;
4282
	if ( sGame.Compare("ALL") )
4283
		iGame = GAME_ALL;
4284
	else if ( sGame.Compare("X3") )
4285
		iGame = GAME_X3;
4286
	else if ( sGame.Compare("X2") )
4287
		iGame = GAME_X2;
4288
	else if ( sGame.Compare("X3TC") )
4289
		iGame = GAME_X3TC;
4290
	else if ( sGame.Compare("X3AP") )
4291
		iGame = GAME_X3AP;
4292
	else if ( sGame.Compare("XREBIRTH") )
4293
		iGame = GAME_XREBIRTH;
4294
	else if ( sGame.IsNumber() )
4295
		iGame = sGame.ToInt();
4296
 
4297
	return iGame;
4298
}
4299
 
4300
CyString CBaseFile::ConvertGameToString(int iGame)
4301
{
4302
	CyString game = "ALL";
4303
 
4304
	switch(iGame) {
4305
		case GAME_ALL:
4306
			game = "ALL";
4307
			break;
4308
		case GAME_X2:
4309
			game = "X2";
4310
			break;
4311
		case GAME_X3:
4312
			game = "X3";
4313
			break;
4314
		case GAME_X3TC:
4315
			game = "X3TC";
4316
			break;
4317
		case GAME_X3AP:
4318
			game = "X3AP";
4319
			break;
4320
		case GAME_XREBIRTH:
4321
			game = "XREBIRTH";
4322
			break;
4323
		default:
4324
			game = (long)iGame;
4325
	}
4326
 
4327
	return game;
4328
}
4329
 
4330
bool CBaseFile::IsGameInPackage(int game)
4331
{
4332
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
4333
		if ( node->Data()->GetGame() == game )
4334
			return true;
4335
	}
4336
 
4337
	return false;
4338
}
4339
 
4340
bool CBaseFile::IsAnyGameInPackage()
4341
{
4342
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
4343
		if ( node->Data()->GetGame() )
4344
			return true;
4345
	}
4346
 
4347
	return false;
4348
}
4349
 
4350
int CBaseFile::FindFirstGameInPackage()
4351
{
4352
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
4353
		if ( node->Data()->GetGame() )
4354
			return node->Data()->GetGame();
4355
	}
4356
 
4357
	return 0;
4358
}
4359
bool CBaseFile::IsMultipleGamesInPackage()
4360
{
4361
	int game = 0;
4362
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
4363
		if ( node->Data()->GetGame() ) {
4364
			if ( game != node->Data()->GetGame() )
4365
				return true;
4366
			game = node->Data()->GetGame();
4367
		}
4368
	}
4369
 
4370
	return false;
4371
}