Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
 
2
#include "VirtualFileSystem.h"
3
#include "File_IO.h"
4
#include "CatFile.h"
35 cycrow 5
#include "XspFile.h"
1 cycrow 6
 
79 cycrow 7
#include "Packages.h"
8
 
35 cycrow 9
namespace SPK {
10
 
1 cycrow 11
CVirtualFileSystem::CVirtualFileSystem()
12
{
13
	m_bLoaded = false;
35 cycrow 14
	m_pMap = new FileList;
15
	m_pModMap = new FileList;
16
 
17
	m_pTexts = new CTextDB();
18
	m_pModTexts = new CTextDB();
19
 
1 cycrow 20
	m_sAddon = "";
35 cycrow 21
 
22
	m_iLang = 0;
1 cycrow 23
}
24
 
25
CVirtualFileSystem::~CVirtualFileSystem(void)
26
{
35 cycrow 27
	if ( m_pMap )		delete m_pMap;
28
	if ( m_pModMap )	delete m_pModMap;
29
 
30
	if ( m_pTexts )		delete m_pTexts;
31
	if ( m_pModTexts )  delete m_pModTexts;
1 cycrow 32
}
33
 
35 cycrow 34
void CVirtualFileSystem::setLanguage(int iLang)
1 cycrow 35
{
35 cycrow 36
	m_iLang = iLang;
37
}
38
 
39
bool CVirtualFileSystem::LoadFilesystem(const Utils::String &dir, int maxPatch)
40
{
41
	return this->LoadFilesystem(dir, "", maxPatch);
42
}
43
 
44
bool CVirtualFileSystem::LoadFilesystem(const Utils::String &dir, const Utils::String &mod, int maxPatch)
45
{
1 cycrow 46
	m_sDir = dir;
47
 
35 cycrow 48
	this->_clear();
1 cycrow 49
 
50
	int number = 1;
52 cycrow 51
	while ( CFileIO(CyString(dir) + "/" + CyString::Number(number).PadNumber(2) + ".cat").ExistsOld() )
1 cycrow 52
	{
58 cycrow 53
		if ( maxPatch && maxPatch < number ) break;
35 cycrow 54
		CyString file = CyString(dir) + "/" + CyString::Number(number).PadNumber(2);
52 cycrow 55
		if ( !CFileIO(file + ".dat").ExistsOld() )
1 cycrow 56
			break;
57
 
58
		CCatFile cat;
59
		if ( cat.Open(file + ".cat", m_sAddon, CATREAD_JUSTCONTENTS, false) == CATERR_NONE )
60
		{
43 cycrow 61
			for ( CListNode<SInCatFile> *c = cat.GetFiles()->Front(); c; c = c->next() ) {
62
				this->_addModFile(CFileIO(c->Data()->sFile).GetFullFilename().ToString(), CyString(file + ".cat").ToString(), m_pMap);
1 cycrow 63
				m_bLoaded = true;
64
			}
65
		}
66
		++number;
67
	}
68
 
43 cycrow 69
	// add all the files from the mod
35 cycrow 70
	if ( !mod.empty() )
71
		this->addMod(mod);
72
 
43 cycrow 73
	// now add all the extracted data
74
	this->_addDir(m_sDir, "");
75
 
1 cycrow 76
	return m_bLoaded;
77
}
78
 
43 cycrow 79
 
80
void CVirtualFileSystem::_addDir(const Utils::String &sStart, const Utils::String &sDir)
81
{
82
	CDirIO Dir(sStart + "/" + sDir);
83
	CyStringList *list = Dir.DirList();
84
	if ( list ) {
85
		for ( SStringList *strNode = list->Head(); strNode; strNode = strNode->next ) {
58 cycrow 86
			if ( CDirIO(Dir.Dir(strNode->str)).IsDir() ) _addDir(sStart, sDir + "/" + strNode->str.ToString());
43 cycrow 87
			else if ( CFileIO(strNode->str).CheckFileExtension("cat") ) continue;
88
			else if ( CFileIO(strNode->str).CheckFileExtension("dat") ) continue;
58 cycrow 89
			else this->_addFile(sDir + "/" + strNode->str.ToString(), Dir.File(strNode->str).ToString(), m_pMap);
43 cycrow 90
		}
91
	}
92
}
93
 
94
void CVirtualFileSystem::_addFile(const Utils::String &sFile, const Utils::String &sDest, FileList *pList)
95
{
58 cycrow 96
	Utils::String test = sFile.findReplace("\\", "/").findReplace("//", "/").removeIf(0, '/').lower();
97
	(*pList)[sFile.findReplace("\\", "/").findReplace("//", "/").removeIf(0, '/').lower()] = sDest.findReplace("//", "/");
43 cycrow 98
}
99
void CVirtualFileSystem::_addModFile(const Utils::String &sFile, const Utils::String &sMod, FileList *pList)
100
{
101
	this->_addFile(sFile, sMod + "::" + sFile, pList);
102
}
103
 
35 cycrow 104
bool CVirtualFileSystem::loadMod(const Utils::String &mod)
1 cycrow 105
{
106
	bool loaded = false;
35 cycrow 107
 
108
	if ( !m_pModMap ) m_pModMap = new FileList;
109
 
1 cycrow 110
	CCatFile cat;
111
	if ( CCatFile::Opened(cat.Open(mod, m_sAddon, CATREAD_JUSTCONTENTS, false), false) )
112
	{
43 cycrow 113
		for ( CListNode<SInCatFile> *c = cat.GetFiles()->Front(); c; c = c->next() ) {
114
			this->_addModFile(CFileIO(c->Data()->sFile).GetFullFilename().ToString(), mod, m_pModMap);
35 cycrow 115
			loaded = true;
116
		}
117
	}
118
 
119
	return loaded;
120
}
121
 
122
bool CVirtualFileSystem::addMod(const Utils::String &mod)
123
{
124
	bool loaded = false;
125
 
126
	if ( !m_pMap ) m_pMap = new FileList;
127
 
128
	CCatFile cat;
129
	if ( CCatFile::Opened(cat.Open(mod, m_sAddon, CATREAD_JUSTCONTENTS, false), false) )
130
	{
131
		for ( CListNode<SInCatFile> *c = cat.GetFiles()->Front(); c; c = c->next() )
132
		{
43 cycrow 133
			this->_addModFile(CFileIO(c->Data()->sFile).GetFullFilename().ToString(), mod, m_pMap);
1 cycrow 134
			loaded = true;
135
		}
136
	}
137
 
138
	return loaded;
139
}
140
 
35 cycrow 141
bool CVirtualFileSystem::textExists(int iLang, int iPage, int iID) const
1 cycrow 142
{
35 cycrow 143
	if ( m_pTexts ) {
144
		if ( m_pTexts->exists(iLang, iPage, iID) ) return m_pTexts->exists(iLang, iPage, iID);
145
	}
146
	if ( m_pModTexts ) {
147
		if ( m_pModTexts->exists(iLang, iPage, iID) ) return m_pModTexts->exists(iLang, iPage, iID);
148
	}
149
 
150
	return false;
1 cycrow 151
}
152
 
35 cycrow 153
Utils::String CVirtualFileSystem::findText(int iLang, int iPage, int iID) const
1 cycrow 154
{
35 cycrow 155
	if ( m_pTexts ) {
156
		if ( m_pTexts->exists(iLang, iPage, iID) ) return m_pTexts->get(iLang, iPage, iID);
157
	}
158
	if ( m_pModTexts ) {
159
		if ( m_pModTexts->exists(iLang, iPage, iID) ) return m_pModTexts->get(iLang, iPage, iID);
160
	}
1 cycrow 161
 
35 cycrow 162
	return Utils::String("ReadText") + (long)iPage + "-" + (long)iID;
163
}
43 cycrow 164
 
165
bool CVirtualFileSystem::isFileAvailable(const Utils::String &file)
35 cycrow 166
{
43 cycrow 167
	return !this->_findFile(file).empty();
168
}
169
 
170
Utils::String CVirtualFileSystem::_findFile(const Utils::String &file)
171
{
172
	Utils::String toFile = file.findReplace("\\", "/").lower();
173
 
35 cycrow 174
	if ( m_pModMap && !m_pModMap->empty() ) {
175
		if ( !m_sAddon.empty() ) {
43 cycrow 176
			FileListItr aitr = m_pModMap->find(CFileIO(m_sAddon + "/" + toFile).GetFullFilename().ToLower().c_str());
177
			if ( aitr == m_pModMap->end() ) aitr = m_pModMap->find(CFileIO(_convertExtension(m_sAddon + "/" + toFile)).GetFullFilename().ToLower().c_str());
35 cycrow 178
			if ( aitr != m_pModMap->end() ) return aitr->second;
179
		}
43 cycrow 180
		FileListItr itr = m_pModMap->find(CFileIO(toFile).GetFullFilename().ToLower().c_str());
181
		if ( itr == m_pModMap->end() ) itr = m_pModMap->find(CFileIO(_convertExtension(toFile)).GetFullFilename().ToLower().c_str());
35 cycrow 182
		if ( itr != m_pModMap->end() ) return itr->second;
183
	}
184
	else if ( m_pMap && !m_pMap->empty() ) {
185
		if ( !m_sAddon.empty() ) {
58 cycrow 186
			FileListItr aitr = m_pMap->find(CFileIO(m_sAddon + "/" + toFile).fullFilename().lower().c_str());
187
			if ( aitr == m_pMap->end() ) aitr = m_pMap->find(CFileIO(_convertExtension(m_sAddon + "/" + file)).fullFilename().lower().c_str());
35 cycrow 188
			if ( aitr != m_pMap->end() ) return aitr->second;
189
		}
190
		FileListItr itr = m_pMap->find(CFileIO(file).GetFullFilename().ToLower().c_str());
191
		if ( itr == m_pMap->end() ) itr = m_pMap->find(CFileIO(_convertExtension(file)).GetFullFilename().ToLower().c_str());
192
		if ( itr != m_pMap->end() ) return itr->second;
193
	}
194
	return "";
195
}
196
 
58 cycrow 197
Utils::String CVirtualFileSystem::_extractFromCat(const Utils::String &sCat, const Utils::String &sFile, const Utils::String &sTo)
35 cycrow 198
{
58 cycrow 199
	CCatFile catFile;
200
	if ( catFile.Open(sCat, m_sAddon, CATREAD_CATDECRYPT, false) == CATERR_NONE )
201
	{
202
		// check for the file
203
		if ( catFile.ExtractFile(sFile, sTo) ) return sTo;
204
		if ( catFile.Error() == CATERR_INVALIDDEST || catFile.Error() == CATERR_CANTCREATEDIR ) {
205
			if ( catFile.ExtractFile(sFile) ) return sFile;
206
		}
207
	}
208
 
209
	return "";
210
}
211
 
212
Utils::String CVirtualFileSystem::_extract(const Utils::String &sFile, const Utils::String &sTo)
213
{
214
	// check if we need to unpack the file
215
	if ( CCatFile::CheckPackedExtension(sFile) ) {
216
		CFileIO File(sFile);
217
		C_File f(CyString(File.fullFilename()));
218
		if ( !f.readFromFile(File) ) return "";
219
		if ( !f.UnPCKFile() ) return "";
220
		if ( !f.WriteToFile(sTo) ) return "";
221
		return sTo;
222
	}
223
	return sFile;
224
}
225
 
226
Utils::String CVirtualFileSystem::ExtractGameFile(const Utils::String &file, const Utils::String &to)
227
{
43 cycrow 228
	Utils::String sIn = _findFile(file);
229
	Utils::String sFile = file;
230
 
58 cycrow 231
	if ( sIn.empty() ) return "";
35 cycrow 232
 
43 cycrow 233
	if ( sIn.isin("::") ) {
234
		sFile = sIn.token("::", 2);
235
		sIn = sIn.token("::", 1);
58 cycrow 236
		return _extractFromCat(sIn, sFile, to);
43 cycrow 237
	}
58 cycrow 238
 
239
	return _extract(sIn, to);
1 cycrow 240
}
241
 
35 cycrow 242
Utils::String CVirtualFileSystem::_convertExtension(const Utils::String &sFile)
243
{
244
	CFileIO File(sFile);
245
	if ( File.CheckFileExtension("pck") ) {
246
		return File.ChangeFileExtension("xml").ToString();
247
	}
248
	else if ( File.CheckFileExtension("xml") ) {
249
		return File.ChangeFileExtension("pck").ToString();
250
	}
251
	else if ( File.CheckFileExtension("pbb") ) {
252
		return File.ChangeFileExtension("bob").ToString();
253
	}
254
	else if ( File.CheckFileExtension("bob") ) {
255
		return File.ChangeFileExtension("pbb").ToString();
256
	}
257
	else if ( File.CheckFileExtension("pbd") ) {
258
		return File.ChangeFileExtension("bod").ToString();
259
	}
260
	else if ( File.CheckFileExtension("bod") ) {
261
		return File.ChangeFileExtension("pbd").ToString();
262
	}
263
 
264
	return sFile;
265
}
266
 
267
CyStringList *CVirtualFileSystem::GetTShipsEntries()
268
{
58 cycrow 269
	Utils::String sTo = this->ExtractGameFile("types/tships.pck", "tships.txt");
270
	if ( !sTo.empty() ) {
271
		CFileIO TShips(sTo);
52 cycrow 272
		if ( TShips.exists() )
35 cycrow 273
		{
274
			CyStringList *lines = TShips.ReadLinesStr();
275
			if ( lines )
276
			{
277
				// remove any commands, blank lines, and start
278
				// and put the id as the data
279
				int entries = -1;
280
				for ( SStringList *str = lines->Head(); str; str = str->next )
281
				{
282
					str->str.RemoveFirstSpace();
283
					str->str.RemoveChar(9);
284
					str->str.RemoveChar('\r');
285
					str->str.RemoveChar('\n');
286
					if ( str->str.Empty() )
287
					{
288
						str->remove = true;
289
						continue;
290
					}
291
 
292
					if ( str->str[0] == '/' )
293
					{
294
						str->remove = true;
295
						continue;
296
					}
297
 
298
					if ( entries == -1 )
299
					{
300
						entries = str->str.GetToken(";", 2, 2).ToInt();
301
						str->remove = true;
302
						continue;
303
					}
304
 
305
					// hopefully we now have a valid tships line
306
					int num = -1;
307
					while ( str->data.Empty() )
308
						str->data = str->str.GetToken(";", num--, (num + 2));
309
				}
310
			}
311
			// remove the tmp file
52 cycrow 312
			TShips.remove();
35 cycrow 313
 
314
			if ( lines )
315
				lines->RemoveMarked();
316
			return lines;
317
		}
318
	}
319
 
320
	return NULL;
321
}
322
 
323
C_File *CVirtualFileSystem::extractGameFileToPackage(CBaseFile *pPackage, const Utils::String &sFile, FileType iFileType)
324
{
325
	return this->extractGameFileToPackage(pPackage, sFile, iFileType, sFile);
326
}
327
 
328
C_File *CVirtualFileSystem::extractGameFileToPackage(CBaseFile *pPackage, const Utils::String &sFile, FileType iFileType, const Utils::String &sTo)
329
{
79 cycrow 330
	Utils::String to = this->ExtractGameFile(sFile, CPackages::tempDirectory() + "tmp.dat");
58 cycrow 331
	if ( !to.empty() ) {
332
		CFileIO File(to);
35 cycrow 333
 
334
		C_File *f = pPackage->AddFile(CFileIO(sTo).GetFilename(), CFileIO(sTo).GetDir(), iFileType);
335
		if ( f ) {
79 cycrow 336
			if ( f->ReadFromFile(CPackages::GetTempDirectory() + "tmp.dat") ) {
52 cycrow 337
				File.remove();
35 cycrow 338
				return f;
339
			}
340
		}
341
 
52 cycrow 342
		File.remove();
35 cycrow 343
	}
344
 
345
	return NULL;
346
}
347
 
348
Utils::String CVirtualFileSystem::getTShipsEntry(const Utils::String &sId)
349
{
350
	CyStringList *ships = this->GetTShipsEntries();
351
	if ( ships )
352
	{
353
		SStringList *node = ships->FindData(CyString(sId).upper());
354
		if ( node )
355
			return node->str.ToString();
356
	}
357
	return "";
358
}
359
 
360
void CVirtualFileSystem::extractTexts(CXspFile *pPackage, int textId)
361
{
362
	//TODO: check for better finding of files in map
363
	for ( FileListItr itr = m_pMap->begin(); itr != m_pMap->end(); ++itr ) {
364
		Utils::String str = itr->first;
365
 
366
		if ( !m_sAddon.empty() ) {
367
			if ( !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "/t/") && !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "\\t\\") )
368
				continue;
369
		}
370
		else {
371
			if ( !str.left(2).Compare("t\\") && !str.left(2).Compare("t/") && !str.left(8).Compare("addon\t\\") && !str.left(8).Compare("addon/t/") )
372
				continue;
373
		}
374
 
79 cycrow 375
		Utils::String sTo = this->ExtractGameFile(str, CPackages::tempDirectory() + "tmp.dat");
58 cycrow 376
		if ( !sTo.empty() ) {
377
			pPackage->AddTextFromFile(sTo, textId);
378
			CFileIO::Remove(sTo);
35 cycrow 379
		}
380
	}
