Subversion Repositories spk

Rev

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