Subversion Repositories spk

Rev

Rev 121 | Rev 125 | 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
 
1018
			if ( !m_bOverrideFiles && !cFile->CompareNew(pFile) ) {
1019
				if ( errorStr ) errorStr->PushBack(pFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_SKIPFILE));
1020
				CLog::log(CLog::Log_Install, 1, "Newer version of the file already installed, skipping");
1021
				*bDoFile = false;
1022
			}
1023
			break;
1024
		}
1025
 
1026
		return cFile;
1027
	}
1028
 
1029
	return NULL;
1030
}
1031
 
1032
bool CBaseFile::_install_checkFileEnable(C_File *pCheckFile, C_File *fit, const Utils::String &sDestination, bool bEnabled, CyStringList *errorStr)
1033
{
1034
	// found a file, check if its in the disabled directory
1035
	CyString dir = pCheckFile->GetFilePointer();
1036
	dir = dir.GetToken ( 1, dir.NumToken ('/') - 1, '/' );
1037
	CyString lastDir = dir.GetToken ( dir.NumToken('/'), '/' ).ToLower();
1038
 
1039
	// if its disabled, rename it so its enabled
1040
	if ( ((pCheckFile->IsDisabled()) || (lastDir == "disabled") || (dir.ToLower().IsIn ("/disabled/"))) && (bEnabled) )
1041
	{
1042
		CLog::logf(CLog::Log_Install, 2, "Existing file, %s, is disabled, re-enabling it", pCheckFile->GetFilePointer().c_str());
1043
		// first check if the directory exists
1044
		if ( pCheckFile->IsInMod() ) {
1045
			CyString tofile = pCheckFile->GetFilePointer().GetToken("::", 2, 2);
1046
 
1047
			CCatFile tocat;
1048
			int err = tocat.Open ( fit->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, true );
1049
			if ( (err == CATERR_NONE) || (err == CATERR_CREATED) ) {
52 cycrow 1050
				tocat.AppendFile(pCheckFile->GetFilePointer().ToString(), tofile.ToString());
50 cycrow 1051
				CLog::logf(CLog::Log_Install, 2, "Adding existing file into new mod File, %s => %s", fit->GetFilePointer().GetToken("::", 1, 1).c_str(), tofile.c_str());
1052
			}
1053
 
1054
			CCatFile fromcat;
1055
			err = fromcat.Open ( pCheckFile->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, false );
1056
			if ( err == CATERR_NONE ) {
124 cycrow 1057
				fromcat.removeFile(tofile.ToString());
50 cycrow 1058
				CLog::logf(CLog::Log_Install, 2, "Removing file from existing mod, %s::%s", pCheckFile->GetFilePointer().GetToken("::", 1, 1).c_str(), tofile.c_str());
1059
			}
1060
 
1061
			CLog::logf(CLog::Log_Install, 1, "Adjusting existing file name %s => %s", pCheckFile->GetFilePointer().c_str(), fit->GetFilePointer().c_str());
1062
			pCheckFile->SetFilename ( fit->GetFilePointer() );
1063
			CLog::logf(CLog::Log_Install, 2, "Adjusting In Mod setting, %s => %s", pCheckFile->GetInMod().c_str(), fit->GetInMod().c_str());
1064
			pCheckFile->SetInMod(fit->GetInMod());
1065
		}
1066
		else {
1067
			CyString to = pCheckFile->GetDirectory(this);
1068
			CDirIO Dir(sDestination);
121 cycrow 1069
			if ( !Dir.exists(to.ToString()) ) {
50 cycrow 1070
				if ( !Dir.Create ( to ) ) {
1071
					if ( errorStr )	errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1072
					return false;
1073
				}
1074
				if ( errorStr )	errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1075
			}
1076
 
1077
			CyString destfile = CyString(sDestination) + "/" + pCheckFile->GetNameDirectory(this);
52 cycrow 1078
			if ( CFileIO(destfile).ExistsOld() ) CFileIO::Remove(destfile.ToString());
50 cycrow 1079
			CLog::logf(CLog::Log_Install, 1, "Adjusting existing filename, %s => %s", pCheckFile->GetFilePointer().c_str(), destfile.c_str());
1080
			rename ( pCheckFile->GetFilePointer().c_str(), destfile.c_str() );
1081
			pCheckFile->SetFilename ( CyString(sDestination) + "/" + pCheckFile->GetNameDirectory(this) );
1082
		}
1083
		pCheckFile->SetDisabled(false);
1084
 
1085
		if ( errorStr ) errorStr->PushBack(pCheckFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));
1086
	}
1087
 
1088
	return true;
1089
}
51 cycrow 1090
 
1091
bool CBaseFile::_install_createDirectory(CDirIO &Dir, const Utils::String &sTo, C_File *pFile, CyStringList *errorStr)
1092
{
1093
	m_sLastError = sTo;
1094
	if ( !sTo.isin ( "::" ) )
1095
	{
121 cycrow 1096
		if ( !Dir.exists(sTo) )
51 cycrow 1097
		{
1098
			CLog::logf(CLog::Log_Install, 2, "Creating directory to install file into, %s", sTo.c_str());
1099
			if ( !Dir.Create(sTo) )
1100
			{
1101
				if ( errorStr )
1102
					errorStr->PushBack(CyString(sTo), ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
1103
				return false;
1104
			}
1105
			if ( errorStr )
1106
				errorStr->PushBack(CyString(sTo), ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
1107
		}
1108
	}
1109
	else {
124 cycrow 1110
		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());
1111
		pFile->SetFilename(CCatFile::PckChangeExtension(pFile->GetFilePointer().ToString()));
51 cycrow 1112
	}
1113
 
1114
	return true;
1115
}
1116
 
1117
void CBaseFile::_install_writeFile(C_File *pFile, const Utils::String &sDestination, CyStringList *errorStr)
1118
{
1119
	m_iLastError = SPKERR_WRITEFILE;
1120
	m_sLastError = pFile->GetFilePointer();
1121
	CyString sInstalledFile = pFile->GetNameDirectory(this);
1122
	if ( pFile->IsDisabled() )
1123
	{
1124
		sInstalledFile = pFile->GetFilePointer().Remove(sDestination);
1125
		if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )
1126
			sInstalledFile.Erase(0, 1);
1127
	}
1128
 
1129
	if ( !pFile->WriteFilePointer() )
1130
	{
1131
		CLog::log(CLog::Log_Install, 1, "Failed to write the file");
1132
		if ( errorStr )
1133
			errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));
1134
	}
1135
	else
1136
	{
1137
		CLog::log(CLog::Log_Install, 1, "File written successfully");
1138
		CLog::log(CLog::Log_Install, 2, "Checking signed status of the file");
1139
		pFile->UpdateSigned();
1140
		if ( errorStr )
1141
			errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));
1142
 
1143
		switch(pFile->GetFileType())
1144
		{
1145
			case FILETYPE_SCRIPT:
1146
			case FILETYPE_UNINSTALL:
1147
				CLog::log(CLog::Log_Install, 2, "Updating file signature");
1148
				pFile->UpdateSignature();
1149
				break;
1150
		}
1151
	}
1152
}
1153
 
43 cycrow 1154
bool CBaseFile::InstallFiles ( CyString destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, CyStringList *errorStr, bool enabled, CPackages *packages )
1155
{
50 cycrow 1156
	//TODO: add errorStr and progress as member variables
43 cycrow 1157
	if ( enabled ) {
14 cycrow 1158
		this->_install_adjustFakePatches(packages);
43 cycrow 1159
		if ( packages ) this->_install_renameText(packages);
6 cycrow 1160
	}
1161
 
50 cycrow 1162
	bool bFailed = false;
1163
 
6 cycrow 1164
	CDirIO Dir(destdir);
1165
	int fileCount = 0;
1166
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
1167
	{
1168
		C_File *fit = node->Data();
1169
 
50 cycrow 1170
		// start the install process, check if we need to the file enabled or disabled
1171
		CLog::logf(CLog::Log_Install, 1, "Preparing to install file: %s", fit->GetNameDirectory(this).c_str());
1172
		bool fileEnabled = _install_setEnabled(enabled, fit);
1173
 
1174
		// check if the file is for the correct game version
6 cycrow 1175
		if ( fit->GetGame() && packages->GetGame() ) {
50 cycrow 1176
			if ( fit->GetGame() != packages->GetGame() ) {
1177
				CLog::logf(CLog::Log_Install, 1, "File didn't match game version, skipping, %d != %d", fit->GetGame(), packages->GetGame());
6 cycrow 1178
				continue;
50 cycrow 1179
			}
6 cycrow 1180
		}
1181
 
50 cycrow 1182
		// update the progress display to show we are processing this file
1183
		if ( progress ) {
1184
			if ( progress->IsSecond() ) progress->SwitchSecond();
6 cycrow 1185
			progress->UpdateFile ( fit );
1186
			progress->UpdateProgress(fileCount++, m_lFiles.size());
1187
			progress->SwitchSecond();
1188
		}
1189
 
1190
		// first uncompress the file
50 cycrow 1191
		//TODO: add this flag to C_File
1192
		bool uncomprToFile;
1193
		if ( !this->_install_uncompress(fit, progress, errorStr, &uncomprToFile) ) {
1194
			bFailed = true;
1195
			continue;
6 cycrow 1196
		}
1197
 
50 cycrow 1198
		bool dofile = _install_checkVersion(fit, destdir.ToString());
6 cycrow 1199
 
1200
		// change file pointer
50 cycrow 1201
		Utils::String sFilename = _install_adjustFilepointer(fit, fileEnabled, destdir.ToString());
6 cycrow 1202
 
1203
		C_File *adjustPointer = NULL;
1204
 
50 cycrow 1205
		if ( filelist ) {
98 cycrow 1206
			C_File *cFile = _install_checkFile(fit, errorStr, &dofile, filelist);
6 cycrow 1207
 
1208
			// no matching file found, adding to main list
50 cycrow 1209
			if ( !cFile ) filelist->push_back ( fit );
6 cycrow 1210
			else
1211
			{
1212
				// if the file is not enabled, we need to check for any that might be enabled
51 cycrow 1213
				if ( !fileEnabled ) //_install_checkDisabled(cFile, destdir, errorStr);
6 cycrow 1214
				{
50 cycrow 1215
					//TODO: check what this is actually doing
6 cycrow 1216
					if ( !cFile->GetUsed() )
1217
					{
1218
						CFileIO rFile(cFile->GetFilePointer());
52 cycrow 1219
						if ( rFile.exists() )
6 cycrow 1220
						{
1221
							if ( errorStr )
1222
							{
52 cycrow 1223
								if ( rFile.remove() )
6 cycrow 1224
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));
1225
								else
1226
									errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));
1227
							}
1228
						}
1229
						cFile->SetFilename(fit->GetFilePointer());
1230
						cFile->SetDisabled(true);
1231
					}
1232
					else
1233
					{
51 cycrow 1234
						fit->SetFullDir ( CyString(sFilename) + fit->GetDirectory(this) );
1235
						fit->SetDisabled(false);
6 cycrow 1236
					}
1237
				}
1238
				// move it to enabled
50 cycrow 1239
				else {
1240
					if ( !this->_install_checkFileEnable(cFile, fit, destdir.ToString(), fileEnabled, errorStr) ) {
1241
						bFailed = true;
1242
						continue;
6 cycrow 1243
					}
1244
				}
1245
 
1246
				adjustPointer = cFile;
50 cycrow 1247
				if ( dofile ) adjustPointer->SetCreationTime(fit->GetCreationTime());
6 cycrow 1248
			}
1249
		}
1250
 
1251
		if ( dofile )