381
}
382
 
383
void CVirtualFileSystem::updateTexts(int iFromPage, int iToPage)
384
{
385
	this->_updateTexts(iFromPage, iToPage, m_pMap, m_pTexts);
386
}
387
void CVirtualFileSystem::updateTexts(int iPage)
388
{
389
	this->_updateTexts(iPage, iPage, m_pMap, m_pTexts);
390
}
391
void CVirtualFileSystem::updateModTexts(int iFromPage, int iToPage)
392
{
393
	this->_updateTexts(iFromPage, iToPage, m_pModMap, m_pModTexts);
394
}
395
void CVirtualFileSystem::updateModTexts(int iPage)
396
{
397
	this->_updateTexts(iPage, iPage, m_pModMap, m_pModTexts);
398
}
399
 
400
void CVirtualFileSystem::_clear()
401
{
402
	m_bLoaded = false;
403
 
404
	if ( m_pMap ) delete m_pMap;
405
	m_pMap = new FileList;
406
	if ( m_pModMap ) delete m_pModMap;
407
	m_pModMap = new FileList;
408
}
409
 
410
void CVirtualFileSystem::_updateTexts(int iFromPage, int iToPage, FileList *pFileList, CTextDB *pTextList)
411
{
412
	// read all text files
413
	for ( FileListItr itr = pFileList->begin(); itr != pFileList->end(); ++itr ) {
414
		Utils::String str = itr->first;
415
 
416
		if ( !m_sAddon.empty() ) {
417
			if ( !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "/t/") && !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "\\t\\") )
418
				continue;
419
		}
