Subversion Repositories spk

Rev

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

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