1252
		{
1253
			// uncompressed to file, rename and move
1254
			if ( uncomprToFile )
1255
			{
1256
				m_iLastError = SPKERR_WRITEFILE;
1257
				CyString to = fit->GetDirectory(this);
51 cycrow 1258
				if ( !fileEnabled )	to = CyString("PluginManager/Disabled/") + to;
6 cycrow 1259
 
51 cycrow 1260
				if ( !_install_createDirectory(Dir, to.ToString(), fit, errorStr) ) {
1261
					bFailed = true;
1262
					continue;
6 cycrow 1263
				}
1264
 
1265
				int err = 1;
1266
				m_sLastError = to;
51 cycrow 1267
				if ( !fit->GetTempFile ().Empty() )	err = rename ( fit->GetTempFile().c_str(), to.c_str() );
1268
				if ( err ) {
1269
					bFailed = true;
1270
					continue;
1271
				}
6 cycrow 1272
			}
1273
			//otherwise, just extract the file
1274
			else
1275
			{
1276
				// old file is found in list, switch to using new one
50 cycrow 1277
				if ( (filelist) && (adjustPointer) ) {
6 cycrow 1278
					adjustPointer->CopyData(fit, false);
50 cycrow 1279
					CLog::log(CLog::Log_Install, 2, "Copying data into existing file");
1280
				}
6 cycrow 1281
 
1282
				CyString fpointer = fit->GetFilePointer();
1283
				m_iLastError = SPKERR_CREATEDIRECTORY;
1284
				CyString dir = fit->GetFilePointer().GetToken ( "/", 1, fit->GetFilePointer().NumToken("/") - 1 );
1285
 
1286
				dir = dir.Remove(destdir);
51 cycrow 1287
				if ( dir[0] == '/' || dir[0] == '\\' ) dir.Erase(0, 1);
6 cycrow 1288
 
51 cycrow 1289
				if ( !_install_createDirectory(Dir, dir.ToString(), fit, errorStr) ) {
1290
					bFailed = true;
1291
					continue;
6 cycrow 1292
				}
1293
 
51 cycrow 1294
				_install_writeFile(fit, destdir.ToString(), errorStr);
6 cycrow 1295
			}
1296
			ClearError ();
1297
		}
1298
 
1299
		if ( adjustPointer )
1300
		{
50 cycrow 1301
			CLog::log(CLog::Log_Install, 2, "Adjusting pointers to existing file and deleting new file pointer");
6 cycrow 1302
			node->ChangeData(adjustPointer);
1303
			delete fit;
1304
		}
50 cycrow 1305
 
1306
		CLog::log(CLog::Log_Install, 1, "File installation completed");
6 cycrow 1307
	}
1308
 
1309
	// now clear or data memory
50 cycrow 1310
	CLog::log(CLog::Log_Install, 2, "Delting temporary file data from memory");
51 cycrow 1311
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) node->Data()->DeleteData();
6 cycrow 1312
 
50 cycrow 1313
	return !bFailed;
6 cycrow 1314
}
1315
 
1316
/*######################################################################################################*/
1317
 
1318
 
1319
/*
1320
	Func:   ParseHeader
1321
	Input:  Header String - string formated directly from the file
1322
	Return: Boolean - If string is a valid header
1323
	Desc:   Splits up the main header string to get all required settings
1324
*/
1325
bool CBaseFile::ParseHeader ( CyString header )
1326
{
14 cycrow 1327
	if ( !this->CheckHeader(header.GetToken ( 1, ';' ).ToString()) )
6 cycrow 1328
		return false;
1329
 
1330
	m_SHeader.fVersion = header.GetToken ( 2, ';' ).ToFloat();
1331
	if ( m_SHeader.fVersion > FILEVERSION )
1332
		return false;
1333
 
1334
	m_SHeader.iValueCompression = header.GetToken ( 3, ';' ).ToInt();
1335
	m_SHeader.lValueCompressSize = header.GetToken ( 4, ';' ).ToLong();
1336
 
1337
	return true;
1338
}
1339
 
14 cycrow 1340
bool CBaseFile::CheckHeader(const Utils::String header) const
6 cycrow 1341
{
1342
	if ( header.Compare("BaseCycrow") )
1343
		return true;
1344
	return false;
1345
}
1346
 
1347
/*
1348
	Func:   ParseFileHeader
1349
	Input:  Header String - string formated directly from the file
1350
	Return: Boolean - If string is a valid header
1351
	Desc:   Splits up the file header string to get all required settings
1352
*/
1353
bool CBaseFile::ParseFileHeader ( CyString header )
1354
{
1355
	if ( header.GetToken ( 1, ';' ) != "FileHeader" )
1356
		return false;
1357
 
1358
	m_SHeader2.iNumFiles = header.GetToken ( 2, ';' ).ToInt();
1359
	m_SHeader2.lSize = header.GetToken ( 3, ';' ).ToInt();
1360
	m_SHeader2.lFullSize = header.GetToken ( 4, ';' ).ToInt();
1361
	m_SHeader2.iFileCompression = header.GetToken ( 5, ';' ).ToInt();
1362
	m_SHeader2.iDataCompression = header.GetToken ( 6, ';' ).ToInt();
1363
 
1364
	return true;
1365
}
1366
 
1367
 
1368
/*
1369
	Func:   ParseValueLine
1370
	Input:  String - single line from a file to set
1371
	Return: Boolean - returns true if value exists
1372
	Desc:   Reads the line and assigns the parameters for the file
1373
*/
14 cycrow 1374
bool CBaseFile::ParseValueLine(const Utils::String &sLine)
6 cycrow 1375
{
14 cycrow 1376
	Utils::String first = sLine.token(" ", 1);
1377
	Utils::String rest  = sLine.tokens(" ", 2);
6 cycrow 1378
 
50 cycrow 1379
	if ( first.Compare("Name:") )					this->setName(rest);
1380
	else if ( first.Compare("Author:") )			this->setAuthor(rest);
1381
	else if ( first.Compare("Version:") )			this->setVersion(rest);
14 cycrow 1382
	else if ( first.Compare("fGameVersion:") ) {
6 cycrow 1383
		if ( m_lGames.Back() ) {
1384
			m_lGames.Back()->Data()->sVersion = rest;
1385
		}
1386
	}
14 cycrow 1387
	else if ( first.Compare("GameVersion:") ) {
6 cycrow 1388
		if ( m_lGames.Back() ) {
14 cycrow 1389
			m_lGames.Back()->Data()->iVersion = rest;
6 cycrow 1390
		}
1391
	}
14 cycrow 1392
	else if ( first.Compare("Game:") )
46 cycrow 1393
		this->AddGameCompatability(rest, "");
14 cycrow 1394
	else if ( first.Compare("GameCompat:") )
1395
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
1396
	else if ( first.Compare("GameCompatExact:") )
1397
		this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));
50 cycrow 1398
	else if ( first.Compare("Date:") )				this->setCreationDate(rest);
49 cycrow 1399
	else if ( first.Compare("WebAddress:") )		this->setWebAddress(rest);
1400
	else if ( first.Compare("WebSite:") )			this->setWebSite(rest);
1401
	else if ( first.Compare("Email:") )				this->setEmail(rest);
14 cycrow 1402
	else if ( first.Compare("WebMirror1:") || first.Compare("Mirror1:") || first.Compare("WebMirror:") )
6 cycrow 1403
		this->AddWebMirror(rest);
14 cycrow 1404
	else if ( first.Compare("WebMirror2:") || first.Compare("Mirror2:") )
6 cycrow 1405
		this->AddWebMirror(rest);
48 cycrow 1406
	else if ( first.Compare("PluginType:") )		this->setPluginType(rest);
1407
	else if ( first.Compare("Desc:") )				this->setDescription(rest);
1408
	else if ( first.Compare("UninstallAfter:") )	this->addUninstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));
1409
	else if ( first.Compare("UninstallBefore:") )	this->addUninstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));
1410
	else if ( first.Compare("InstallAfter:") )		this->addInstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));
1411
	else if ( first.Compare("InstallBefore:") )		this->addInstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));
14 cycrow 1412
	else if ( first.Compare("ScriptName:") )
1413
		AddLanguageName(ParseLanguage(rest.token(":", 1)), rest.token(":", 2));
48 cycrow 1414
	else if ( first.Compare("GameChanging:") )		this->setGameChanging(rest);
1415
	else if ( first.Compare("EaseOfUse:") )			this->setEaseOfUse(rest);
1416
	else if ( first.Compare("Recommended:") )		this->setRecommended(rest);
14 cycrow 1417
	else if ( first.Compare("NeededLibrary:") )
1418
		this->AddNeededLibrary(rest.token("||", 1), rest.token("||", 2), rest.token("||", 3));
1419
	else if ( first.Compare("FakePatchBefore:") )
1420
		this->AddFakePatchOrder(false, rest.token("||", 1), rest.token("||", 2));
1421
	else if ( first.Compare("FakePatchAfter:") )
1422
		this->AddFakePatchOrder(true, rest.token("||", 1), rest.token("||", 2));
49 cycrow 1423
	else if ( first.Compare("ForumLink:") )			this->setForumLink(rest);
6 cycrow 1424
	else
1425
		return false;
1426
 
1427
	return true;
1428
}
1429
 
48 cycrow 1430
int CBaseFile::ParseLanguage(const Utils::String &lang) const
6 cycrow 1431
{
48 cycrow 1432
	int langID = lang;
1433
	if ( !langID ) {
1434
		if ( lang.Compare("english") )		return 44;
1435
		else if ( lang.Compare("default") )	return 0;
1436
		else if ( lang.Compare("german") )	return 49;
1437
		else if ( lang.Compare("russian") )	return 7;
1438
		else if ( lang.Compare("spanish") )	return 34;
1439
		else if ( lang.Compare("french") )	return 33;
6 cycrow 1440
	}
1441
 
1442
	return langID;
1443
}
1444
 
1445
/*
1446
	Func:   ReadValues
1447
	Input:  String - values in one long line
1448
	Desc:   splits the values data into each line to read the data
1449
*/
1450
void CBaseFile::ReadValues ( CyString values )
1451
{
1452
	int num = 0;
1453
	CyString *lines = values.SplitToken ( '\n', &num );
1454
 
1455
	for ( int i = 0; i < num; i++ )
14 cycrow 1456
		ParseValueLine ( lines[i].ToString() );
6 cycrow 1457
 
1458
	CLEANSPLIT(lines, num)
1459
}
1460
 
1461
/*
1462
	Func:   ParseFilesLine
1463
	Input:  String - single line from a file to set
1464
	Return: Boolean - returns true if value exists
1465
	Desc:   Reads the line and assigns the parameters for the file
1466
*/
1467
bool CBaseFile::ParseFilesLine ( CyString line )
1468
{
1469
	if ( !line.IsIn(":") )
1470
		return false;
1471
 
1472
	CyString command = line.GetToken ( 1, ':' );
1473
 
1474
	long size = line.GetToken ( 2, ':').ToInt ();
1475
	long usize = line.GetToken ( 3, ':').ToInt ();
1476
	long compression = line.GetToken ( 4, ':').ToInt ();
1477
 
1478
	if ( command == "Icon" )
1479
	{
1480
		m_sIconExt = line.GetToken ( 5, ':' );
1481
		m_pIconFile = new C_File ();
1482
		m_pIconFile->SetDataSize ( size - 4 );
1483
		m_pIconFile->SetDataCompression ( compression );
1484
		m_pIconFile->SetUncompressedDataSize ( usize );
1485
 
1486
		return true;
1487
	}
1488
 
1489
	time_t time = line.GetToken ( 5,':' ).ToLong();
1490
	bool compressToFile = (line.GetToken ( 6, ':').ToInt() == 1) ? true : false;
1491
	CyString name  = line.GetToken ( 7, ':' );
1492
	CyString dir = line.GetToken ( 8, ':' );
1493
 
1494
	if ( name.Empty() )
1495
		return true;
1496
 
1497
	bool shared = false;
1498
	if ( command.Left(1) == "$" )
1499
	{
1500
		shared = true;
1501
		command.Erase ( 0, 1 );
1502
	}
1503
 
1504
	int type = -1;
1505
	if ( command == "Script" )
1506
		type = FILETYPE_SCRIPT;
1507
	else if ( command == "Text" )
1508
		type = FILETYPE_TEXT;
1509
	else if ( command == "Readme" )
1510
		type = FILETYPE_README;
1511
	else if ( command == "Map" )
1512
		type = FILETYPE_MAP;
1513
	else if ( command == "Mod" )
1514
		type = FILETYPE_MOD;
1515
	else if ( command == "Uninstall" )
1516
		type = FILETYPE_UNINSTALL;
1517
	else if ( command == "Sound" )
1518
		type = FILETYPE_SOUND;
1519
	else if ( command == "Mission" )
1520
		type = FILETYPE_MISSION;
1521
	else if ( command == "Extra" )
1522
		type = FILETYPE_EXTRA;
1523
	else if ( command == "Screen" )
1524
		type = FILETYPE_SCREEN;
1525
	else if ( command == "Backup" )
1526
		type = FILETYPE_BACKUP;
1527
	else if ( command == "Advert" )
1528
		type = FILETYPE_ADVERT;
1529
	else if ( command == "ShipScene" )
1530
		type = FILETYPE_SHIPSCENE;
1531
	else if ( command == "CockpitScene" )
1532
		type = FILETYPE_COCKPITSCENE;
1533
	else if ( command == "ShipOther" )
1534
		type = FILETYPE_SHIPOTHER;
1535
	else if ( command == "ShipModel" )
1536
		type = FILETYPE_SHIPMODEL;
1537
 
1538
	if ( type == -1 )
1539
		return false;
1540
 
1541
	C_File *file = new C_File ();
1542
 
1543
	if ( dir.Left(5).Compare("GAME_") ) {
1544
		file->SetGame(dir.GetToken("_", 2, 2).ToInt());
1545
		dir = NullString;
1546
	} 
1547
	else if ( line.NumToken(":") >= 9 ) {
1548
		file->SetGame(line.GetToken(":", 9, 9).GetToken("_", 2, 2).ToInt());
1549
	}
1550
 
1551
	file->SetFileType ( type );
1552
	file->SetCreationTime ( time );
1553
	file->SetName ( name );
1554
	file->SetDir ( dir );
1555
	file->SetDataSize ( size - 4 );
1556
	file->SetDataCompression ( compression );
1557
	file->SetUncompressedDataSize ( usize );
1558
	file->SetShared ( shared );
1559
	file->SetCompressedToFile ( compressToFile );
1560
 
88 cycrow 1561
	_addFile(file, true);
6 cycrow 1562
 
1563
	return true;
1564
}
1565
 
