Subversion Repositories spk

Rev

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