Subversion Repositories spk

Rev

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

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