1566
 
1567
/*
1568
	Func:   ParseFiles
1569
	Input:  String - values in one long line
1570
	Desc:   splits the files data into each line to read the data
1571
*/
1572
void CBaseFile::ReadFiles ( CyString values )
1573
{
1574
	int num = 0;
1575
	CyString *lines = values.SplitToken ( '\n', &num );
1576
 
1577
	for ( int i = 0; i < num; i++ )
1578
		ParseFilesLine ( lines[i] );
1579
 
1580
	CLEANSPLIT(lines, num)
1581
}
1582
 
1583
 
1584
 
1585
/*
1586
	Func:   ReadFile
1587
	Input:  filename - the name of the file to open and read
1588
			readdata - If falses, dont read the files to memory, just read the headers and values
1589
	Return: boolean - return ture if acceptable format
1590
	Desc:   Opens and reads the spk file and loads all data into class
1591
*/
1592
bool CBaseFile::ReadFile ( CyString filename, int readtype, CProgressInfo *progress )
1593
{
58 cycrow 1594
	CFileIO File(filename.ToString());
1595
	if ( !File.startRead() ) return false;
6 cycrow 1596
 
58 cycrow 1597
	bool ret = this->readFile(File, readtype, progress);
50 cycrow 1598
	if ( ret ) this->setFilename(filename.ToString());
6 cycrow 1599
 
58 cycrow 1600
	File.close();
6 cycrow 1601
	return ret;
1602
}
51 cycrow 1603
 
109 cycrow 1604
int CBaseFile::_read_Header(CFileIO &File, int iReadType, int iMaxProgress, CProgressInfo *pProgress)
6 cycrow 1605
{
51 cycrow 1606
	int doneLen = 0;
6 cycrow 1607
 
51 cycrow 1608
	// read data to memory
1609
	unsigned char *readData;
1610
	try {
1611
		readData = new unsigned char[m_SHeader.lValueCompressSize];
1612
	}
1613
	catch (std::exception &e) {
1614
		CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [header], %d (%s)", m_SHeader.lValueCompressSize, e.what());
1615
		return -1;
1616
	}
6 cycrow 1617
 
51 cycrow 1618
	unsigned char size[4];
109 cycrow 1619
	File.read(size, 4);
1620
	File.read(readData, m_SHeader.lValueCompressSize);
6 cycrow 1621
 
51 cycrow 1622
	unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
6 cycrow 1623
 
51 cycrow 1624
	// check for zlib compression
1625
	if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ) {
1626
		// uncomress the data
1627
		try {
6 cycrow 1628
			unsigned char *uncompr = new unsigned char[uncomprLen];
1629
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );
1630
			// update the progress for each section
51 cycrow 1631
			if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);
1632
			if ( err == Z_OK ) this->ReadValues ( CyString ((char *)uncompr) );
6 cycrow 1633
			doneLen = uncomprLen;
1634
			delete uncompr;
1635
		}
51 cycrow 1636
		catch (std::exception &e) {
1637
			CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());
53 cycrow 1638
			delete []readData;
51 cycrow 1639
			return -1;
6 cycrow 1640
		}
51 cycrow 1641
	}
1642
	else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP ) {
1643
		long len = uncomprLen;
1644
		unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lValueCompressSize, (size_t*)&len, NULL );
1645
		// update the progress for each section
1646
		if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);
6 cycrow 1647
 
51 cycrow 1648
		if ( compr ) ReadValues ( CyString ((char *)compr) );
6 cycrow 1649
	}
51 cycrow 1650
	// no compression
1651
	else
1652
		ReadValues ( CyString ((char *)readData) );
6 cycrow 1653
 
53 cycrow 1654
	delete []readData;
6 cycrow 1655
 
51 cycrow 1656
	return doneLen;
1657
}
6 cycrow 1658
 
109 cycrow 1659
int CBaseFile::_read_FileHeader(CFileIO &File, int iReadType, int iMaxProgress, int iDoneLen, CProgressInfo *pProgress)
51 cycrow 1660
{
1661
	unsigned char *readData;
1662
	try {
1663
		readData = new unsigned char[m_SHeader2.lSize];
1664
	}
1665
	catch (std::exception &e) {
1666
		CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [header], %d (%s)", m_SHeader2.lSize, e.what());
1667
		return -1;
1668
	}
6 cycrow 1669
 
51 cycrow 1670
	unsigned char size[4];
109 cycrow 1671
	File.read(size, 4);
1672
	File.read(readData, m_SHeader2.lSize);
6 cycrow 1673
 
51 cycrow 1674
	unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
6 cycrow 1675
 
51 cycrow 1676
	// check for zlib compression
1677
	if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ) {
1678
		if ( uncomprLen < (unsigned long)iDoneLen ) uncomprLen = iDoneLen;
6 cycrow 1679
 
51 cycrow 1680
		try {
6 cycrow 1681
			unsigned char *uncompr = new unsigned char[uncomprLen];
1682
			int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );
1683
			// update the progress for each section
51 cycrow 1684
			if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);
1685
			if ( err == Z_OK ) ReadFiles ( CyString ((char *)uncompr) );
6 cycrow 1686
			delete uncompr;
1687
		}
51 cycrow 1688
		catch (std::exception &e) {
1689
			CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());
53 cycrow 1690
			delete []readData;
51 cycrow 1691
			return -1;
6 cycrow 1692
		}
1693
 
1694
	}
51 cycrow 1695
	else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
1696
	{
1697
		long len = uncomprLen;
1698
		unsigned char *compr = LZMADecode_C ( readData, m_SHeader2.lSize, (size_t*)&len, NULL );
1699
		// update the progress for each section
1700
		if ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);
1701
		if ( compr ) ReadFiles ( CyString ((char *)compr) );
1702
	}
1703
	else
1704
		ReadFiles ( CyString ((char *)readData) );
6 cycrow 1705
 
53 cycrow 1706
	delete []readData;
51 cycrow 1707
	return true;
1708
}
1709
 
58 cycrow 1710
bool CBaseFile::readFile(CFileIO &File, int readtype, CProgressInfo *progress)
51 cycrow 1711
{
1712
	ClearError ();
1713
 
1714
	// first read the header
58 cycrow 1715
	if ( !ParseHeader(File.readEndOfLine()) ) return false;
51 cycrow 1716
	if ( readtype == SPKREAD_HEADER ) return true;
1717
 
1718
	// update the progress for each section
1719
	int maxProgress = (readtype == SPKREAD_VALUES) ? 3 : 6;
1720
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(1, maxProgress);
1721
 
1722
	long doneLen = 0;
1723
	// next read the data values for the spk files
109 cycrow 1724
	if ( m_SHeader.lValueCompressSize ) doneLen = this->_read_Header(File, readtype, maxProgress, progress);
51 cycrow 1725
 
1726
	// update the progress for each section
1727
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(3, maxProgress);
1728
	if ( readtype == SPKREAD_VALUES ) return true;
1729
 
1730
	// next should be the next header
58 cycrow 1731
	if ( !ParseFileHeader(File.readEndOfLine()) ) return false;
51 cycrow 1732
 
1733
	// clear the current file list
1734
	m_lFiles.clear(true);
88 cycrow 1735
	if ( _pTextDB ) {
1736
		delete _pTextDB;
1737
		_pTextDB = NULL;
1738
	}
51 cycrow 1739
 
1740
	// update the progress for each section
1741
	if ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(4, maxProgress);
1742
 
109 cycrow 1743
	if ( m_SHeader2.lSize ) this->_read_FileHeader(File, readtype, maxProgress, doneLen, progress);
51 cycrow 1744
 
6 cycrow 1745
	// file mismatch
1746
	long numfiles = m_lFiles.size();
51 cycrow 1747
	if ( m_pIconFile ) ++numfiles;
1748
	if ( m_SHeader2.iNumFiles != numfiles ) {
6 cycrow 1749
		m_iLastError = SPKERR_FILEMISMATCH;
1750
		return false;
1751
	}
1752
 
1753
	// update the progress for each section
51 cycrow 1754
	if ( readtype != SPKREAD_ALL && progress )	progress->UpdateProgress(6, maxProgress);
6 cycrow 1755
 
51 cycrow 1756
	if ( readtype == SPKREAD_ALL ) {
6 cycrow 1757
		int fileCount = 2;
58 cycrow 1758
		if ( m_pIconFile ) m_pIconFile->readFromFile(File, m_pIconFile->GetDataSize());
6 cycrow 1759
 
51 cycrow 1760
		// ok finally we need to read all the file
1761
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
58 cycrow 1762
			node->Data()->readFromFile(File, node->Data()->GetDataSize());
51 cycrow 1763
			if ( progress )	progress->UpdateProgress(fileCount++, m_lFiles.size() + 2);
6 cycrow 1764
		}
1765
 
1766
		m_bFullyLoaded = true;
1767
	}
1768
 
1769
	return true;
1770
}
1771
 
1772
bool CBaseFile::IsMod()
1773
{
1774
	// check for any mod files that are not fake patchs
1775
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
1776
	{
1777
		C_File *f = fNode->Data();
1778
		if ( f->GetFileType() != FILETYPE_MOD )
1779
			continue;
1780
 
1781
		if ( !f->IsFakePatch() )
1782
			return true;
1783
	}
1784
 
1785
	return false;
1786
}
1787
 
13 cycrow 1788
bool CBaseFile::IsFakePatch() const
6 cycrow 1789
{
1790
	// check for any mod files that are not fake patchs
1791
	for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
1792
	{
1793
		C_File *f = fNode->Data();
1794
		if ( f->GetFileType() != FILETYPE_MOD )
1795
			continue;
1796
 
1797
		if ( f->IsFakePatch() )
1798
			return true;
1799
	}
1800
 
1801
	return false;
1802
}
1803
 