420
		else {
421
			if ( !str.left(2).Compare("t\\") && !str.left(2).Compare("t/") )
422
				continue;
423
		}
424
 
79 cycrow 425
		Utils::String sTo = this->ExtractGameFile(str, CPackages::tempDirectory() + "tmp.dat");
58 cycrow 426
		if ( !sTo.empty() ) {
35 cycrow 427
			// add all texts into the map, id=(pageid, tid) data=text
57 cycrow 428
			Utils::String baseFile = CFileIO(str).baseName();
35 cycrow 429
			int lang = (baseFile.isin("-L")) ? baseFile.right(3) : baseFile.truncate(-4);
430
 
431
			if ( m_iLang && lang != m_iLang ) continue;
432
			// open the text file to add
58 cycrow 433
			pTextList->parseTextFile(iFromPage, iToPage, sTo, lang);
35 cycrow 434
		}
435
	}
436
}
437
 
78 cycrow 438
void CVirtualFileSystem::clearMods(bool bIncludeStandard)
35 cycrow 439
{
78 cycrow 440
	if ( bIncludeStandard ) {
441
		if ( m_pTexts ) delete m_pTexts;
442
		m_pTexts = new CTextDB();
443
	}
444
 
35 cycrow 445
	if ( m_pModTexts ) delete m_pModTexts;
446
	m_pModTexts = new CTextDB();
447
}
448
 
