Subversion Repositories spk

Rev

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

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