14 cycrow 1804
Utils::String CBaseFile::CreateValuesLine () const
6 cycrow 1805
{
14 cycrow 1806
	Utils::String values("Name: ");
50 cycrow 1807
	values += this->name() + "\n";
1808
	values += "Author: " + this->author() + "\n";
1809
	values += "Version: " + this->version() + "\n";
1810
	if ( !this->creationDate().empty() )values += "Date: "			+ this->creationDate()	+ "\n";
49 cycrow 1811
	if ( !this->webAddress().empty() )	values += "WebAddress: "	+ this->webAddress()	+ "\n";
1812
	if ( !this->webSite().empty() )		values += "WebSite: "		+ this->webSite()		+ "\n";
1813
	if ( !this->email().empty() )		values += "Email: "			+ this->email()			+ "\n";
1814
	if ( !this->forumLink().empty() )	values += "ForumLink: "		+ this->forumLink()		+ "\n";
1815
 
6 cycrow 1816
	for ( SStringList *str = m_lMirrors.Head(); str; str = str->next )
14 cycrow 1817
		values += Utils::String("WebMirror: ") + str->str.ToString() + "\n";
48 cycrow 1818
	if ( !this->description().empty() ) {
1819
		Utils::String desc = this->description();
14 cycrow 1820
		desc = desc.findReplace("<newline>", "<br>");
1821
		desc = desc.findReplace("\n", "<br>");
1822
		desc.remove('\r');
1823
		values += "Desc: " + desc + "\n";
6 cycrow 1824
	}
1825
 
1826
	for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {
46 cycrow 1827
		if ( !gc->Data()->sVersion.empty() )
1828
			values += Utils::String("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion + "\n";
6 cycrow 1829
		else
14 cycrow 1830
			values += Utils::String("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";
6 cycrow 1831
	}
1832
 
1833
	if ( m_bSigned )
1834
		values += "Signed\n";
1835
 
46 cycrow 1836
	for ( int j = 0; j < 2; j++ ) {
1837
		const CInstallText *text;
1838
		Utils::String textStart;
1839
		switch(j) {
1840
			case 0:	textStart = "Uninstall"; text = this->uninstallText(); break;
1841
			case 1: textStart = "Install"; text = this->installText(); break;
1842
		}
1843
		for ( unsigned int i = 0; i < text->count(); i++ ) {
1844
			int iLang = text->language(i);
1845
			if ( !text->getBefore(iLang).empty() ) values += textStart + "Before: " + (long)iLang + "|" + text->getBefore(iLang) + "\n";
1846
			if ( !text->getAfter(iLang).empty() ) values += textStart + "After: " + (long)iLang + "|" + text->getAfter(iLang) + "\n";
1847
		}
6 cycrow 1848
	}
1849
 
46 cycrow 1850
	values += Utils::String("GameChanging: ") + (long)gameChanging() + "\n";
1851
	values += Utils::String("EaseOfUse: ") + (long)easeOfUse() + "\n";
1852
	values += Utils::String("Recommended: ") + (long)recommended() + "\n";
6 cycrow 1853
 
14 cycrow 1854
	for ( CListNode<SNames> *nNode = m_lNames.Front(); nNode; nNode = nNode->next() )
46 cycrow 1855
		values += Utils::String("ScriptName: ") + (long)nNode->Data()->iLanguage + ":" + nNode->Data()->sName + "\n";
6 cycrow 1856
 
14 cycrow 1857
	for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() ) {
6 cycrow 1858
		SNeededLibrary *l = libNode->Data();
14 cycrow 1859
		values += (CyString("NeededLibrary: ") + l->sName + "||" + l->sAuthor + "||" + l->sMinVersion + "\n").ToString();
6 cycrow 1860
	}
1861
 
1862
	for ( SStringList *fpbNode = m_lFakePatchBefore.Head(); fpbNode; fpbNode = fpbNode->next )
14 cycrow 1863
		values += (CyString("FakePatchBefore: ") + fpbNode->str + "||" + fpbNode->data + "\n").ToString();
6 cycrow 1864
	for ( SStringList *fpaNode = m_lFakePatchAfter.Head(); fpaNode; fpaNode = fpaNode->next )
14 cycrow 1865
		values += (CyString("FakePatchAfter: ") + fpaNode->str + "||" + fpaNode->data + "\n").ToString();
6 cycrow 1866
 
48 cycrow 1867
	values += Utils::String("PluginType: ") + (long)this->pluginType() + "\n";
6 cycrow 1868
 
1869
	return values;
1870
}
1871
 
1872
 
1873
/*
1874
	Func:   WriteFile
1875
	Input:  filename - The filename of the spk file to write to
1876
	Desc:   Writes the data to an spk file
1877
*/
1878
bool CBaseFile::WriteFile ( CyString filename, CProgressInfo *progress )
1879
{
52 cycrow 1880
	CFileIO File(filename);
1881
	if ( File.startWrite() ) return WriteData(File, progress);
1882
	return false;
6 cycrow 1883
}
1884
 
52 cycrow 1885
bool CBaseFile::WriteHeader(CFileIO &file, int valueheader, int valueComprLen)
6 cycrow 1886
{
52 cycrow 1887
	return file.write("BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);
6 cycrow 1888
}
1889
 
52 cycrow 1890
bool CBaseFile::WriteData(CFileIO &file, CProgressInfo *progress )
6 cycrow 1891
{
1892
	int valueheader = m_SHeader.iValueCompression, fileheader = m_SHeader.iValueCompression;
1893
	if ( valueheader == SPKCOMPRESS_7ZIP )
1894
		valueheader = SPKCOMPRESS_ZLIB;
1895
	if ( fileheader == SPKCOMPRESS_7ZIP )
1896
		fileheader = SPKCOMPRESS_ZLIB;
1897
 
1898
	// get the script values
1899
	this->UpdateSigned(true);
1900
	CyString values = this->CreateValuesLine();
1901
 
1902
	// compress the values
1903
	int valueUncomprLen = (int)values.Length();
1904
	unsigned long valueComprLen = 0;
1905
	unsigned char *valueCompr = NULL;
1906
	bool compressed = false;
1907
	if ( valueheader == SPKCOMPRESS_ZLIB )
1908
	{
1909
		valueComprLen = valueUncomprLen;
1910
		if ( valueComprLen < 100 )
1911
			valueComprLen = 200;
1912
		else if ( valueComprLen < 1000 )
1913
			valueComprLen *= 2;
1914
 
1915
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
1916
		int err = compress ( (unsigned char *)valueCompr, &valueComprLen, (const unsigned char *)values.c_str(), (unsigned long)values.Length(), 0 );
1917
		if ( err == Z_OK )
1918
			compressed = true;
1919
	}
1920
 
1921
	if ( !compressed )
1922
	{
1923
		valueComprLen = valueUncomprLen;
1924
		valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
1925
		memcpy ( valueCompr, values.c_str(), valueComprLen );
1926
		valueheader = SPKCOMPRESS_NONE;
1927
	}
1928
 
1929
	// write the main header to the file
52 cycrow 1930
	if ( !this->WriteHeader(file, valueheader, valueComprLen) )	return false;
6 cycrow 1931
 
1932
	// write the compressed data to file
52 cycrow 1933
	file.put(static_cast<unsigned char>(valueUncomprLen >> 24));
1934
	file.put(static_cast<unsigned char>(valueUncomprLen >> 16));
1935
	file.put(static_cast<unsigned char>(valueUncomprLen >> 8));
1936
	file.put(static_cast<unsigned char>(valueUncomprLen));
1937
	file.write(valueCompr, valueComprLen);
6 cycrow 1938
	free ( valueCompr );
1939
 
1940
	// now compress the files header
1941
	// create the files values
1942
	CyString files = CreateFilesLine ( true, progress );
1943
 
1944
	// compress the files values
1945
	long fileUncomprLen = (long)files.Length(), fileComprLen = fileUncomprLen;
1946
	unsigned char *fileCompr = NULL;
1947
 
1948
	compressed = false;
1949
	if ( fileUncomprLen )
1950
	{
1951
		if ( fileheader == SPKCOMPRESS_ZLIB )
1952
		{
1953
			if ( fileComprLen < 100 )
1954
				fileComprLen = 200;
1955
			else if ( fileComprLen < 1000 )
1956
				fileComprLen *= 2;
1957
			fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
1958
			int err = compress ( (unsigned char *)fileCompr, (unsigned long *)&fileComprLen, (const unsigned char *)files.c_str(), (unsigned long)files.Length(), 0 );
1959
			if ( err == Z_OK )
1960
				compressed = true;
1961
		}
1962
	}
1963
 
1964
	// if unable to compress, store it as plain text
1965
	if ( !compressed )
1966
	{
1967
		fileComprLen = fileUncomprLen;
1968
		fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
1969
		memcpy ( fileCompr, files.c_str(), fileComprLen );
1970
		fileheader = SPKCOMPRESS_NONE;
1971
	}
1972
 
1973
	// now write the file header
1974
	m_SHeader2.lSize = fileComprLen;
52 cycrow 1975
	file.write("FileHeader;%d;%ld;%ld;%d;%d\n", m_SHeader2.iNumFiles, m_SHeader2.lSize, m_SHeader2.lFullSize, fileheader, m_SHeader2.iDataCompression);
6 cycrow 1976
 
52 cycrow 1977
	file.put(static_cast<unsigned char>(fileUncomprLen >> 24));
1978
	file.put(static_cast<unsigned char>(fileUncomprLen >> 16));
1979
	file.put(static_cast<unsigned char>(fileUncomprLen >> 8));
1980
	file.put(static_cast<unsigned char>(fileUncomprLen));
1981
	file.write(fileCompr, fileComprLen);
6 cycrow 1982
	free ( fileCompr );
1983
 
1984
	if ( progress )
1985
	{
1986
		progress->UpdateStatus(STATUS_WRITE);
1987
		progress->SetDone(0);
1988
		long max = 0;
88 cycrow 1989
		for ( CListNode<C_File> *file = m_lFiles.Front(); file; file = file->next() )
1990
			max += file->Data()->GetDataSize();
6 cycrow 1991
		if ( m_pIconFile )
1992
			max += m_pIconFile->GetDataSize();
1993
		progress->SetMax(max);
1994
	}
1995
 
1996
	// now finally, write all the file data
52 cycrow 1997
	if ( m_pIconFile ) {
1998
		if ( progress )	progress->UpdateFile(m_pIconFile);
1999
		file.writeSize(m_pIconFile->GetUncompressedDataSize());
2000
		file.write(m_pIconFile->GetData(), m_pIconFile->GetDataSize());
2001
		if ( progress )	progress->IncDone(m_pIconFile->GetDataSize());
6 cycrow 2002
	}
2003
 
2004
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2005
	{
52 cycrow 2006
		C_File *f = node->Data();
2007
		if ( progress )	progress->UpdateFile(f);
2008
		file.writeSize(f->GetUncompressedDataSize());
2009
		unsigned char *data = f->GetData();
2010
		size_t remaining = f->GetDataSize();
2011
		while ( remaining )	{
6 cycrow 2012
			size_t writeSize = WRITECHUNK;
52 cycrow 2013
			if ( writeSize > remaining ) writeSize = remaining;
6 cycrow 2014
 
52 cycrow 2015
			if ( file.write(data, writeSize) ) {
2016
				data += writeSize;
2017
				remaining -= writeSize;
2018
			}
6 cycrow 2019
 
52 cycrow 2020
			if ( progress ) progress->IncDone((int)writeSize);
6 cycrow 2021
		}
2022
	}
2023
 
50 cycrow 2024
	_changed();
6 cycrow 2025
 
2026
	return true;
2027
}
2028
 
2029
 
2030
bool CBaseFile::ExtractFile ( C_File *file, CyString dir, bool includedir, CProgressInfo *progress )
2031
{
2032
	if ( ReadFileToMemory ( file ) )
2033
	{
2034
		// now finally, uncompress the file
2035
		long len = 0;
2036
		unsigned char *data = file->UncompressData ( &len, progress );
2037
		if ( !data )
2038
		{
2039
			// attempt a file decompress
2040
			if ( file->GetCompressionType() == SPKCOMPRESS_7ZIP )
2041
			{
2042
				if ( file->UncompressToFile ( dir, this, includedir, progress ) )
2043
					return true;
2044
			}
2045
			return false;
2046
		}
2047
 
2048
		if ( !file->WriteToDir ( dir, this, includedir, NullString, data, len ) )
2049
			return false;
2050
 
2051
		return true;
2052
 
2053
	}
2054
	else
2055
		return false;
2056
}
2057
 
2058
bool CBaseFile::ExtractFile ( int filenum, CyString dir, bool includedir, CProgressInfo *progress )
2059
{
2060
	// invalid valus
2061
	if ( filenum < 0 )
2062
		return false;
2063
	// out of range
2064
	if ( filenum > m_lFiles.size() )
2065
		return false;
2066
 
2067
	// get the file pointer
2068
	C_File *file = m_lFiles.Get ( filenum );
2069
	return ExtractFile ( file, dir, includedir, progress );
2070
}
2071
 
2072
 
2073
 
2074
bool CBaseFile::ExtractAll ( CyString dir, int game, bool includedir, CProgressInfo *progress )
2075
{
2076
	// no file to read from
50 cycrow 2077
	if ( this->filename().empty() )
6 cycrow 2078
		return false;
2079
 
2080
	// now open the file
58 cycrow 2081
	CFileIO *File = _startRead();
2082
	if ( !File ) return false;
6 cycrow 2083
 
2084
	// now were in the file section
2085
	// skip past each one
58 cycrow 2086
	if ( m_pIconFile ) File->seek(4 + m_pIconFile->GetDataSize ());
6 cycrow 2087
 
2088
	CDirIO Dir(dir);
2089
 
52 cycrow 2090
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
6 cycrow 2091
		C_File *fit = node->Data();
2092
 
52 cycrow 2093
		if ( progress )	progress->UpdateFile ( fit );
6 cycrow 2094
 
52 cycrow 2095
		if ( (!fit->GetDataSize ()) || (!fit->GetData()) ) {
58 cycrow 2096
			if ( !fit->readFromFile(*File, fit->GetDataSize()) ) return false;
6 cycrow 2097
		}
2098
		else
58 cycrow 2099
			File->seek(fit->GetDataSize());
6 cycrow 2100
 
2101
		if ( game ) {
2102
			if ( fit->GetGame() && fit->GetGame() != game )
2103
				continue;
2104
		}
2105
 
2106
		// create directory first
2107
		Dir.Create(fit->GetDirectory(this));
2108
 
2109
		long size = 0;
2110
		unsigned char *data = fit->UncompressData (&size, progress);
52 cycrow 2111
		if ( (!data) && (fit->GetCompressionType() == SPKCOMPRESS_7ZIP) ) {
2112
			if ( !fit->UncompressToFile ( dir, this, includedir, progress ) ) return false;
6 cycrow 2113
		}
52 cycrow 2114
		else if ( (!data) || (!fit->WriteToDir ( dir, this, includedir, NullString, data, size )) ) return false;
6 cycrow 2115
	}
2116
 
58 cycrow 2117
	delete File;
6 cycrow 2118
	return true;
2119
}
2120
 
2121
 
2122
 
2123
 
2124
bool CBaseFile::UpdateSigned (bool updateFiles)
2125
{
2126
	m_bSigned = true;
2127
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2128
	{
2129
		C_File *file = node->Data();
2130
		if ( updateFiles )
2131
			file->UpdateSigned();
2132
		// extra, text, soundtrack, readmes and screen files do not require a modified game directly
2133
		if ( (file->GetFileType() == FILETYPE_EXTRA) || (file->GetFileType() == FILETYPE_TEXT) || (file->GetFileType() == FILETYPE_SOUND) || (file->GetFileType() == FILETYPE_SCREEN) || (file->GetFileType() == FILETYPE_README) )
2134
			continue;
2135
		// mods and maps always need modified game
2136
		else if ( (file->GetFileType() == FILETYPE_MOD) || (file->GetFileType() == FILETYPE_MAP) )
2137
		{
2138
			m_bSigned = false;
2139
			break;
2140
		}
2141
 
2142
		// else should be a script file, script or uninstall type
2143
		// all scripts must be signed, if any are not, then no signed status
2144
		if ( !file->IsSigned () )
2145
		{
2146
			m_bSigned = false;
2147
			break;
2148
		}
2149
	}
2150
 
2151
	return m_bSigned;
2152
}
2153
 
2154
 
46 cycrow 2155
bool CBaseFile::IsPackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2156
{
2157
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2158
	{
2159
		SNeededLibrary *l = node->Data();
2160
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2161
			return true;
2162
	}
2163
 
2164
	return false;
2165
}
2166
 
46 cycrow 2167
SNeededLibrary *CBaseFile::FindPackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2168
{
2169
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2170
	{
2171
		SNeededLibrary *l = node->Data();
2172
		if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
2173
			return l;
2174
	}
2175
 
2176
	return NULL;
2177
}
2178
 
2179
void CBaseFile::RemoveFakePatchOrder(CyString scriptName, CyString author)
2180
{
2181
	RemoveFakePatchOrder(true, scriptName, author);
2182
	RemoveFakePatchOrder(false, scriptName, author);
2183
}
2184
void CBaseFile::RemoveFakePatchOrder(bool after, CyString scriptName, CyString author)
2185
{
2186
	CyStringList *list;
2187
	if ( after )
2188
		list = &m_lFakePatchAfter;
2189
	else
2190
		list = &m_lFakePatchBefore;
2191
 
2192
	for ( SStringList *str = list->Head(); str; str = str->next )
2193
	{
2194
		// already added
2195
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
2196
			str->remove = true;
2197
	}
2198
 
2199
	list->RemoveMarked();
2200
}
2201
 
2202
void CBaseFile::AddFakePatchOrder(bool after, CyString scriptName, CyString author)
2203
{
2204
	CyStringList *list;
2205
	if ( after )
2206
		list = &m_lFakePatchAfter;
2207
	else
2208
		list = &m_lFakePatchBefore;
2209
 
2210
	// check if the package already exists
2211
	for ( SStringList *str = list->Head(); str; str = str->next )
2212
	{
2213
		// already added
2214
		if ( str->str.Compare(scriptName) && str->data.Compare(author) )
2215
			return;
2216
	}
2217
 
2218
	// cant have it on both list
2219
	RemoveFakePatchOrder(!after, scriptName, author);
2220
 
2221
	list->PushBack(scriptName, author);
2222
}
46 cycrow 2223
void CBaseFile::AddNeededLibrary(const Utils::String &scriptName, const Utils::String &author, const Utils::String &minVersion)
6 cycrow 2224
{
2225
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2226
	if ( !l )
2227
	{
2228
		l = new SNeededLibrary;
2229
		l->sName = scriptName;
2230
		l->sAuthor = author;
2231
		m_lNeededLibrarys.push_back(l);
2232
	}
2233
	l->sMinVersion = minVersion;
2234
}
2235
 
46 cycrow 2236
void CBaseFile::RemovePackageNeeded(const Utils::String &scriptName, const Utils::String &author)
6 cycrow 2237
{
2238
	SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
2239
	if ( l )
2240
	{
2241
		m_lNeededLibrarys.remove(l);
2242
		delete l;
2243
	}
2244
}
2245
 
2246
void CBaseFile::ClearNeededPackages()
2247
{
2248
	SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");
46 cycrow 2249
	Utils::String version;
2250
	if ( ns ) version = ns->sMinVersion;
2251
 
6 cycrow 2252
	for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2253
		node->DeleteData();
2254
	m_lNeededLibrarys.clear();
2255
 
46 cycrow 2256
	if ( !version.empty() )	this->AddNeededLibrary("<package>", "<author>", version);
6 cycrow 2257
}
2258
 
2259
 
2260
bool CBaseFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
2261
{
2262
	list->PushBack("#");
2263
	list->PushBack(CyString("# Packager Script"));
2264
	list->PushBack(CyString("# -- Generated by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2) + " --");
2265
	list->PushBack("#");
2266
	list->PushBack("");
2267
	if ( !datafile )
2268
	{
2269
		list->PushBack("# Variable for your game directory, where to get files from");
2270
		list->PushBack("# $PATH variable is used to get the current path");
2271
		list->PushBack("Variable: $GAMEDIR $PATH");
2272
		list->PushBack("");
2273
	}
2274
	list->PushBack("# The name of the script");
50 cycrow 2275
	list->PushBack(CyString("Name: ") + this->name());
6 cycrow 2276
	list->PushBack("");
2277
	list->PushBack("# The author of the script, ie, you");
50 cycrow 2278
	list->PushBack(CyString("Author: ") + this->author());
6 cycrow 2279
	list->PushBack("");
2280
	list->PushBack("# The creation data, when it was created");
2281
	if ( datafile )
50 cycrow 2282
		list->PushBack(CyString("Date: ") + this->creationDate());
2283
	else {
6 cycrow 2284
		list->PushBack("# $DATE variable is used to get the current date");
2285
		list->PushBack("Date: $DATE");
2286
	}
2287
	list->PushBack("");
2288
	list->PushBack("# The version of script");
2289
	if ( datafile )
50 cycrow 2290
		list->PushBack(CyString("Version: ") + this->version());
6 cycrow 2291
	else
2292
	{
2293
		list->PushBack("# $ASK variable is used to get an input when creating");
2294
		list->PushBack("Version: $ASK");
2295
	}
2296
	list->PushBack("");
2297
 
2298
	if ( !m_lGames.empty() ) {
2299
		list->PushBack("# The game version the script is for <game> <version> (can have multiple games)");
2300
		for ( SGameCompat *g = m_lGames.First(); g; g = m_lGames.Next() ) {
13 cycrow 2301
			Utils::String game = CBaseFile::ConvertGameToString(g->iGame);
6 cycrow 2302
 
46 cycrow 2303
			if ( !g->sVersion.empty() )
6 cycrow 2304
			{
2305
				game += " ";
46 cycrow 2306
				game += g->sVersion;
6 cycrow 2307
			}
2308
			else
2309
			{
2310
				game += " ";
2311
				game += (long)g->iVersion;
2312
			}
2313
 
2314
			list->PushBack(CyString("Game: ") + game);
2315
		}
2316
 
2317
		list->PushBack("");
2318
	}
2319
 
48 cycrow 2320
	if ( !this->description().empty() ) {
6 cycrow 2321
		list->PushBack("# The description of the script, displays when installing");
48 cycrow 2322
		list->PushBack(CyString("Description: ") + this->description());
6 cycrow 2323
		list->PushBack("");
2324
	}
2325
 
49 cycrow 2326
	if ( !this->webSite().empty() ) {
6 cycrow 2327
		list->PushBack("# A link to the website for the script, ie for an online help page");
49 cycrow 2328
		list->PushBack(CyString("WebSite: ") + this->webSite());
6 cycrow 2329
		list->PushBack("");
2330
	}
2331
 
49 cycrow 2332
	if ( !this->forumLink().empty() ) {
6 cycrow 2333
		list->PushBack("# A direct link to the thread in the egosoft forum");
49 cycrow 2334
		list->PushBack(CyString("ForumLink: ") + this->forumLink());
6 cycrow 2335
		list->PushBack("");
2336
	}
2337
 
49 cycrow 2338
	if ( !this->webAddress().empty() ) {
6 cycrow 2339
		list->PushBack("# A link to the address for the update file");
49 cycrow 2340
		list->PushBack(CyString("WebAddress: ") + this->webAddress());
6 cycrow 2341
		list->PushBack("");
2342
	}
2343
 
49 cycrow 2344
	if ( !this->email().empty() ) {
6 cycrow 2345
		list->PushBack("# The email address of the author, to allow users to contract if needed");
49 cycrow 2346
		list->PushBack(CyString("Email: ") + this->email());
6 cycrow 2347
		list->PushBack("");
2348
	}
2349
 
2350
	if ( m_lMirrors.Count() )
2351
	{
2352
		list->PushBack("# A link to the mirror address for the update file, can have many of these");
2353
		for ( SStringList *node = m_lMirrors.Head(); node; node = node->next )
2354
			list->PushBack(CyString("WebMirror: ") + node->str);
2355
		list->PushBack("");
2356
	}
2357
 
2358
	if ( m_bAutoGenerateUpdateFile )
2359
	{
2360
		list->PushBack("# Auto generate the package update file when created");
2361
		list->PushBack("GenerateUpdateFile");
2362
	}
2363
 
2364
	if ( m_lNeededLibrarys.size() )
2365
	{
2366
		list->PushBack("# Needed Library dependacies, require these to be installed");
2367
		for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
2368
			list->PushBack(CyString("Depend: ") + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);
2369
 
2370
		list->PushBack("");
2371
	}
2372
 
46 cycrow 2373
	if ( !_noRatings() )
6 cycrow 2374
	{
2375
		list->PushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");
46 cycrow 2376
		list->PushBack(CyString("Ratings: ") + (long)easeOfUse() + " " + (long)gameChanging() + " " + (long)recommended());
6 cycrow 2377
		list->PushBack("");
2378
	}
2379
 
2380
	if ( m_lNames.size() )
2381
	{
2382
		list->PushBack("# Package names, uses different names for different languages");
2383
		for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
2384
			list->PushBack(CyString("ScriptName: ") + (long)node->Data()->iLanguage + " " + node->Data()->sName);
2385
		list->PushBack("");
2386
	}
2387
 
46 cycrow 2388
	for ( int j = 0; j < 2; j++ ) {
2389
		Utils::String installText = (j == 0) ? "Install" : "Uninstall";
2390
		const CInstallText *pText = (j == 0) ? this->installText() : this->uninstallText();
2391
		if ( pText->any() )
6 cycrow 2392
		{
46 cycrow 2393
			list->PushBack(CyString("# " + installText + " Texts, display text before and/or after " + installText + "ing to inform the use of special conditions"));
2394
			for ( unsigned int i = 0; i < pText->count(); i++ ) {
2395
				long iLang = pText->language(i);
2396
				if ( !pText->getBefore(iLang).empty() )	list->PushBack(CyString(installText + "Before: ") + iLang + " " + pText->getBefore(iLang));
2397
				if ( !pText->getAfter(iLang).empty()  )	list->PushBack(CyString(installText + "After: ") + iLang + " " + pText->getAfter(iLang));
2398
			}
2399
			list->PushBack("");
6 cycrow 2400
		}
2401
	}
2402
 
2403
	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 2404
	switch ( this->pluginType() )
6 cycrow 2405
	{
2406
		case PLUGIN_NORMAL:
2407
			list->PushBack("PluginType: Normal");
2408
			break;
2409
		case PLUGIN_STABLE:
2410
			list->PushBack("PluginType: Stable");
2411
			break;
2412
		case PLUGIN_EXPERIMENTAL:
2413
			list->PushBack("PluginType: Experimental");
2414
			break;
2415
		case PLUGIN_CHEAT:
2416
			list->PushBack("PluginType: Cheat");
2417
			break;
2418
		case PLUGIN_MOD:
2419
			list->PushBack("PluginType: Mod");
2420
			break;
2421
	}
2422
	list->PushBack("");
2423
 
2424
	return true;
2425
}
2426
 
2427
bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, CyStringList *list)
2428
{
2429
	// now do files and wildcards
2430
	CyStringList files;
2431
	for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
2432
	{
2433
		CyString name = "$GAMEDIR/";
2434
 
2435
		bool done = false;
2436
		if ( wildcard )
2437
		{
2438
			CyString base = f->Data()->GetBaseName();
2439
			if ( f->Data()->GetFileType() == FILETYPE_SCRIPT )
2440
			{
2441
				if ( base.GetToken(".", 1, 1).Compare("plugin") || base.GetToken(".", 1, 1).Compare("lib") )
2442
				{
2443
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
2444
					done = true;
2445
				}
2446
				else if ( base.GetToken(".", 1, 1).Compare("al") && !base.GetToken(".", 2, 2).Compare("plugin") )
2447
				{
2448
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
2449
					done = true;
2450
				}
2451
			}
2452
			else if ( f->Data()->GetFileType() == FILETYPE_TEXT )
2453
			{
2454
				if ( base.IsIn("-L") )
2455
				{
2456
					name += f->Data()->GetDirectory(this) + "/" + base.GetToken("-L", 1, 1) + "-L*";
2457
					done = true;
2458
				}
2459
				else
2460
				{
2461
					name += f->Data()->GetDirectory(this) + "/*" + base.Right(4) + ".*";
2462
					done = true;
2463
				}
2464
			}
2465
		}
2466
 
2467
		if ( !done )
2468
			name += f->Data()->GetNameDirectory(this);
2469
 
2470
		if ( !f->Data()->GetDir().Empty() )
2471
		{
2472
			name += "|";
2473
			name += f->Data()->GetDir();
2474
		}
2475
		files.PushBack(CyString("GAME ") + CBaseFile::ConvertGameToString(f->Data()->GetGame()) + " " + name, f->Data()->GetFileTypeString(), true);
2476
	}
2477
 
2478
 
2479
	if ( !files.Empty() )
2480
	{
2481
		list->PushBack("# Files List, all the files to add, can include wild cards");
2482
		for ( SStringList *node = files.Head(); node; node = node->next )
2483
			list->PushBack(node->data + ": " + node->str);
2484
		list->PushBack("");
2485
	}
2486
 
2487
	return true;
2488
}
2489
 
50 cycrow 2490
Utils::String CBaseFile::GetAutosaveName()
6 cycrow 2491
{
50 cycrow 2492
	return this->name() + "-V" + this->version() + "-" + this->creationDate().findReplace("/", ".");
6 cycrow 2493
}
2494
 
2495
bool CBaseFile::CheckGameCompatability(int game)
2496
{
2497
	if ( m_lGames.empty() )
2498
		return true; // no game compatability added, assume its ok for all
2499
 
2500
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2501
		if ( node->Data()->iGame == 0 || node->Data()->iGame == game )
2502
			return true;
2503
	}
2504
	return false;
2505
}
2506
 
2507
bool CBaseFile::CheckGameVersionCompatability(int game, CyString sVersion, int iVersion)
2508
{
2509
	if ( m_lGames.empty() )
2510
		return true; // no game compatability added, assume its ok for all
2511
 
2512
	bool foundAll = false;
2513
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2514
		if ( node->Data()->iGame == 0 )
2515
			foundAll = true;
2516
		else if ( node->Data()->iGame == game ) { // now check the version
46 cycrow 2517
			if ( node->Data()->sVersion.empty() ) {
2518
				if ( CyString(node->Data()->sVersion).CompareVersion(sVersion) == COMPARE_OLDER )
6 cycrow 2519
					return false;
2520
				return true;
2521
			}
2522
			else {
2523
				if ( node->Data()->iVersion > iVersion )
2524
					return false;
2525
				return true;
2526
			}
2527
		}
2528
	}
2529
	return foundAll;
2530
}
2531
 
