Subversion Repositories spk

Rev

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

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