Subversion Repositories spk

Rev

Rev 14 | Details | Compare with Previous | Last modification | View Log | RSS feed

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