2532
bool CBaseFile::RemoveGameCompatability(int game)
2533
{
2534
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2535
		if ( node->Data()->iGame == game ) {
2536
			m_lGames.remove(node);
50 cycrow 2537
			_changed();
6 cycrow 2538
			return true;
2539
		}
2540
	}
2541
 
2542
	return false;
2543
}
2544
 
2545
SGameCompat *CBaseFile::GetGameCompatability(int game)
2546
{
2547
	for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
2548
		if ( node->Data()->iGame == game ) {
2549
			return node->Data();
2550
		}
2551
	}
2552
 
2553
	return NULL;
2554
}
2555
 
46 cycrow 2556
void CBaseFile::AddGameCompatability(int game, const Utils::String &version)
6 cycrow 2557
{
2558
	// first check if we already have it on the list
2559
	SGameCompat *Found = this->GetGameCompatability(game);
2560
	if ( !Found ) {
2561
		Found = new SGameCompat;
2562
		m_lGames.push_back(Found);
2563
	}
2564
 
2565
	Found->iGame = game;
2566
	Found->iVersion = -1;
46 cycrow 2567
	Found->sVersion = "";
6 cycrow 2568
 
46 cycrow 2569
	if ( version.isin(".") || !version.isNumber() )
6 cycrow 2570
		Found->sVersion = version;
2571
	else
46 cycrow 2572
		Found->iVersion = version;
50 cycrow 2573
	_changed();
6 cycrow 2574
}
2575
 
