Subversion Repositories spk

Rev

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