Subversion Repositories spk

Rev

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

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