98 cycrow 2576
bool CBaseFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames)
6 cycrow 2577
{
50 cycrow 2578
	if ( sFirst.Compare("Name") )					this->setName(sRest);
2579
	else if ( sFirst.Compare("Author") )			this->setAuthor(sRest);
14 cycrow 2580
	else if ( sFirst.Compare("ScriptName") )
2581
		AddLanguageName(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));
46 cycrow 2582
	else if ( sFirst.Compare("UninstallBefore") )	this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));
2583
	else if ( sFirst.Compare("UninstallAfter") )	this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));
2584
	else if ( sFirst.Compare("InstallBefore") )		this->addInstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));
2585
	else if ( sFirst.Compare("InstallAfter") )		this->addInstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));
50 cycrow 2586
	else if ( sFirst.Compare("Date") )				this->setCreationDate(sRest);
2587
	else if ( sFirst.Compare("Version") )			this->setVersion(sRest);
14 cycrow 2588
	else if ( sFirst.Compare("GameVersion") )
2589
		this->AddGameCompatability(-1, sRest);
50 cycrow 2590
	else if ( sFirst.Compare("PluginType") ) {
48 cycrow 2591
		if ( sRest.isNumber() )						this->setPluginType(sRest);
2592
		else if ( sRest.Compare("Normal") )			this->setPluginType(PLUGIN_NORMAL);
2593
		else if ( sRest.Compare("Stable") )			this->setPluginType(PLUGIN_STABLE);
2594
		else if ( sRest.Compare("Experimental") )	this->setPluginType(PLUGIN_EXPERIMENTAL);
2595
		else if ( sRest.Compare("Cheat") )			this->setPluginType(PLUGIN_CHEAT);
2596
		else if ( sRest.Compare("Mod") )			this->setPluginType(PLUGIN_MOD);
6 cycrow 2597
	}
2598
	// new version
14 cycrow 2599
	else if ( sFirst.Compare("GenerateUpdateFile") )
6 cycrow 2600
		m_bAutoGenerateUpdateFile = true;
14 cycrow 2601
	else if ( sFirst.Compare("Game") )
6 cycrow 2602
	{
14 cycrow 2603
		Utils::String sGame = sRest.token(" ", 1);
2604
		this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), sRest.token(" ", 2));
6 cycrow 2605
	}
48 cycrow 2606
	else if ( sFirst.Compare("Description") )		this->setDescription(sRest);
14 cycrow 2607
	else if ( sFirst.Compare("AutoSave") || sFirst.Compare("AutoExport") || sFirst.Compare("AutoRarExport") || sFirst.Compare("AutoZipExport") )
6 cycrow 2608
	{
50 cycrow 2609
		Utils::String filename = sRest;
2610
		Utils::String cdate = this->creationDate().findReplace("/", ".").remove(' ');
2611
		if ( filename.isin("$AUTOSAVE") )
6 cycrow 2612
		{
96 cycrow 2613
			if ( this->GetType() == TYPE_XSP )
50 cycrow 2614
				filename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");
6 cycrow 2615
			else
50 cycrow 2616
				filename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");
6 cycrow 2617
		}
50 cycrow 2618
		filename = filename.findReplace("$NAME", this->name().remove(' '));
2619
		filename = filename.findReplace("$AUTHOR", this->author().remove(' '));
2620
		filename = filename.findReplace("$DATE", cdate);
2621
		filename = filename.findReplace("$CDATE", cdate);
2622
		filename = filename.findReplace("$VERSION", this->version());
6 cycrow 2623
 
14 cycrow 2624
		if ( sFirst.Compare("AutoZipExport") || sFirst.Compare("AutoExport") )
50 cycrow 2625
			this->setExportFilename(CFileIO(filename).ChangeFileExtension("zip").ToString());
14 cycrow 2626
		else if ( sFirst.Compare("AutoRarExport") )
50 cycrow 2627
			this->setExportFilename(CFileIO(filename).ChangeFileExtension("rar").ToString());
6 cycrow 2628
		else
50 cycrow 2629
			this->setFilename(filename);
6 cycrow 2630
	}
49 cycrow 2631
	else if ( sFirst.Compare("WebSite") )		this->setWebSite(sRest);
2632
	else if ( sFirst.Compare("ForumLink") || sFirst.Compare("Forum") ) this->setForumLink(sRest);
2633
	else if ( sFirst.Compare("Email") )			this->setEmail(sRest);
2634
	else if ( sFirst.Compare("WebAddress") )	this->setWebAddress(sRest);
14 cycrow 2635
	else if ( sFirst.Compare("WebMirror") )
2636
		this->AddWebMirror(sRest);
2637
	else if ( sFirst.Compare("WebMirror1") )
2638
		this->AddWebMirror(sRest);
2639
	else if ( sFirst.Compare("WebMirror2") )
2640
		this->AddWebMirror(sRest);
2641
	else if ( sFirst.Compare("Ftp") )
2642
		m_sFtpAddr = sRest;
46 cycrow 2643
	else if ( sFirst.Compare("Ratings") )		_setRatings(sRest.token(" ", 1), sRest.token(" ", 2), sRest.token(" ", 3));
2644
	else if ( sFirst.Compare("EaseOfUse") )		setEaseOfUse(sRest);