449
bool CVirtualFileSystem::loadShipData(CyStringList *list)
450
{
451
	bool ret = false;
452
 
79 cycrow 453
	Utils::String sTo = this->ExtractGameFile("types/TShips.pck", CPackages::tempDirectory() + "tmp.dat");
58 cycrow 454
	if ( !sTo.empty() ) {
455
		CFileIO File(sTo);
35 cycrow 456
		CyStringList *lines = File.ReadLinesStr();
457
		if ( lines )
458
		{
459
			bool readFirst = false;
460
			for ( SStringList *str = lines->Head(); str; str = str->next )
461
			{
462
				if ( str->str.Empty() )
463
					continue;
464
				str->str.RemoveChar('\r');
465
				str->str.RemoveChar(9);
466
				str->str.RemoveFirstSpace();
467
				if ( str->str.Empty() )
468
					continue;
469
				if ( str->str[0] == '/' || str->str[0] == '#' )
470
					continue;
471
 
472
				if ( !readFirst )
473
					readFirst = true;
474
				else
475
				{
476
					CyString t = str->str.GetToken(";", -2);
477
					while ( t.Right(1) == ";" )
478
						t.Truncate((int)t.Length() - 1);
479
					list->PushBack(t, str->str);
480
				}
481
			}
482
 
483
			delete lines;
484
			ret = true;
485
		}
486
 
52 cycrow 487
		File.remove();
35 cycrow 488
	}
489
 
490
	return ret;
491
}
492
 
493
 
494
} //NAMESPACE