Subversion Repositories spk

Rev

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