2645
	else if ( sFirst.Compare("GameChanging"))	setGameChanging(sRest);
2646
	else if ( sFirst.Compare("Recommended") )	setRecommended(sRest);
14 cycrow 2647
	else if ( sFirst.Compare("Depend") )
6 cycrow 2648
	{
46 cycrow 2649
		Utils::String version = sRest.token("|", 2);
2650
		Utils::String name = sRest.token("|", 1);
2651
		Utils::String author = sRest.tokens("|", 3);
6 cycrow 2652
 
2653
		this->AddNeededLibrary(name, author, version);
2654
	}
14 cycrow 2655
	else if ( sFirst.Compare("DependPackage") )
6 cycrow 2656
	{
2657
		CPackages p;
14 cycrow 2658
		CBaseFile *spk =  p.OpenPackage(sRest, 0, 0, SPKREAD_VALUES);
6 cycrow 2659
		if ( spk )
2660
		{
50 cycrow 2661
			this->AddNeededLibrary(spk->name(), spk->author(), spk->version());
6 cycrow 2662
			delete spk;
2663
		}
2664
	}
14 cycrow 2665
	else if ( sFirst.Compare("Icon") )
6 cycrow 2666
	{
14 cycrow 2667
		C_File *icon = new C_File(sRest.c_str());
6 cycrow 2668
		if ( icon->ReadFromFile() )
14 cycrow 2669
			this->SetIcon(icon, CFileIO(sRest).GetFileExtension());
6 cycrow 2670
	}
2671
	else
2672
	{
14 cycrow 2673
		Utils::String checkType = sFirst;
6 cycrow 2674
		bool shared = false;
14 cycrow 2675
		if ( checkType.left(6).Compare("Shared") )
6 cycrow 2676
		{
14 cycrow 2677
			checkType = sFirst.right(-6);
6 cycrow 2678
			shared = true;
2679
		}
2680
 
2681
		// now check type name
2682
		int filetype = GetFileTypeFromString(checkType);
2683
		if ( filetype != -1 )
98 cycrow 2684
			this->AddFileScript(filetype, shared, sRest, sMainGame, otherGames);
6 cycrow 2685
		else if ( !checkType.Compare("changelog") )
2686
			return false;
2687
	}
2688
 
2689
	return true;
2690
}
2691
 
98 cycrow 2692
void CBaseFile::AddFileScript(int filetype, bool shared, CyString rest, const Utils::String &sMainGame, Utils::CStringList &otherGames)
6 cycrow 2693
{
2694
	CyString dir;
2695
	if ( rest.IsIn("|") )
2696
	{
2697
		dir = rest.GetToken("|", 2);
2698
		rest = rest.GetToken("|", 1, 1);
2699
	}
2700
 
98 cycrow 2701
	int mainGame = CBaseFile::GetGameFromString(sMainGame);
2702
 
6 cycrow 2703
	int game = 0;
2704
	if ( rest.GetToken(" ", 1, 1).Left(4).Compare("GAME") ) {
13 cycrow 2705
		game = CBaseFile::GetGameFromString(rest.GetToken(" ", 2, 2).ToString());
6 cycrow 2706
		rest = rest.GetToken(" ", 3);
2707
	}
2708
 
2709
	rest = rest.FindReplace("\\", "/");
2710
 
2711
	// wild cards
2712
	if ( rest.IsAnyIn("*?") )
2713
	{
102 cycrow 2714
		CDirIO Dir(CFileIO(rest).dir());
6 cycrow 2715
		CyStringList *dirList = Dir.DirList();
2716
		if ( dirList )
2717
		{
2718
			for ( SStringList *strNode = dirList->Head(); strNode; strNode = strNode->next )
2719
			{
2720
				CyString file = Dir.File(strNode->str);
2721
				if ( file.WildMatch(rest) )
2722
				{
98 cycrow 2723
					int addGame = game;
2724
					// check if the file exists in the subdirectory too, if it does, add for each game
2725
					if ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {
2726
						CFileIO F(file);
2727
						for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {
102 cycrow 2728
							Utils::String checkDir = F.dir() + "/" + g;
121 cycrow 2729
							if ( CDirIO(checkDir).exists(F.filename()) ) {
98 cycrow 2730
								addGame = mainGame;
2731
								C_File *newfile = this->AppendFile(CDirIO(checkDir).File(F.filename()), filetype, CBaseFile::GetGameFromString(g), dir);
2732
								if ( newfile ) newfile->SetShared(shared);
2733
							}
2734
						}
2735
					}
2736
 
2737
					C_File *newfile = this->AppendFile(file, filetype, addGame, dir);
6 cycrow 2738
					if ( newfile )
2739
						newfile->SetShared(shared);
2740
				}
2741
			}
2742
			delete dirList;
2743
		}
2744
	}
2745
	else
2746
	{
98 cycrow 2747
		int addGame = game;
2748
		// check if the file exists in the subdirectory too, if it does, add for each game
2749
		if ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {
2750
			CFileIO F(rest);
2751
			for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {
102 cycrow 2752
				Utils::String checkDir = F.dir() + "/" + g;
121 cycrow 2753
				if ( CDirIO(checkDir).exists(F.filename()) ) {
98 cycrow 2754
					addGame = mainGame;
121 cycrow 2755
					C_File *newfile = this->AppendFile(CDirIO(checkDir).file(F.filename()), filetype, CBaseFile::GetGameFromString(g), dir);
98 cycrow 2756
					if ( newfile ) newfile->SetShared(shared);
2757
				}
2758
			}
2759
		}
2760
 
2761
		C_File *file = this->AppendFile(rest, filetype, addGame, dir);
6 cycrow 2762
		if ( file )
2763
			file->SetShared(shared);
2764
	}
2765
}
2766
 
2767
 
2768
CyString CBaseFile::GetFullFileSizeString() { return SPK::GetSizeString ( this->GetFullFileSize() ); }
2769
 
52 cycrow 2770
// used for a multiple spk file
6 cycrow 2771
unsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress)
2772
{
52 cycrow 2773
	if ( this->WriteFile("temp.dat", progress) ) {
2774
		CFileIO File("temp.dat");
2775
		File.setAutoDelete(true);
2776
		return File.readAll(size);
6 cycrow 2777
	}
2778
	return NULL;
2779
}
2780
 
2781
 
2782
void CBaseFile::ConvertNormalMod(C_File *f, CyString to)
2783
{
2784
	C_File *match = this->FindMatchingMod(f);
2785
	if ( match )
2786
	{
2787
		// file link
2788
		if ( !match->GetData() )
2789
			match->ReadFromFile();
2790
		match->ChangeBaseName(to);
2791
	}
2792
 
2793
	// file link
2794
	if ( !f->GetData() )
2795
		f->ReadFromFile();
2796
 
2797
	f->ChangeBaseName(to);
2798
}
2799
 
2800
void CBaseFile::ConvertAutoText(C_File *f)
2801
{
2802
	CyString to;
2803
	if ( f->GetBaseName().IsIn("-L") )
2804
		to = CyString("0000-L") + f->GetBaseName().GetToken("-L", 2, 2);
2805
	else if ( f->GetBaseName().IsIn("-l") )
2806
		to = CyString("0000-L") + f->GetBaseName().GetToken("-l", 2, 2);
2807
	else
2808
		to = f->GetBaseName().Left(-4) + "0000";
2809
 
2810
	// file link
2811
	if ( !f->GetData() )
2812
		f->ReadFromFile();
2813
 
2814
	f->ChangeBaseName(to);
2815
 
2816
}
2817
 
2818
void CBaseFile::ConvertFakePatch(C_File *f)
2819
{
2820
	// find next available fake patch
2821
	int num = 0;
2822
 
2823
	bool found = true;
2824
	while ( found )
2825
	{
2826
		++num;
2827
		found = false;
2828
		CyString find = CyString::Number(num).PadNumber(2);
2829
		for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2830
		{
2831
			if ( node->Data()->GetFileType() != FILETYPE_MOD )
2832
				continue;
2833
			if ( !node->Data()->IsFakePatch() )
2834
				continue;
2835
			if ( node->Data()->GetBaseName().Compare(find) )
2836
			{
2837
				found = true;
2838
				break;
2839
			}
2840
		}
2841
	}
2842
 
2843
	CyString to = CyString::Number(num).PadNumber(2);
2844
	C_File *match = this->FindMatchingMod(f);
2845
 
2846
	// file link
2847
	if ( !f->GetData() )
2848
		f->ReadFromFile();
2849
 
2850
	f->ChangeBaseName(to);
2851
	if ( match )
2852
	{
2853
		// file link
2854
		if ( !match->GetData() )
2855
			match->ReadFromFile();
2856
		match->ChangeBaseName(to);
2857
	}
2858
}
2859
 
2860
C_File *CBaseFile::FindMatchingMod(C_File *f)
2861
{
2862
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2863
	{
2864
		if ( node->Data()->GetFileType() != FILETYPE_MOD )
2865
			continue;
2866
 
2867
		if ( f->GetFileExt().Compare(node->Data()->GetFileExt()) )
2868
			continue;
2869
 
2870
		if ( f->GetBaseName().Compare(node->Data()->GetBaseName()) )
2871
			return node->Data();
2872
	}
2873
 
2874
	return NULL;
2875
}
2876
 
2877
void CBaseFile::RenameFile(C_File *f, CyString baseName)
2878
{
2879
	if ( f->GetFileType() == FILETYPE_MOD )
2880
	{
2881
		C_File *match = this->FindMatchingMod(f);
2882
		if ( match )
2883
			match->ChangeBaseName(baseName);
2884
	}
2885
 
2886
	// need to edit the file
2887
	if ( f->GetFileType() == FILETYPE_SCRIPT || f->GetFileType() == FILETYPE_UNINSTALL )
2888
		f->RenameScript(baseName);
2889
 
2890
	f->ChangeBaseName(baseName);
2891
}
2892
 
2893
CyString CBaseFile::CreateUpdateFile(CyString dir)
2894
{
50 cycrow 2895
	CyString file = this->GetNameValidFile() + "_" + this->author() + ".dat";
6 cycrow 2896
	file.RemoveChar(' ');
2897
 
2898
	CyStringList write;
50 cycrow 2899
	write.PushBack(CyString("Package: ") + this->name());
2900
	write.PushBack(CyString("Author: ") + this->author());
2901
	write.PushBack(CyString("Version: ") + this->version());
111 cycrow 2902
	write.PushBack(CyString("File: ") + CFileIO(this->filename()).filename());
6 cycrow 2903
 
2904
	CFileIO File(dir + "/" + file);
2905
	if ( File.WriteFile(&write) )
102 cycrow 2906
		return File.fullFilename();
6 cycrow 2907
	return NullString;
2908
}
2909
 
2910
CyString CBaseFile::ErrorString(int error, CyString errorStr)
2911
{
2912
	if ( error == SPKERR_NONE ) return NullString;
2913
 
2914
	CyString err;
2915
 
2916
	switch(error)
2917
	{
2918
		case SPKERR_MALLOC:
2919
			err = "Memory Failed";
2920
			break;
2921
		case SPKERR_FILEOPEN:
2922
			err = "Failed to open file";
2923
			break;
2924
		case SPKERR_FILEREAD:
2925
			err = "Failed to read file";
2926
			break;
2927
		case SPKERR_UNCOMPRESS:
2928
			err = "Failed to Uncompress";
2929
			break;
2930
		case SPKERR_WRITEFILE:
2931
			err = "Failed to write file";
2932
			break;
2933
		case SPKERR_CREATEDIRECTORY:
2934
			err = "Failed to create directory";
2935
			break;
2936
		case SPKERR_FILEMISMATCH:
2937
			err = "File count mismatch";
2938
			break;
2939
	}
2940
 
2941
	if ( !err.Empty() )
2942
	{
2943
		if ( !errorStr.Empty() )
2944
		{
2945
			err += " (";
2946
			err += errorStr + ")";
2947
		}
2948
		return err;
2949
	}
2950
 
2951
	return CyString((long)error);
2952
}
2953
 
2954
bool CBaseFile::SaveToArchive(CyString filename, int game, CProgressInfo *progress)
2955
{
2956
	TCHAR buf[5000];
2957
	wsprintf(buf, L"%hs", filename.c_str());
2958
 
2959
	HZIP hz = CreateZip(buf, 0);
2960
	if ( !hz ) return false;
2961
 
2962
	// read files and compress
2963
	ReadAllFilesToMemory();
2964
	if ( !UncompressAllFiles(progress) )
2965
	{
2966
		CloseZip(hz);
2967
		return false;
2968
	}
2969
 
2970
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2971
	{
2972
		if ( game != -1 ) {
2973
			if ( game && node->Data()->GetGame() && node->Data()->GetGame() != game )
2974
				continue;
2975
			if ( !game && node->Data()->GetGame() )
2976
				continue;
2977
		}
2978
		CyString fname = node->Data()->GetNameDirectory(this);
2979
		// create the directory
2980
		wsprintf(buf, L"%hs", fname.c_str());
2981
		ZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());
2982
	}
2983
 
109 cycrow 2984
	// if its a ship, then add any generated files
2985
	this->addGeneratedFiles(hz);
2986
 
6 cycrow 2987
	// add the data file
2988
	CyStringList list;
2989
	if ( this->GeneratePackagerScript(false, &list, true) )
2990
	{
2991
		if ( CFileIO("test.tmp").WriteFile(&list) )
2992
		{
2993
			ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");
52 cycrow 2994
			CFileIO::Remove("test.tmp");
6 cycrow 2995
		}
2996
	}
2997
 
2998
	CloseZip(hz);
2999
 
3000
	return true;
3001
}
3002
 
13 cycrow 3003
int CBaseFile::GetGameFromString(const Utils::String &sGame)
6 cycrow 3004
{
3005
	int iGame = GAME_ALL;
3006
	if ( sGame.Compare("ALL") )
3007
		iGame = GAME_ALL;
3008
	else if ( sGame.Compare("X3") )
3009
		iGame = GAME_X3;
3010
	else if ( sGame.Compare("X2") )
3011
		iGame = GAME_X2;
3012
	else if ( sGame.Compare("X3TC") )
3013
		iGame = GAME_X3TC;
3014
	else if ( sGame.Compare("X3AP") )
3015
		iGame = GAME_X3AP;
3016
	else if ( sGame.Compare("XREBIRTH") )
3017
		iGame = GAME_XREBIRTH;
13 cycrow 3018
	else if ( sGame.isNumber() )
3019
		iGame = sGame;
6 cycrow 3020
 
3021
	return iGame;
3022
}
3023
 
13 cycrow 3024
Utils::String CBaseFile::ConvertGameToString(int iGame)
6 cycrow 3025
{
13 cycrow 3026
	Utils::String game = "ALL";
6 cycrow 3027
 
3028
	switch(iGame) {
3029
		case GAME_ALL:
3030
			game = "ALL";
3031
			break;
3032
		case GAME_X2:
3033
			game = "X2";
3034
			break;
3035
		case GAME_X3:
3036
			game = "X3";
3037
			break;
3038
		case GAME_X3TC:
3039
			game = "X3TC";
3040
			break;
3041
		case GAME_X3AP:
3042
			game = "X3AP";
3043
			break;
3044
		case GAME_XREBIRTH:
3045
			game = "XREBIRTH";
3046
			break;
3047
		default:
3048
			game = (long)iGame;
3049
	}
3050
 
3051
	return game;
3052
}
3053
 
3054
bool CBaseFile::IsGameInPackage(int game)
3055
{
3056
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3057
		if ( node->Data()->GetGame() == game )
3058
			return true;
3059
	}
3060
 
3061
	return false;
3062
}
3063
 
3064
bool CBaseFile::IsAnyGameInPackage()
3065
{
3066
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3067
		if ( node->Data()->GetGame() )
3068
			return true;
3069
	}
3070
 
3071
	return false;
3072
}
3073
 
88 cycrow 3074
Utils::String builtInWares()
3075
{
3076
	Utils::String str;
3077
	str += "28;0;0;0;0;59;5753;0;35714;1;1;0;35714;-100000;0;0;SS_WARE_SW_NEW1;\n";
3078
	str += "28;0;0;0;0;60;5763;0;33232;1;1;0;33232;0;1043;0;SS_WARE_SW_NEW2;\n";
3079
	str += "28;0;0;0;0;61;5773;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW3;\n";
3080
	str += "28;0;0;0;0;62;5783;0;56;1;1;0;56;-100000;0;0;SS_WARE_SW_NEW4;\n";
3081
	str += "28;0;0;0;0;63;5793;0;88;1;1;0;88;-100000;0;0;SS_WARE_SW_NEW5;\n";
3082
	str += "28;0;0;0;0;64;5803;0;283;1;1;0;283;-100000;0;0;SS_WARE_SW_NEW6;\n";
3083
	str += "28;0;0;0;0;65;5813;0;383;1;1;0;383;-100000;0;0;SS_WARE_SW_NEW7;\n";
3084
	str += "28;0;0;0;0;66;5823;0;1389;1;1;0;1389;-100000;1043;0;SS_WARE_SW_NEW8;\n";
3085
	str += "28;0;0;0;0;67;5833;0;3396;1;1;0;3396;-100000;0;0;SS_WARE_SW_NEW9;\n";
3086
	str += "28;0;0;0;0;68;5843;0;4215;1;1;0;4215;-100000;0;0;SS_WARE_SW_NEW10;\n";
3087
	str += "28;0;0;0;0;69;5853;0;5635;1;1;0;5635;-100000;0;0;SS_WARE_SW_NEW11;\n";
3088
	str += "28;0;0;0;0;70;5863;0;65735;1;1;0;65735;-100000;0;0;SS_WARE_SW_NEW12;\n";
3089
	str += "28;0;0;0;0;71;5873;0;17857;1;1;0;17857;333;1043;0;SS_WARE_SW_NEW13;\n";
3090
	str += "28;0;0;0;0;72;5883;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW14;\n";
3091
	str += "28;0;0;0;0;73;5893;0;324515;1;1;0;324515;-100000;0;0;SS_WARE_SW_NEW15;\n";
3092
	str += "28;0;0;0;0;74;5903;0;638508;1;1;0;638508;-100000;0;0;SS_WARE_SW_NEW16;\n";
3093
	str += "28;0;0;0;0;75;5913;0;225755;1;1;0;225755;-100000;0;0;SS_WARE_SW_NEW17;\n";
3094
	str += "28;0;0;0;0;76;5923;0;1931535;1;1;0;1931535;1000;0;0;SS_WARE_SW_NEW18;\n";
3095
	str += "28;0;0;0;0;77;5933;0;2209150;1;1;0;2209150;-100000;0;0;SS_WARE_SW_NEW19;\n";
3096
	str += "28;0;0;0;0;78;5943;0;6727565;1;1;0;6727565;-100000;0;0;SS_WARE_SW_NEW20;\n";
3097
	str += "28;0;0;0;0;85;9999;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_1;\n";
3098
	str += "28;0;0;0;0;86;15053;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_2;\n";
3099
	str += "28;0;0;0;0;87;15063;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_3;\n";
3100
	str += "28;0;0;0;0;88;15073;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_4;\n";
3101
	str += "28;0;0;0;0;89;15083;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_5;\n";
3102
	str += "28;0;0;0;0;90;15093;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_6;\n";
3103
 
3104
	return str;
3105
}
3106
 
3107
void CBaseFile::_addWaresToList(int iLang, CLinkList<SWareEntry> &list, const Utils::String &wares, enum WareTypes eType)
3108
{
3109
	int totalWares = 0;
3110
	Utils::String *w = wares.tokenise("\n", &totalWares);
3111
 
3112
	for(int i = 0; i < totalWares; i++) {
3113
		int textId = w[i].token(";", 7).toLong();
3114
		int useLang = iLang;
3115
		if ( !_pTextDB->exists(useLang, 17, textId) )
3116
			useLang = 44;
3117
		if ( !_pTextDB->exists(useLang, 17, textId) )
3118
			useLang = 49;
3119
		if ( _pTextDB->exists(useLang, 17, textId) ) {	
3120
			SWareEntry *ware = new SWareEntry;
3121
			ware->name = _pTextDB->get(useLang, 17, textId);
3122
			ware->description = _pTextDB->get(useLang, 17, textId + 1);
3123
			ware->id = w[i].token(";", -2);
3124
			ware->relval = w[i].token(";", 9).toLong();
3125
			ware->notority = w[i].token(";", 14).toLong();
3126
			ware->type = eType;
3127
			ware->position = i;
89 cycrow 3128
			ware->package = this;
88 cycrow 3129
			list.push_back(ware);
3130
		}
3131
	}
3132
 
3133
	CLEANSPLIT(w, totalWares);
3134
}
3135
 
3136
bool CBaseFile::readWares(int iLang, CLinkList<SWareEntry> &list, const Utils::String &empWares)
3137
{
3138
	_pTextDB->setLanguage(iLang);
3139
 
3140
	// now go through all emp wares and get the ones we have text for
3141
	_addWaresToList(iLang, list, empWares, Ware_EMP);
3142
	_addWaresToList(iLang, list, builtInWares(), Ware_BuiltIn);
3143
 
89 cycrow 3144
	return true;
3145
}
88 cycrow 3146
 
89 cycrow 3147
bool CBaseFile::_readCommands(int iLang, int iStartID, CLinkList<SCommandSlot> &list)
3148
{
3149
	_pTextDB->setLanguage(iLang);
3150
 
3151
	for(int i = 2; i <= 13; i++) {
3152
		for(int j = 0; j < 64; j++) {
3153
			int id = (i * 100) + j;
3154
			if ( _pTextDB->exists(iLang, iStartID + 2, id) ) {
3155
				SCommandSlot *slot = new SCommandSlot;
3156
				list.push_back(slot);
3157
 
3158
				slot->id = _pTextDB->get(iLang, iStartID, id);
3159
				slot->name = _pTextDB->get(iLang, iStartID + 2, id);
3160
				slot->shortName = _pTextDB->get(iLang, iStartID + 3, id);
3161
				slot->info = _pTextDB->get(iLang, iStartID + 14, id);
3162
				slot->slot = id;
3163
				slot->package = this;
3164
 			}
3165
		}
3166
	}
3167
 
3168
	for(int i = 1400; i <= 2000; i++) {
3169
		if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {
3170
			SCommandSlot *slot = new SCommandSlot;
3171
			list.push_back(slot);
3172
 
3173
			slot->id = _pTextDB->get(iLang, iStartID, i);
3174
			slot->name = _pTextDB->get(iLang, iStartID + 2, i);
3175
			slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);
3176
			slot->info = _pTextDB->get(iLang, iStartID + 14, i);
3177
			slot->slot = i;
3178
			slot->package = this;
3179
		}
3180
	}
3181
 
3182
	for(int i = 6000; i <= 9999; i++) {
3183
		if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {
3184
			SCommandSlot *slot = new SCommandSlot;
3185
			list.push_back(slot);
3186
 
3187
			slot->id = _pTextDB->get(iLang, iStartID, i);
3188
			slot->name = _pTextDB->get(iLang, iStartID + 2, i);
3189
			slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);
3190
			slot->info = _pTextDB->get(iLang, iStartID + 14, i);
3191
			slot->slot = i;
3192
			slot->package = this;
3193
		}
3194
	}
3195
 
88 cycrow 3196
	return true;
3197
}
3198
 
89 cycrow 3199
bool CBaseFile::readWingCommands(int iLang, CLinkList<SCommandSlot> &list)
3200
{
3201
	return _readCommands(iLang, 2028, list);
3202
}
3203
 
3204
bool CBaseFile::readCommands(int iLang, CLinkList<SCommandSlot> &list)
3205
{
3206
	return _readCommands(iLang, 2008, list);
3207
}
3208
 
6 cycrow 3209
int CBaseFile::FindFirstGameInPackage()
3210
{
3211
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3212
		if ( node->Data()->GetGame() )
3213
			return node->Data()->GetGame();
3214
	}
3215
 
3216
	return 0;
3217
}
3218
bool CBaseFile::IsMultipleGamesInPackage()
3219
{
3220
	int game = 0;
3221
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
3222
		if ( node->Data()->GetGame() ) {
3223
			if ( game != node->Data()->GetGame() )
3224
				return true;
3225
			game = node->Data()->GetGame();
3226
		}
3227
	}
3228
 
3229
	return false;
3230
}