Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
#include "XspFile.h"
2
#include "File_IO.h"
3
#include "Packages.h"
4
#include "CatFile.h"
5
 
109 cycrow 6
#define ADDSECTIONLIST(T, L) for(CListNode<T> *node = L.Front(); node; node = node->next()) \
7
		_addSection(list, node->Data()->sSection, node->Data()->sData);
8
 
9
#define GENERATESECTION(F, T, L) if ( !L.empty() ) {						\
10
									type = F;								\
113 cycrow 11
									Utils::CList<STypesSection> list;		\
109 cycrow 12
									ADDSECTIONLIST(T, L);					\
13
									data = CXspFile::TypesListToString(list, true); \
14
								}
15
 
170 cycrow 16
#define GENERATESTRINGSECTION(F, L, FIRST) if ( !L.empty() ) {				\
109 cycrow 17
									type = F;								\
113 cycrow 18
									Utils::CList<STypesSection> list;		\
19
									_addDataSection(L, list, FIRST);		\
109 cycrow 20
									data = CXspFile::TypesListToString(list, true); \
21
								}
22
 
23
 
1 cycrow 24
CXspFile::CXspFile () : CBaseFile()
25
{
26
	SetDefaults ();
27
}
28
 
29
void CXspFile::Delete ()
30
{
31
	CBaseFile::Delete();
32
	m_pSceneFile = m_pCockpitFile = NULL;
33
 
34
	// delete lists
35
	m_lMissileMasks.MemoryClear();
36
	m_lWeaponMasks.MemoryClear();
37
 
38
	m_lMissileMasks.destroy();
39
	m_lWeaponMasks.destroy();
40
 
41
	for ( CListNode<SCockpit> *n = m_lCockpit.Front(); n; n = n->next() )
42
		n->Data()->lWeaponMask.MemoryClear();
43
	m_lCockpit.MemoryClear();
44
	m_lCockpit.destroy();
165 cycrow 45
	_lCutData.clear();
170 cycrow 46
	_lBodies.clear();
47
	_lAnimations.clear();
1 cycrow 48
}
49
 
50
void CXspFile::SetDefaults ()
51
{
52
	CBaseFile::SetDefaults ();
53
 
54
	m_pSceneFile = m_pCockpitFile = NULL;
55
	m_bLanguageText = m_bExistingShip = false;
56
	m_iOrgDesc = 0;
57
 
58
	m_iShipyard = SHIPYARD_NONE;
59
}
60
 
216 cycrow 61
void CXspFile::addText(int id, const Utils::WString &name, const Utils::WString &desc)
1 cycrow 62
{
63
	// first check if theres an existing id
64
	SText *newtext = NULL;
65
	for ( SText *t = m_lText.First(); t; t = m_lText.Next() )
66
	{
67
		if ( t->iId == id )
68
		{
69
			newtext = t;
70
			break;
71
		}
72
	}
73
 
74
	if ( !newtext )
75
	{
76
		newtext = new SText;
77
		newtext->iId = id;
78
		m_lText.push_back ( newtext );
79
	}
80
 
81
	newtext->sName = name;
82
	newtext->sDesc = desc;
83
 
50 cycrow 84
	_changed();
1 cycrow 85
}
86
 
87
void CXspFile::RemoveText(int id)
88
{
89
	for ( SText *t = m_lText.First(); t; t = m_lText.Next() )
90
	{
91
		if ( t->iId == id )
92
		{
50 cycrow 93
			_changed();
1 cycrow 94
			m_lText.RemoveCurrent();
95
			return;
96
		}
97
	}
98
}
99
 
216 cycrow 100
void CXspFile::addDummy(const Utils::WString &section, const Utils::WString &data)
1 cycrow 101
{
102
	SDummy *d = new SDummy;
103
	d->sData = data;
104
	d->sSection = section;
105
 
216 cycrow 106
	if ( d->sData.right(1) != L";" )
107
		d->sData += L";";
1 cycrow 108
 
109
	m_lDummy.push_back ( d );
110
 
50 cycrow 111
	_changed();
1 cycrow 112
}
113
 
216 cycrow 114
void CXspFile::addComponent(const Utils::WString &section, const Utils::WString &section2, const Utils::WString &data)
1 cycrow 115
{
116
	SComponent *c = new SComponent;
117
	c->sData = data;
118
	c->sSection = section;
119
	c->sSection2 = section2;
120
 
216 cycrow 121
	if ( c->sData.right(1) != L";" )
122
		c->sData += L";";
1 cycrow 123
 
124
	m_lComponent.push_back ( c );
125
 
50 cycrow 126
	_changed();
1 cycrow 127
}
128
 
129
void CXspFile::AddWeaponMask ( int game, int mask )
130
{
131
	// first check if we have one for the game
132
	SWeaponMask *m = NULL;
133
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
134
	{
135
		if ( node->Data()->iGame == game )
136
		{
137
			m = node->Data();
138
			break;
139
		}
140
	}
141
 
142
	// not found, create one
143
	if ( !m )
144
	{
145
		m = new SWeaponMask;
146
		m_lWeaponMasks.push_back(m);
147
		m->iGame = game;
148
	}
149
 
150
	m->iMask = mask;
50 cycrow 151
	_changed();
1 cycrow 152
}
153
void CXspFile::AddMissileMask ( int game, int mask )
154
{
155
	// first check if we have one for the game
156
	SWeaponMask *m = NULL;
157
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
158
	{
159
		if ( node->Data()->iGame == game )
160
		{
161
			m = node->Data();
162
			break;
163
		}
164
	}
165
 
166
	// not found, create one
167
	if ( !m )
168
	{
169
		m = new SWeaponMask;
170
		m_lMissileMasks.push_back(m);
171
		m->iGame = game;
172
	}
173
 
174
	m->iMask = mask;
50 cycrow 175
	_changed();
1 cycrow 176
}
177
 
178
bool CXspFile::IsValid ()
179
{
50 cycrow 180
	if ( this->name().empty() )
1 cycrow 181
		return false;
50 cycrow 182
	if ( this->author().empty() )
1 cycrow 183
		return false;
184
 
185
	return true;
186
}
187
 
207 cycrow 188
Utils::WString CXspFile::createValuesLine() const
1 cycrow 189
{
207 cycrow 190
	Utils::WString values = CBaseFile::createValuesLine ();
1 cycrow 191
 
217 cycrow 192
	values += L"Data: " + m_sData + L"\n";
193
	values += L"ID: " + m_sID + L"\n";
1 cycrow 194
 
195
	if ( m_bLanguageText )
207 cycrow 196
		values += L"LanguageText\n";
1 cycrow 197
	if ( m_bExistingShip )
207 cycrow 198
		values += L"ExistingShip\n";
199
	values += Utils::WString(L"OrgDesc: ") + (long)m_iOrgDesc + L"\n";
200
	values += Utils::WString(L"Shipyard: ") + (long)m_iShipyard + L"\n";
1 cycrow 201
 
14 cycrow 202
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() ) {
203
		SCockpit *cockpit = node->Data();
207 cycrow 204
		values += Utils::WString(L"CockpitNew: ") + (long)cockpit->lWeaponMask.size();
14 cycrow 205
		for ( CListNode<SWeaponMask> *wNode = cockpit->lWeaponMask.Front(); wNode; wNode = wNode->next() ) {
207 cycrow 206
			values += L":";
14 cycrow 207
			values += (long)wNode->Data()->iGame;
207 cycrow 208
			values += L":";
14 cycrow 209
			values += (long)wNode->Data()->iMask;
1 cycrow 210
		}
207 cycrow 211
		values += L" ";
216 cycrow 212
		values += cockpit->sCockpit + L"\n";
1 cycrow 213
	}
214
 
14 cycrow 215
	for ( CListNode<SText> *tNode = m_lText.Front(); tNode; tNode = tNode->next() )
216 cycrow 216
		values += Utils::WString(L"Text: ") + (long)tNode->Data()->iId + L"|" + tNode->Data()->sName.findReplace(L"|", L"<::PiPe::>") + L"|" + tNode->Data()->sDesc + L"\n";
1 cycrow 217
 
14 cycrow 218
	for ( CListNode<SComponent> *cNode = m_lComponent.Front(); cNode; cNode = cNode->next() )
216 cycrow 219
		values += L"Component: " + cNode->Data()->sData.findReplace(L"|", L"<::PiPe::>") + L"|" + cNode->Data()->sSection.findReplace(L"|", L"<::PiPe::>") + L"|" + cNode->Data()->sSection2 + L"\n";
1 cycrow 220
 
14 cycrow 221
	for ( CListNode<SDummy> *dNode = m_lDummy.Front(); dNode; dNode = dNode->next() )
216 cycrow 222
		values += L"Dummy: " + dNode->Data()->sData.findReplace(L"|", L"<::PiPe::>") + L"|" + dNode->Data()->sSection + L"\n";
1 cycrow 223
 
14 cycrow 224
	for ( CListNode<SWeaponMask> *wNode = m_lWeaponMasks.Front(); wNode; wNode = wNode->next() )
207 cycrow 225
		values += Utils::WString(L"WeaponMask: ") + (long)wNode->Data()->iGame + L" " + (long)wNode->Data()->iMask + L"\n";
14 cycrow 226
	for ( CListNode<SWeaponMask> *mNode = m_lMissileMasks.Front(); mNode; mNode = mNode->next() )
207 cycrow 227
		values += Utils::WString(L"MissileMask: ") + (long)mNode->Data()->iGame + L" " + (long)mNode->Data()->iMask + L"\n";
170 cycrow 228
	for (auto itr = _lCutData.begin(); itr != _lCutData.end(); itr++)
216 cycrow 229
		values += L"CutData: " + (*itr)->str + L"\n";
170 cycrow 230
	for (auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
216 cycrow 231
		values += L"Bodies: " + (*itr)->str + L"\n";
170 cycrow 232
	for (auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
216 cycrow 233
		values += L"Animations: " + (*itr)->str + L"\n";
1 cycrow 234
 
235
	return values;
236
}
237
 
207 cycrow 238
bool CXspFile::parseValueLine(const Utils::WString &sLine)
1 cycrow 239
{
207 cycrow 240
	Utils::WString first = sLine.token(L":", 1);
241
	Utils::WString rest  = sLine.tokens(L":", 2).removeFirstSpace();
1 cycrow 242
 
207 cycrow 243
	if ( first.Compare(L"Data") )
217 cycrow 244
		m_sData = rest;
207 cycrow 245
	else if ( first.Compare(L"ID") )
217 cycrow 246
		m_sID = rest;
207 cycrow 247
	else if ( sLine.Compare(L"LanguageText") )
1 cycrow 248
		m_bLanguageText = true;
207 cycrow 249
	else if ( sLine.Compare(L"ExistingShip") )
1 cycrow 250
		m_bExistingShip = true;
207 cycrow 251
	else if ( first.Compare(L"OrgDesc") || first.Compare(L"OriginalDesc") )
14 cycrow 252
		m_iOrgDesc = rest;
207 cycrow 253
	else if ( first.Compare(L"Shipyard") )
14 cycrow 254
		m_iShipyard = rest;
207 cycrow 255
	else if ( first.Compare(L"CutData") )
216 cycrow 256
		this->addCutData(rest);
207 cycrow 257
	else if ( first.Compare(L"Bodies") )
216 cycrow 258
		this->addBodies(rest);
207 cycrow 259
	else if ( first.Compare(L"Animations") )
216 cycrow 260
		this->addAnimation(rest);
207 cycrow 261
	else if ( first.Compare(L"Cockpit") )
216 cycrow 262
		this->addCockpit(rest, 0);
207 cycrow 263
	else if ( first.Compare(L"CockpitNew") )
1 cycrow 264
	{
207 cycrow 265
		Utils::WString cockpit = rest.tokens(L" ", 2);
266
		Utils::WString sMasks = rest.token(L" ", 1);
216 cycrow 267
		this->addCockpit(cockpit, 0, -1);
207 cycrow 268
		int num = sMasks.token(L":", 1);
1 cycrow 269
		for ( int i = 0; i < num; i++ )
270
		{
207 cycrow 271
			int mask = sMasks.token(L":", ((i + 1) * 2) + 1);
272
			int game = sMasks.token(L":", ((i + 1) * 2));
216 cycrow 273
			this->addCockpit(cockpit, game, mask);
1 cycrow 274
		}
275
	}
207 cycrow 276
	else if ( first == L"Web" )	this->setWebSite(rest);
277
	else if ( first.Compare(L"WeaponMask") )
278
		this->AddWeaponMask(rest.token(L" ", 1), rest.token(L" ", 2));
279
	else if ( first.Compare(L"MissileMask") )
280
		this->AddMissileMask(rest.token(L" ", 1), rest.token(L" ", 2));
281
	else if ( first == L"Text" )
1 cycrow 282
	{
283
		SText *text = new SText;
207 cycrow 284
		text->iId = rest.token(L"|", 1);
216 cycrow 285
		text->sName = rest.token(L"|", 2);
207 cycrow 286
		text->sName = text->sName.findReplace(L"<::PiPe::>", L"|");
216 cycrow 287
		text->sDesc = rest.tokens(L"|", 3);
1 cycrow 288
		m_lText.push_back ( text );
289
	}
207 cycrow 290
	else if ( first == L"Component" )
1 cycrow 291
	{
292
		SComponent *c = new SComponent;
216 cycrow 293
		c->sData = rest.token(L"|", 1);
207 cycrow 294
		c->sData = c->sData.findReplace (L"<::PiPe::>", L"|");
216 cycrow 295
		c->sSection = rest.token(L"|", 2);
207 cycrow 296
		c->sSection = c->sSection.findReplace (L"<::PiPe::>", L"|");
216 cycrow 297
		c->sSection2 = rest.tokens(L"|", 3);
1 cycrow 298
		m_lComponent.push_back ( c );
299
	}
207 cycrow 300
	else if ( first == L"Dummy" )
1 cycrow 301
	{
302
		SDummy *d = new SDummy;
216 cycrow 303
		d->sData = rest.token(L"|", 1);
207 cycrow 304
		d->sData = d->sData.findReplace (L"<::PiPe::>", L"|");
216 cycrow 305
		d->sSection = rest.tokens(L"|", 2);
1 cycrow 306
		m_lDummy.push_back ( d );
307
	}
207 cycrow 308
	else if ( first == L"Comment" )	this->setDescription(rest.findReplace(L"<newline>", L"<br>"));
1 cycrow 309
	else
207 cycrow 310
		return CBaseFile::parseValueLine(sLine);
1 cycrow 311
 
312
	return true;
313
}
314
 
203 cycrow 315
Utils::WString CXspFile::shipName(int lang)
1 cycrow 316
{
203 cycrow 317
	Utils::WString name;
1 cycrow 318
	if ( (m_bLanguageText) && (lang) )
319
	{
320
		for ( SText *text = m_lText.First(); text; text = m_lText.Next() )
321
		{
322
			if ( text->iId == lang )
323
			{
216 cycrow 324
				name = text->sName;
1 cycrow 325
				break;
326
			}
327
		}
328
	}
329
 
39 cycrow 330
	if ( name.empty() )
171 cycrow 331
		name = this->name(lang);
1 cycrow 332
 
333
	return name;
334
}
335
 
39 cycrow 336
//TODO: split this up
218 cycrow 337
bool CXspFile::convertOld(const Utils::WString &file)
1 cycrow 338
{
339
	// open the file
218 cycrow 340
	FILE *id = _wfopen(file.c_str(), L"rb");
1 cycrow 341
	if ( !id )
342
		return false;
343
 
344
	// read to memory
345
	fseek(id, 0, SEEK_END);
346
	size_t size = ftell(id);
347
	fseek(id, 0, SEEK_SET);
348
	unsigned char *data = new unsigned char[size + 1];
349
	fread(data, sizeof(unsigned char), size, id);
350
	data[size] = '\0';
351
	fclose(id);
352
 
353
	// uncompress the file
354
	size_t len;
355
	unsigned char *compr = LZMADecode_C ( data, size, &len, NULL );
356
 
218 cycrow 357
	delete[] data;
1 cycrow 358
 
359
	if ( !compr )
360
		return false;
361
 
362
	this->Delete();
363
	this->SetDefaults();
364
 
365
	// now read the data line by line
366
	size_t pos = 0;
367
	size_t start = 0;
368
	int packageVersion = 0;
369
	while ( pos < len )
370
	{
371
		while ( compr[pos++] != '\n' && pos < len );
372
 
373
		compr[pos - 1] = '\0';
218 cycrow 374
		Utils::WString line = Utils::WString::FromString((char *)(compr + start));
1 cycrow 375
		start = pos;
39 cycrow 376
		if ( line.empty() )
1 cycrow 377
			continue;
218 cycrow 378
		Utils::WString first = line.token(L":", 1);
379
		Utils::WString rest = line.tokens(L":", 2);
39 cycrow 380
		rest = rest.removeFirstSpace();
1 cycrow 381
 
382
		// now check each line
218 cycrow 383
		if ( first.Compare(L"Packager") )
39 cycrow 384
			packageVersion = rest;
218 cycrow 385
		else if ( first.Compare(L"Shipyard") )
1 cycrow 386
		{
218 cycrow 387
			std::vector<Utils::WString> strs;
388
			if(rest.tokenise(L";", strs))
1 cycrow 389
			{
390
				int cur = 1;
218 cycrow 391
				for (size_t i = 0; i < strs.size(); i++, cur *= 2 )
1 cycrow 392
				{
218 cycrow 393
					if ( strs[i] == L"1" )
1 cycrow 394
						this->AddShipyard(cur);
395
				}
396
			}
397
		}
226 cycrow 398
		else if ( first.Compare(L"ScreenShot") )
1 cycrow 399
		{
218 cycrow 400
			int size = rest.token(L" ", 1);
401
			Utils::WString ext = rest.token(L" ", 2);
1 cycrow 402
 
217 cycrow 403
			C_File *newFile = this->addFile(m_sID + L"_" + (long)(this->countFiles(FILETYPE_SCREEN) + 1) + L"." + ext, L"", FILETYPE_SCREEN);
1 cycrow 404
			newFile->ReadFromData((char *)(compr + pos), size); 
405
 
406
			start += (size + 1);
407
		}
218 cycrow 408
		else if ( first.Compare(L"SceneFile") )
1 cycrow 409
		{
218 cycrow 410
			Utils::WString file = rest.tokens(L" ", 3);
217 cycrow 411
			m_pSceneFile = this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPSCENE);
218 cycrow 412
			m_pSceneFile->SetCreationTime((long)rest.token(L" ", 1));
413
			m_pSceneFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
1 cycrow 414
 
415
			start += m_pSceneFile->GetDataSize();
416
		}
218 cycrow 417
		else if ( first.Compare(L"CockpitFile") )
1 cycrow 418
		{
218 cycrow 419
			Utils::WString file = rest.tokens(L" ", 3);
217 cycrow 420
			m_pCockpitFile = this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_COCKPITSCENE);
218 cycrow 421
			m_pCockpitFile->SetCreationTime((long)rest.token(L" ", 1));
422
			m_pCockpitFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
1 cycrow 423
 
424
			start += m_pCockpitFile->GetDataSize();
425
		}
218 cycrow 426
		else if ( first.Compare(L"Model") )
1 cycrow 427
		{
218 cycrow 428
			Utils::WString file = rest.tokens(L" ", 3);
217 cycrow 429
			C_File *newFile= this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPMODEL);
218 cycrow 430
			newFile->SetCreationTime((long)rest.token(L" ", 1));
431
			newFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
1 cycrow 432
 
433
			start += (newFile->GetDataSize() + 1);
434
		}
218 cycrow 435
		else if ( first.Compare(L"Files") )
1 cycrow 436
		{
218 cycrow 437
			Utils::WString file = rest.tokens(L" ", 3);
1 cycrow 438
 
439
			C_File *newFile = NULL;
440
			int special = 0;
217 cycrow 441
			if ( file.Compare(L"types/CutData.txt") || file.Compare(L"types/CutData.pck") )
1 cycrow 442
			{
127 cycrow 443
				newFile = new C_File(file);
1 cycrow 444
				special = 1;
445
			}
217 cycrow 446
			else if ( file.Compare(L"types/Bodies.txt") || file.Compare(L"types/Bodies.pck") )
1 cycrow 447
			{
127 cycrow 448
				newFile = new C_File(file);
1 cycrow 449
				special = 2;
450
			}
217 cycrow 451
			else if ( file.Compare(L"types/Animations.txt") || file.Compare(L"types/Animations.pck") )
1 cycrow 452
			{
127 cycrow 453
				newFile = new C_File(file);
1 cycrow 454
				special = 3;
455
			}
456
			else
457
			{
217 cycrow 458
				newFile = this->addFile(CFileIO(file).filename(), CFileIO(file).dir(), FILETYPE_SHIPOTHER);
218 cycrow 459
				newFile->SetCreationTime((long)rest.token(L" ", 1));
1 cycrow 460
			}
218 cycrow 461
			newFile->ReadFromData((char *)(compr + pos), rest.token(L" ", 2));
1 cycrow 462
			start += (newFile->GetDataSize() + 1);
463
 
464
			if ( special )
465
			{
213 cycrow 466
				if (newFile->checkFileExt(L"pck"))
1 cycrow 467
					newFile->UnPCKFile();
468
 
469
				// read data into lines
218 cycrow 470
				Utils::WString data = Utils::WString::FromString((const char *)newFile->GetData());
170 cycrow 471
				data.removeChar('\r');
218 cycrow 472
 
473
				std::vector<Utils::WString> sLines;
474
				if(data.tokenise(L"\n", sLines))
1 cycrow 475
				{
476
					// cut data
170 cycrow 477
					size_t entries = -1;
1 cycrow 478
					if ( special == 1 )
479
					{
218 cycrow 480
						Utils::WStringList newLines;
481
						for (size_t i = 0; i < sLines.size(); i++)
1 cycrow 482
						{
218 cycrow 483
							Utils::WString line = sLines[i];
170 cycrow 484
							line.removeChar(' ');
485
							line.removeChar(9);
486
							if ( line.empty() || line[0] == '/' )
1 cycrow 487
								continue;
488
							if ( entries == -1 )
489
							{
218 cycrow 490
								entries	= line.token(L";", 1).toInt() - 36;
1 cycrow 491
								if ( entries <= 0 )
492
									break;
493
							}
494
							else
495
							{
218 cycrow 496
								int id = line.token(L";", 1).toInt();
1 cycrow 497
								if ( id >= 9000 && id <= 9017 )
498
									continue;
499
 
500
								switch (id)
501
								{
502
									case 948:
503
									case 4111:
504
									case 4112:
505
									case 4064:
506
									case 4169:
507
									case 4178:
508
									case 4177:
509
									case 4163:
510
									case 4194:
511
									case 4162:
512
									case 4191:
513
									case 4200:
514
									case 4161:
515
									case 4097:
516
									case 4205:
517
									case 4206:
518
									case 4207:
519
									case 4107:
520
										break;
521
 
522
									default:
170 cycrow 523
										newLines.pushBack(line);
1 cycrow 524
								}
170 cycrow 525
								if ( newLines.size() == entries )
1 cycrow 526
									break;
527
							}
528
						}
529
 
170 cycrow 530
						for(auto itr = newLines.begin(); itr != newLines.end(); itr++)
531
							this->addCutData((*itr)->str);
1 cycrow 532
					}
533
					// bodies
534
					else if ( special == 2 )
535
					{
536
						entries = 0;
218 cycrow 537
						Utils::WString section;
538
						for (size_t i = 0; i < sLines.size(); i++ )
1 cycrow 539
						{
218 cycrow 540
							Utils::WString line = sLines[i];
39 cycrow 541
							line.removeChar(' ');
542
							line.removeChar(9);
543
							if ( line.empty() || line[0] == '/' )
1 cycrow 544
								continue;
545
							if ( entries <= 0)
546
							{
218 cycrow 547
								section = line.token(L";", 1);
548
								entries	= line.token(L";", 2).toInt();
1 cycrow 549
							}
550
							else
551
							{
218 cycrow 552
								if ( !line.isin(L";") )
1 cycrow 553
									continue;
218 cycrow 554
								if ( line.countToken(L";") <= 2 )
1 cycrow 555
								{
218 cycrow 556
									this->addBodies(section + ";" + line.token(L";", 1) + L";");
1 cycrow 557
									--entries;
558
								}
559
								else
560
								{
561
									bool done = false;
562
									while (!done)
563
									{
218 cycrow 564
										std::vector<Utils::WString> strs;
1 cycrow 565
										done = true;
218 cycrow 566
										line.tokenise(L";", strs);
567
										for (size_t j = 0; j < strs.size(); j++)
1 cycrow 568
										{
569
											if ( !entries )
570
											{
218 cycrow 571
												line = line.tokens(L";", j + 1);
39 cycrow 572
												if ( !line.empty() )
1 cycrow 573
													done = false;
574
												break;
575
											}
576
 
39 cycrow 577
											if ( strs[j].empty() )
1 cycrow 578
												continue;
579
 
218 cycrow 580
											this->addBodies(section + L";" + strs[j] + L";");
1 cycrow 581
											--entries;
582
										}
583
										//we must be at another section
584
										if ( !done )
585
										{
218 cycrow 586
											section = line.token(L";", 1);
587
											entries	= line.token(L";", 2).toInt();
588
											line = line.remToken(L";", 1);
589
											line = line.remToken(L";", 1);
1 cycrow 590
 
39 cycrow 591
											if (line.empty())
1 cycrow 592
												done = true;
593
										}
594
									}									
595
								}
596
							}
597
						}
598
					}
599
					// animations
600
					else if ( special == 3 )
601
					{
218 cycrow 602
						Utils::WStringList in;
603
						for (size_t i = 0; i < sLines.size(); i++)
170 cycrow 604
							in.pushBack(sLines[i]);
1 cycrow 605
 
218 cycrow 606
						Utils::WStringList out;
170 cycrow 607
						if ( CXspFile::ReadAnimations(in, out, 87) )
608
							this->addAnimation(out);
1 cycrow 609
					}
610
				}
611
				delete newFile;
612
			}
613
		}
218 cycrow 614
		else if ( first.Compare(L"Script") )
1 cycrow 615
		{
218 cycrow 616
			Utils::WString file = rest.words(3);
617
			C_File *newFile= this->addFile(file, Utils::WString::Null(), FILETYPE_SCRIPT);
39 cycrow 618
			newFile->SetCreationTime((long)rest.word(1));
619
			newFile->ReadFromData((char *)(compr + pos), rest.word(2));
1 cycrow 620
 
621
			start += (newFile->GetDataSize() + 1);
622
		}
218 cycrow 623
		else if ( first.Compare(L"Text") )
624
			this->addText(rest.token(L":", 1), rest.token(L":", 2), rest.tokens(L":", 3));
625
		else if ( first.Compare(L"Component") )
626
			this->addComponent(rest.token(L";", 1), rest.token(L";", 2), rest.tokens(L";", 3));
627
		else if ( first.Compare(L"Dummy") )
1 cycrow 628
		{
629
			SDummy *d = new SDummy;
218 cycrow 630
			d->sData = rest.tokens(L";", 2);
631
			d->sSection = rest.token(L";", 1);
1 cycrow 632
			m_lDummy.push_back ( d );
633
		}
207 cycrow 634
		else if ( !this->parseValueLine(line) )
1 cycrow 635
		{
636
		//	printf ( "Command: %s, Rest: %s\n", first.c_str(), rest.c_str());
637
		}
638
 
639
		pos = start;
640
	}
641
 
642
	// assume all old ones are for X3
14 cycrow 643
	if ( !m_sData.empty() )
1 cycrow 644
	{
217 cycrow 645
		this->AddWeaponMask(GAME_X3 - 1, m_sData.token(L";", 19));
646
		this->AddMissileMask(GAME_X3 - 1, m_sData.token(L";", 25));
1 cycrow 647
	}
648
 
649
	return true;
650
}
651
 
652
 
653
int GetMaxShipyards() { return (int)SHIPYARD_MAX; }
654
 
216 cycrow 655
Utils::WString GetShipyardName (int s)
1 cycrow 656
{
657
	switch (s)
658
	{
659
		case SHIPYARD_ARGON:
216 cycrow 660
			return L"Argon";
1 cycrow 661
		case SHIPYARD_BORON:
216 cycrow 662
			return L"Boron";
1 cycrow 663
		case SHIPYARD_PARANID:
216 cycrow 664
			return L"Paranid";
1 cycrow 665
		case SHIPYARD_SPLIT:
216 cycrow 666
			return L"Split";
1 cycrow 667
		case SHIPYARD_TELADI:
216 cycrow 668
			return L"Teladi";
1 cycrow 669
		case SHIPYARD_PIRATES:
216 cycrow 670
			return L"Pirates";
1 cycrow 671
		case SHIPYARD_FRIEND:
216 cycrow 672
			return L"Friendly";
1 cycrow 673
		case SHIPYARD_XENON:
216 cycrow 674
			return L"Xenon";
1 cycrow 675
		case SHIPYARD_TERRAN:
216 cycrow 676
			return L"Terran";
1 cycrow 677
	}
678
 
216 cycrow 679
	return L"Unknown";
1 cycrow 680
}
681
 
175 cycrow 682
bool CXspFile::writeHeader(CFileIO &file, int valueheader, int valueComprLen) const
1 cycrow 683
{
52 cycrow 684
	return file.write("XSPCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);
1 cycrow 685
}
686
 
210 cycrow 687
bool CXspFile::_checkHeader(const Utils::WString &header) const
1 cycrow 688
{
210 cycrow 689
	if ( header.Compare(L"XSPCycrow") )
1 cycrow 690
		return true;
691
	return false;
692
}
693
 
694
void CXspFile::SetLaserMask(int game, int mask)
695
{
696
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
697
	{
698
		SWeaponMask *m = node->Data();
699
		if ( m->iGame == game )
700
		{
701
			m->iMask = mask;
702
			return;
703
		}
704
	}
705
 
706
	// no found, need to add it
707
	this->AddWeaponMask(game, mask);
708
}
709
 
710
void CXspFile::SetMissileMask(int game, int mask)
711
{
712
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
713
	{
714
		SWeaponMask *m = node->Data();
715
		if ( m->iGame == game )
716
		{
717
			m->iMask = mask;
718
			return;
719
		}
720
	}
721
 
722
	// no found, need to add it
723
	this->AddMissileMask(game, mask);
724
}
725
int CXspFile::GetLaserMask(int game, bool getOnly)
726
{
727
	int mask = -1;
728
	for ( CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next() )
729
	{
730
		SWeaponMask *m = node->Data();
731
		if ( m->iGame == game )
732
			return m->iMask;
733
 
734
		if ( !mask && !getOnly )
735
			mask = m->iMask;
736
	}
737
 
738
	return mask;
739
}
740
 
741
int CXspFile::GetMissileMask(int game, bool getOnly)
742
{
743
	int mask = -1;
744
	for ( CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next() )
745
	{
746
		SWeaponMask *m = node->Data();
747
		if ( m->iGame == game )
748
			return m->iMask;
749
 
750
		if ( !mask && !getOnly )
751
			mask = m->iMask;
752
	}
753
 
754
	return mask;
755
}
756
 
165 cycrow 757
void CXspFile::clearCutData()
758
{
759
	_lCutData.clear();
760
}
170 cycrow 761
void CXspFile::clearAnimations()
762
{
763
	_lAnimations.clear();
764
}
765
void CXspFile::clearBodies()
766
{
767
	_lBodies.clear();
768
}
165 cycrow 769
 
217 cycrow 770
Utils::WString CXspFile::shipClass() const
1 cycrow 771
{
14 cycrow 772
	if ( !m_sData.empty() )
217 cycrow 773
		return m_sData.token(L";", TSHIPPOS_CLASS);
774
	return L"OBJ_SHIP_M5";
1 cycrow 775
}
776
 
210 cycrow 777
bool CXspFile::GeneratePackagerScript(bool wildcard, Utils::WStringList *list, int game, const Utils::WStringList &gameAddons, bool datafile)
1 cycrow 778
{
127 cycrow 779
	if ( !CBaseFile::GeneratePackagerScript(wildcard, list, game, gameAddons, datafile) )
1 cycrow 780
		return false;
781
 
210 cycrow 782
	list->pushBack(L"# File Type, Script or Ship");
783
	list->pushBack(L"FileType: Ship");
784
	list->pushBack(L"");
98 cycrow 785
 
1 cycrow 786
	if ( m_iShipyard )
787
	{
210 cycrow 788
		list->pushBack(L"# Shipyards, Set which shipyards to add ships for sale to");
1 cycrow 789
		for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
790
		{
791
			if ( this->IsShipyard(i) )
216 cycrow 792
				list->pushBack(L"Shipyard: " + GetShipyardName(i));
1 cycrow 793
		}
210 cycrow 794
		list->pushBack(L"");
1 cycrow 795
	}
796
 
797
	if ( m_iOrgDesc > 0 )
798
	{
210 cycrow 799
		list->pushBack(L"# Use Original Description, overrides text entrys to use one of the built in text");
800
		list->pushBack(Utils::WString(L"OriginalDescription: ") + (long)m_iOrgDesc);
801
		list->pushBack(L"");
1 cycrow 802
	}
803
 
14 cycrow 804
	if ( !m_sID.empty() )
1 cycrow 805
	{
210 cycrow 806
		list->pushBack(L"# Ship ID, the ship id to identify the ship as");
217 cycrow 807
		list->pushBack(L"ShipID: " + m_sID);
1 cycrow 808
	}
809
 
108 cycrow 810
	if ( m_bExistingShip )
811
	{
210 cycrow 812
		list->pushBack(L"# Existing Ship, replaces an existing ship in the game with ship package instead of creating a new entry");
813
		list->pushBack(L"ExistingShip");
814
		list->pushBack(L"");
108 cycrow 815
	}
816
 
14 cycrow 817
	if ( !m_sData.empty() )
1 cycrow 818
	{
210 cycrow 819
		list->pushBack(L"# Ship Data, the TShip data entry to add to the game (parts of this are adjusted and auto generated by the installer)");
217 cycrow 820
		list->pushBack(L"ShipData: " + m_sData);
210 cycrow 821
		list->pushBack(L"");
1 cycrow 822
	}
823
 
108 cycrow 824
	if ( m_lText.size() ) {
210 cycrow 825
		list->pushBack(L"# Ship Texts, the name/description of the ship in each language: <LANGID> <NAME>|<DESCRIPTION>");
108 cycrow 826
		for(CListNode<SText> *node = m_lText.Front(); node; node = node->next()) {
216 cycrow 827
			list->pushBack(Utils::WString(L"ShipText: ") + (long)node->Data()->iId + L" " + node->Data()->sName + L"|" + node->Data()->sDesc);
108 cycrow 828
		}
829
 
210 cycrow 830
		list->pushBack(L"");
1 cycrow 831
	}
832
 
108 cycrow 833
	if ( this->m_lWeaponMasks.size() ) {
210 cycrow 834
		list->pushBack(L"# Weapon Masks, the weapons for each game: <GAME> <MASK>");
108 cycrow 835
		for(CListNode<SWeaponMask> *node = m_lWeaponMasks.Front(); node; node = node->next()) {
210 cycrow 836
			list->pushBack(Utils::WString(L"WeaponMask: ") + (long)node->Data()->iGame + L" " + (long)node->Data()->iMask);
108 cycrow 837
		}
838
 
210 cycrow 839
		list->pushBack(L"");
108 cycrow 840
	}
841
 
842
	if ( this->m_lMissileMasks.size() ) {
210 cycrow 843
		list->pushBack(L"# Missile Masks, the missiles for each game: <GAME> <MASK>");
108 cycrow 844
		for(CListNode<SWeaponMask> *node = m_lMissileMasks.Front(); node; node = node->next()) {
210 cycrow 845
			list->pushBack(Utils::WString(L"WeaponMask: ") + (long)node->Data()->iGame + L" " + (long)node->Data()->iMask);
108 cycrow 846
		}
847
 
213 cycrow 848
		list->pushBack(L"");
108 cycrow 849
	}
850
 
851
	if ( this->m_lComponent.size() ) {
210 cycrow 852
		list->pushBack(L"# Ship Components, each component used in the ships scene: <SECTION> <MODELENTRY> <VALUES>");
108 cycrow 853
		for(CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next()) {
216 cycrow 854
			list->pushBack(Utils::WString(L"Component: ") + node->Data()->sSection + L" " + node->Data()->sSection2 + L" " + node->Data()->sData);
108 cycrow 855
		}
210 cycrow 856
		list->pushBack(L"");
108 cycrow 857
	}
858
 
859
	if ( this->m_lDummy.size() ) {
210 cycrow 860
		list->pushBack(L"# Ship Dummies, each dummy entry used in the ships scene: <SECTION> <VALUE>");
108 cycrow 861
		for(CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next()) {
216 cycrow 862
			list->pushBack(L"Dummy: " + node->Data()->sSection + L" " + node->Data()->sData);
108 cycrow 863
		}
210 cycrow 864
		list->pushBack(L"");
108 cycrow 865
	}
866
 
867
	if ( this->m_lCockpit.size() ) {
210 cycrow 868
		list->pushBack(L"# Cockpit entries, each cockpit value with thier weapons mask");
108 cycrow 869
		for(CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next()) {
216 cycrow 870
			list->pushBack(L"Cockpit: " + node->Data()->sCockpit.token(L";", 19) + L" " + node->Data()->sCockpit);
108 cycrow 871
			for(SWeaponMask *mask = node->Data()->lWeaponMask.First(); mask; mask = node->Data()->lWeaponMask.Next()) {
216 cycrow 872
				list->pushBack(L"CockpitWeapon: " + node->Data()->sCockpit.token(L";", 19) + L" " + (long)mask->iGame + L" " + (long)mask->iMask);
108 cycrow 873
			}
874
		}
875
 
210 cycrow 876
		list->pushBack(L"");
108 cycrow 877
	}
878
 
170 cycrow 879
	if (!this->_lCutData.empty())
880
	{
210 cycrow 881
		list->pushBack(L"# Ship Cut Data");
165 cycrow 882
		for(auto itr = _lCutData.begin(); itr != _lCutData.end(); itr++)
216 cycrow 883
			list->pushBack(L"CutData: " + (*itr)->str);
210 cycrow 884
		list->pushBack(L"");
108 cycrow 885
	}
886
 
170 cycrow 887
	if (!this->_lBodies.empty())
888
	{
210 cycrow 889
		list->pushBack(L"# Ship Bodies");
170 cycrow 890
		for(auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
216 cycrow 891
			list->pushBack(L"Bodies: " + (*itr)->str);
210 cycrow 892
		list->pushBack(L"");
108 cycrow 893
	}
894
 
170 cycrow 895
	if (!this->_lAnimations.empty())
896
	{
210 cycrow 897
		list->pushBack(L"# Ship Animations");
170 cycrow 898
		for (auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
216 cycrow 899
			list->pushBack(L"Animation: " + (*itr)->str);	
210 cycrow 900
		list->pushBack(L"");
108 cycrow 901
	}
902
 
1 cycrow 903
	if ( !datafile )
904
	{
127 cycrow 905
		if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list, game, gameAddons) )
1 cycrow 906
			return false;
907
	}
908
 
909
	return true;
910
}
911
 
216 cycrow 912
void CXspFile::_addSection(Utils::CList<STypesSection> &list, const Utils::WString &section, const Utils::WString &data)
109 cycrow 913
{
914
	STypesSection *currentSubSection = NULL;
113 cycrow 915
	for(Utils::CList<STypesSection>::iterator itr = list.begin(); itr != list.end(); itr++) {
109 cycrow 916
		if ( (*itr)->sSection.Compare(section) ) {
917
			currentSubSection = *itr;
918
			break;
919
		}
920
	}
921
 
922
	if ( !currentSubSection ) {
923
		currentSubSection = new STypesSection;
924
		currentSubSection->sSection = section;
925
		list.push_back(currentSubSection);
926
	}
927
 
216 cycrow 928
	currentSubSection->lEntries.pushBack(data, L"");
109 cycrow 929
}
930
 
216 cycrow 931
void CXspFile::_addDataSection(Utils::WStringList& list, Utils::CList<STypesSection>& sectionList, bool bUseFirst)
165 cycrow 932
{
933
	for(auto itr = list.begin(); itr != list.end(); itr++)
934
	{
935
		if (bUseFirst) {
216 cycrow 936
			Utils::WString data = (*itr)->str;
937
			_addSection(sectionList, data.token(L";", 1), data.tokens(L";", 2));
165 cycrow 938
		}
939
		else {
940
			_addSection(sectionList, (*itr)->str, (*itr)->data);
941
		}
942
	}
943
}
944
 
113 cycrow 945
void CXspFile::addDummiesToList(Utils::CList<STypesSection> &list)
109 cycrow 946
{
947
	ADDSECTIONLIST(SDummy, m_lDummy);
948
}
949
 
950
void CXspFile::addComponentsToList(CLinkList<SComponentEntry> &componentList)
951
{
952
	for(CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next()) {
953
		SComponentEntry *currentSection = NULL;
954
		for(CListNode<SComponentEntry> *cNode = componentList.Front(); cNode; cNode = cNode->next()) {
955
			if ( cNode->Data()->sSection.Compare(node->Data()->sSection) ) {
956
				currentSection = cNode->Data();
957
				break;
958
			}
959
		}
960
 
961
		if ( !currentSection ) {
962
			currentSection = new SComponentEntry();
963
			currentSection->sSection = node->Data()->sSection;
964
			componentList.push_back(currentSection);
965
		}
966
 
967
		_addSection(currentSection->lEntries, node->Data()->sSection2, node->Data()->sData);
968
	}
969
}
970
 
113 cycrow 971
void CXspFile::addCutDataToList(Utils::CList<STypesSection> &list)
109 cycrow 972
{
165 cycrow 973
	_addDataSection(this->_lCutData, list, false);
109 cycrow 974
}
975
 
113 cycrow 976
void CXspFile::addBodiesToList(Utils::CList<STypesSection> &list)
109 cycrow 977
{
170 cycrow 978
	_addDataSection(this->_lBodies, list, true);
109 cycrow 979
}
980
 
113 cycrow 981
void CXspFile::addAnimationsToList(Utils::CList<STypesSection> &list)
109 cycrow 982
{
170 cycrow 983
	_addDataSection(this->_lAnimations, list, false);
109 cycrow 984
}
985
 
986
 
987
void CXspFile::addGeneratedFiles(HZIP &hz)
988
{
216 cycrow 989
	CFileIO tmpFile(CPackages::tempDirectory() + L"/temp.tmp");
109 cycrow 990
 
991
	for(int i = 0; i < 5; i++) {
216 cycrow 992
		Utils::WString type;
993
		Utils::WString data;
109 cycrow 994
		switch(i) {
995
			case 0:
217 cycrow 996
				data = L"50;1\r\n" + this->m_sData;
216 cycrow 997
				type = L"TShips";
109 cycrow 998
				break;
999
			case 1:
1000
				if ( !this->m_lCockpit.empty() ) {
216 cycrow 1001
					data = Utils::WString("51;") + (long)this->m_lCockpit.size() + L";\r\n";
109 cycrow 1002
					for(CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next()) {
216 cycrow 1003
						data += node->Data()->sCockpit + L"\r\n";
109 cycrow 1004
					}
216 cycrow 1005
					type = L"TCockpits";
109 cycrow 1006
				}
1007
				break;
1008
			case 2:
1009
				if ( !this->m_lComponent.empty() ) {
216 cycrow 1010
					type = L"Components";
109 cycrow 1011
					CLinkList<SComponentEntry> componentList;
1012
					this->addComponentsToList(componentList);
1013
					for(CListNode<SComponentEntry> *node = componentList.Front(); node; node = node->next()) {
216 cycrow 1014
						data += node->Data()->sSection + L"; " + (long)node->Data()->lEntries.size() + L";\r\n";
109 cycrow 1015
						data += CXspFile::TypesListToString(node->Data()->lEntries, true);
1016
					}
1017
				}
1018
				break;
1019
			case 3:
216 cycrow 1020
				GENERATESECTION(L"Dummies", SDummy, this->m_lDummy);
109 cycrow 1021
				break;
1022
			case 4:
216 cycrow 1023
				GENERATESTRINGSECTION(L"Bodies", this->_lBodies, true);
109 cycrow 1024
				break;
1025
		}
1026
 
1027
		if ( type.empty() ) continue;
1028
 
216 cycrow 1029
		Utils::WString fname = L"GENERATED/types/" + type + L".txt";
109 cycrow 1030
 
216 cycrow 1031
		Utils::WString fileData = L"// Exported " + type + L" file, Generated by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2) + L"\r\n" + data;
1032
		/*
109 cycrow 1033
		if ( tmpFile.startWrite() ) {
1034
			tmpFile.write(fileData.c_str(), fileData.length());
1035
			tmpFile.close();
1036
		}
1037
 
1038
		// tships files
1039
		wsprintf(buf, L"%hs", fname.c_str());
1040
		if ( tmpFile.startRead() ) {
216 cycrow 1041
			*/
1042
		ZipAdd(hz, fname.c_str(), (void *)fileData.c_str(), fileData.length() * sizeof(wchar_t));
1043
		//}
109 cycrow 1044
	}
1045
}
1046
 
197 cycrow 1047
bool CXspFile::loadPackageData(const Utils::WString &sFirst, const Utils::WString &sRest, const Utils::WString &sMainGame, Utils::WStringList &otherGames, Utils::WStringList &gameAddons, CProgressInfo *progress)
1 cycrow 1048
{
197 cycrow 1049
	if ( sFirst.Compare(L"Shipyard") )
1 cycrow 1050
	{
1051
		for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
1052
		{
39 cycrow 1053
			if ( sRest.Compare(GetShipyardName(i)) )
1 cycrow 1054
			{
1055
				this->AddShipyard(i);
1056
				break;
1057
			}
1058
		}
1059
	}
197 cycrow 1060
	else if ( sFirst.Compare(L"OriginalDescription") )
14 cycrow 1061
		m_iOrgDesc = sRest;
197 cycrow 1062
	else if ( sFirst.Compare(L"ShipData") )
217 cycrow 1063
		m_sData = sRest;
197 cycrow 1064
	else if ( sFirst.Compare(L"ReadData") ) // read data from a tships file
1 cycrow 1065
	{
1066
		CPackages p;
217 cycrow 1067
		m_sData = p.readShipData(sRest.tokens(L" ", 2), sRest.token(L" ", 1));
1 cycrow 1068
	}
197 cycrow 1069
	else if ( sFirst.Compare(L"ExistingShip") )
1 cycrow 1070
		m_bExistingShip = true;
197 cycrow 1071
	else if ( sFirst.Compare(L"ShipID") )
217 cycrow 1072
		m_sID = sRest;
197 cycrow 1073
	else if ( sFirst.Compare(L"ShipText") )
216 cycrow 1074
		this->addText(sRest.token(L" ", 1).toLong(), sRest.tokens(L" ", 2).token(L"|", 1), sRest.tokens(L" ", 2).tokens(L"|", 2));
197 cycrow 1075
	else if ( sFirst.Compare(L"Component") )
216 cycrow 1076
		this->addComponent(sRest.token(L" ", 1), sRest.token(L" ", 2), sRest.tokens(L" ", 3));
197 cycrow 1077
	else if ( sFirst.Compare(L"Cockpit") )
216 cycrow 1078
		this->addCockpit(sRest.tokens(L" ", 2).replaceToken(L";", 19, sRest.token(L" ", 1)), 0);
197 cycrow 1079
	else if ( sFirst.Compare(L"CockpitWeapon") )
216 cycrow 1080
		this->addCockpitWeapon(sRest.token(L" ", 1), sRest.token(L" ", 2), sRest.token(L" ", 3));
197 cycrow 1081
	else if ( sFirst.Compare(L"WeaponMask") )
1082
		this->AddWeaponMask(sRest.token(L" ", 1), sRest.token(L" ", 2));
1083
	else if ( sFirst.Compare(L"MissileMask") )
1084
		this->AddMissileMask(sRest.token(L" ", 1), sRest.token(L" ", 2));
1085
	else if ( sFirst.Compare(L"Dummy") )
216 cycrow 1086
		this->addDummy(sRest.token(L" ", 1), sRest.token(L" ", 2));
197 cycrow 1087
	else if ( sFirst.Compare(L"CutData") )
216 cycrow 1088
		this->addCutData(sRest);
197 cycrow 1089
	else if ( sFirst.Compare(L"Animation") )
216 cycrow 1090
		this->addAnimation(sRest);
197 cycrow 1091
	else if ( sFirst.Compare(L"Bodies") )
216 cycrow 1092
		this->addBodies(sRest);
197 cycrow 1093
	else if ( !CBaseFile::loadPackageData(sFirst, sRest, sMainGame, otherGames, gameAddons, progress) )
1 cycrow 1094
	{
1095
		return false;
1096
	}
1097
 
1098
	return true;
1099
}
1100
 
1101
 
217 cycrow 1102
Utils::WString CXspFile::getX3ShipData() const
1 cycrow 1103
{
217 cycrow 1104
	Utils::WString data = m_sData;
1 cycrow 1105
 
1106
	// change the ship subtype, Reunion uses number, TC uses a define
217 cycrow 1107
	Utils::WString sSubType = data.token(L";", 6);
211 cycrow 1108
	if ( !((long)sSubType) && sSubType != L"0" )
217 cycrow 1109
		data = data.replaceToken(L";", 6, (long)CShipData::ConvertShipSubType(sSubType));
1 cycrow 1110
 
217 cycrow 1111
	Utils::WString sClass = data.token(L";", TSHIPPOS_CLASS);
1112
	if ( !((long)sClass) && sClass != L"0" )
1 cycrow 1113
	{
1114
		int num = 0;
1115
		for ( int i = 0; i < OBJ_SHIP_MAX; i++ )
1116
		{
217 cycrow 1117
			if ( sClass.Compare(CShipData::ConvertShipClass(CShipData::GetShipClassFromNum(i))) )
1 cycrow 1118
			{
1119
				num = i;
1120
				break;
1121
			}
1122
		}
1123
 
217 cycrow 1124
		data = data.replaceToken(L";", TSHIPPOS_CLASS, (long)num);
1 cycrow 1125
	}
1126
 
1127
	return data;
1128
}
1129
 
217 cycrow 1130
Utils::WString CXspFile::getTCShipData() const
1 cycrow 1131
{
217 cycrow 1132
	Utils::WString data = m_sData;
1 cycrow 1133
 
217 cycrow 1134
	Utils::WString sSubType = data.token(L";", 6);
211 cycrow 1135
	if ( ((long)sSubType) || sSubType == L"0" )
217 cycrow 1136
		data = data.replaceToken(L";", 6, CShipData::ConvertShipSubType((long)sSubType));
1 cycrow 1137
 
217 cycrow 1138
	Utils::WString sClass = data.token(L";", TSHIPPOS_CLASS);
1139
	if ( ((long)sClass) || sClass == L"0" )
1140
		data = data.replaceToken(L";", TSHIPPOS_CLASS, CShipData::ConvertShipClass((long)sClass));
1 cycrow 1141
 
1142
	return data;
1143
}
1144
 
216 cycrow 1145
bool CXspFile::removeCockpit(const Utils::WString &sCockpitId)
1 cycrow 1146
{
216 cycrow 1147
	Utils::WString cockpitid = sCockpitId;
1 cycrow 1148
	// if its a whole line, just get the end
216 cycrow 1149
	if ( cockpitid.contains(L";") )
1 cycrow 1150
	{
216 cycrow 1151
		cockpitid = cockpitid.tokens(L";", -2);
1152
		while ( cockpitid.right(1) == L";" )
39 cycrow 1153
			cockpitid.truncate(-1);
1 cycrow 1154
	}
1155
 
1156
	bool ret = false;
1157
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1158
	{
216 cycrow 1159
		Utils::WString id = node->Data()->sCockpit.token(L";", 19);
1 cycrow 1160
		if ( id.Compare(cockpitid) )
1161
		{
1162
			node->DeleteData();
1163
			ret = true;
1164
			break;
1165
		}
1166
	}
1167
 
1168
	m_lCockpit.RemoveEmpty();
1169
 
1170
	return ret;
1171
}
1172
 
216 cycrow 1173
bool CXspFile::removeComponent(const Utils::WString &section1, const Utils::WString &section2, const Utils::WString &data)
1 cycrow 1174
{
1175
	bool ret = false;
1176
	for ( CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next() )
1177
	{
1178
		if ( node->Data()->sSection.Compare(section1) && node->Data()->sSection2.Compare(section2) && node->Data()->sData.Compare(data) )
1179
		{
1180
			ret = true;
1181
			node->DeleteData();
1182
			break;
1183
		}
1184
	}
1185
	m_lComponent.RemoveEmpty();
1186
	return ret;
1187
}
1188
 
216 cycrow 1189
bool CXspFile::removeDummy(const Utils::WString &section, const Utils::WString &data)
1 cycrow 1190
{
1191
	bool ret = false;
1192
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
1193
	{
1194
		if ( node->Data()->sSection.Compare(section) && node->Data()->sData.Compare(data) )
1195
		{
1196
			ret = true;
1197
			node->DeleteData();
1198
			break;
1199
		}
1200
	}
1201
	m_lDummy.RemoveEmpty();
1202
 
1203
	return ret;
1204
}
1205
 
218 cycrow 1206
Utils::WString CXspFile::getCockpitData(const Utils::WString &cid)
1 cycrow 1207
{
1208
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1209
	{
216 cycrow 1210
		Utils::WString id = node->Data()->sCockpit.token(L";", 19);
1 cycrow 1211
		if ( id.Compare(cid) )
218 cycrow 1212
			return node->Data()->sCockpit;
1 cycrow 1213
	}
1214
 
218 cycrow 1215
	return L"";
1 cycrow 1216
}
1217
 
218 cycrow 1218
SCockpit *CXspFile::findCockpit(const Utils::WString &cid)
1 cycrow 1219
{
1220
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1221
	{
216 cycrow 1222
		Utils::WString id = node->Data()->sCockpit.token(L";", 19);
1 cycrow 1223
		if ( id.Compare(cid) )
1224
			return node->Data();
1225
	}
1226
 
218 cycrow 1227
	return nullptr;
1 cycrow 1228
}
1229
 
218 cycrow 1230
void CXspFile::editCockpit(const Utils::WString &cid, const Utils::WString &cockpit)
1 cycrow 1231
{
1232
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1233
	{
216 cycrow 1234
		Utils::WString id = node->Data()->sCockpit.token(L";", 19);
1 cycrow 1235
		if ( id.Compare(cid) )
1236
		{
218 cycrow 1237
			node->Data()->sCockpit = cockpit;
1 cycrow 1238
			break;
1239
		}
1240
	}
1241
}
1242
 
218 cycrow 1243
void CXspFile::editCockpit(const Utils::WString &cid, const Utils::WString &scene, int mask)
1 cycrow 1244
{
1245
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1246
	{
216 cycrow 1247
		Utils::WString id = node->Data()->sCockpit.token(L";", 19);
1 cycrow 1248
		if ( id.Compare(cid) )
1249
		{
216 cycrow 1250
			Utils::WString cockpit = node->Data()->sCockpit;
1251
			cockpit = cockpit.replaceToken(L";", 8, scene);
1252
			cockpit = cockpit.replaceToken(L";", 9, (long)mask);
1 cycrow 1253
			node->Data()->sCockpit = cockpit;
1254
			break;
1255
		}
1256
	}
1257
}
218 cycrow 1258
void CXspFile::newCockpit(const Utils::WString &id, const Utils::WString &scene, int mask)
1 cycrow 1259
{
216 cycrow 1260
	Utils::WString cockpit = L"0;0;0;0;0;0;0;";
218 cycrow 1261
	cockpit += scene + L";";
39 cycrow 1262
	cockpit += (long)mask;
216 cycrow 1263
	cockpit += L";0;0;0;0;0;0;-100000;0;0;";
218 cycrow 1264
	cockpit += id + L";";
216 cycrow 1265
	this->addCockpit(cockpit, -1);
1 cycrow 1266
}
1267
 
216 cycrow 1268
bool CXspFile::removeCutData(const Utils::WString &cut)
1 cycrow 1269
{
1270
	bool ret = false;
165 cycrow 1271
	for(size_t i = 0; i < _lCutData.size(); i++)
1 cycrow 1272
	{
216 cycrow 1273
		Utils::WString str = _lCutData[i]->str;
1274
		if (str.token(L";", 1).Compare(cut.token(L";", 1)))
1 cycrow 1275
		{
1276
			ret = true;
165 cycrow 1277
			_lCutData.remove(str);
1 cycrow 1278
			break;
1279
		}
1280
	}
1281
 
1282
	return ret;
1283
}
1284
 
216 cycrow 1285
bool CXspFile::removeBodies(const Utils::WString &cut)
1 cycrow 1286
{
1287
	bool ret = false;
170 cycrow 1288
	for (auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
1 cycrow 1289
	{
170 cycrow 1290
		if ((*itr)->str.remove(' ').Compare(cut.remove(' ')))
1 cycrow 1291
		{
170 cycrow 1292
			_lBodies.remove(itr);
1293
			return true;
1 cycrow 1294
		}
1295
	}
1296
 
170 cycrow 1297
	return false;
1 cycrow 1298
}
1299
 
216 cycrow 1300
bool CXspFile::removeAnimation(const Utils::WString &cut)
1 cycrow 1301
{
170 cycrow 1302
	for(auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
1 cycrow 1303
	{
170 cycrow 1304
		if ((*itr)->str.remove(' ').remove('\n').Compare(cut.remove(' ').remove('\n')))
1 cycrow 1305
		{
170 cycrow 1306
			_lAnimations.remove(itr);
1307
			return true;
1 cycrow 1308
		}
1309
	}
1310
 
170 cycrow 1311
	return false;
1 cycrow 1312
}
1313
 
216 cycrow 1314
SCockpit *CXspFile::_findCockpit(const Utils::WString &sID)
1 cycrow 1315
{
108 cycrow 1316
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() ) {
216 cycrow 1317
		Utils::WString id = node->Data()->sCockpit.token(L";", 19);
108 cycrow 1318
		if ( id.Compare(sID) )
1319
			return node->Data();
1320
	}
1 cycrow 1321
 
108 cycrow 1322
	return NULL;
1323
}
1324
 
216 cycrow 1325
void CXspFile::addCockpitWeapon(const Utils::WString &cockpit, int game, int mask)
108 cycrow 1326
{
1327
	SCockpit *pCockpit = _findCockpit(cockpit);
1328
 
1329
	// search if the game mask already exists
1330
	SWeaponMask *wm = NULL;
1331
	for ( CListNode<SWeaponMask> *node = pCockpit->lWeaponMask.Front(); node; node = node->next() )
1 cycrow 1332
	{
108 cycrow 1333
		if ( node->Data()->iGame == game )
1 cycrow 1334
		{
108 cycrow 1335
			wm = node->Data();
1 cycrow 1336
			break;
1337
		}
1338
	}
1339
 
108 cycrow 1340
	if ( !wm )
1341
	{
1342
		wm = new SWeaponMask;
1343
		pCockpit->lWeaponMask.push_back(wm);
1344
	}
1345
 
1346
	wm->iGame = game;
1347
	if ( mask == -1 )
216 cycrow 1348
		wm->iMask = pCockpit->sCockpit.token(L";", 9);
108 cycrow 1349
	else
1350
		wm->iMask = mask;
1351
	_changed();
1352
}
1353
 
216 cycrow 1354
void CXspFile::addCockpit(const Utils::WString &cockpit, int game, int mask, int index)
108 cycrow 1355
{
216 cycrow 1356
	Utils::WString cid = cockpit.token(L";", 19);
108 cycrow 1357
	SCockpit *pCockpit = _findCockpit(cid);
1358
 
1 cycrow 1359
	if ( !pCockpit )
1360
	{
1361
		pCockpit = new SCockpit;
1362
		pCockpit->sCockpit = cockpit;
1363
		pCockpit->iIndex = index;
1364
		m_lCockpit.push_back(pCockpit);
1365
	}
1366
	if ( index != -1 )
1367
		pCockpit->iIndex = index;
1368
 
1369
	// now add the game mask
1370
	if ( game > 0 )
216 cycrow 1371
		addCockpitWeapon(cid, game, mask);
50 cycrow 1372
	_changed();
1 cycrow 1373
}
1374
 
216 cycrow 1375
void CXspFile::addBody(const Utils::WString &section, const Utils::WString &data)
1 cycrow 1376
{
216 cycrow 1377
	this->addBodies(section + L";" + data);
50 cycrow 1378
	_changed();
1 cycrow 1379
}
216 cycrow 1380
void CXspFile::addBodies(const Utils::WString &sData)
1 cycrow 1381
{
216 cycrow 1382
	Utils::WString data = sData;
39 cycrow 1383
	if ( !data.isNumber() )
1 cycrow 1384
	{
39 cycrow 1385
		if ( data[(int)(data.length() - 5)] == '.' )
1386
			data = data.left(-5);
1387
		else if ( data[(int)(data.length() - 4)] == '.' )
1388
			data = data.left(-4);
216 cycrow 1389
		if ( data.right(1) != L";" )
1390
			data += L";";
1 cycrow 1391
	}
170 cycrow 1392
	if(!_lBodies.contains(data))
1393
		_lBodies.pushBack(data);
50 cycrow 1394
	_changed();
1 cycrow 1395
}
1396
 
216 cycrow 1397
void CXspFile::addCutData(const Utils::WString& data)
165 cycrow 1398
{ 
1399
	if (!_lCutData.contains(data))
1400
	{
1401
		_lCutData.pushBack(data);
1402
		_changed();
1403
	}
1404
}
1405
 
1406
 
218 cycrow 1407
int CXspFile::GetAnimationType(const Utils::WString &type)
1 cycrow 1408
{
218 cycrow 1409
	if ( type.Compare(L"TAT_TAGSINGLESTEP") )
1 cycrow 1410
		return TAT_SINGLE;
218 cycrow 1411
	else if ( type.Compare(L"TAT_TAGONESHOT") 
1412
				|| type.Compare(L"TAT_TAGONESHOT_REINIT") 
1413
				|| type.Compare(L"TAT_PINGPONG")
1414
				|| type.Compare(L"TAT_TAGLOOP") )
1 cycrow 1415
		return TAT_3;
1416
 
1417
	return TAT_NONE;
1418
}
1419
 
216 cycrow 1420
Utils::WString CXspFile::TypesListToString(Utils::CList<STypesSection> &list, bool deleteAfter)
109 cycrow 1421
{
216 cycrow 1422
	Utils::WString data;
109 cycrow 1423
 
113 cycrow 1424
	for(Utils::CList<STypesSection>::iterator itr = list.begin(); itr != list.end(); itr++) {
216 cycrow 1425
		data += (*itr)->sSection + L"; " + (long)(*itr)->lEntries.size() + L";\r\n";
1426
		for(Utils::WStringNode *str = (*itr)->lEntries.first(); str; str = (*itr)->lEntries.next()) {
1427
			data += str->str + L"\r\n";
109 cycrow 1428
		}
1429
 
1430
		if ( deleteAfter ) {
112 cycrow 1431
			(*itr)->lEntries.clear();
109 cycrow 1432
		}
1433
	}
1434
 
1435
	return data;
1436
}
1437
 
218 cycrow 1438
bool CXspFile::ReadAnimations(const Utils::WStringList &lIn, Utils::WStringList &lOut, int startRecord)
212 cycrow 1439
{
1440
	Utils::WString lastComment;
1441
	Utils::WString addEntry;
1442
	int remaining = 0;
1443
	Utils::WString lastType;
1444
	int newEntries = 0;
1445
	int entries = -1;
218 cycrow 1446
	for(auto itr = lIn.begin(); itr != lIn.end(); itr++)
212 cycrow 1447
	{
1448
		Utils::WString line = (*itr)->str;
1449
		line.removeChar('\r');
1450
		line.removeChar(9);
218 cycrow 1451
		if ( line.empty() || line[0] == '/' )
212 cycrow 1452
			continue;
218 cycrow 1453
		if ( entries == -1)
212 cycrow 1454
		{
218 cycrow 1455
			entries	= line.token(L";", 1);
212 cycrow 1456
			newEntries = entries - startRecord;
1457
		}
1458
		else
1459
		{
1460
			// remove comments, endspaces and last ;
1461
			Utils::WString sStriped = line;
218 cycrow 1462
			if ( sStriped.contains(L"//") )
212 cycrow 1463
			{
218 cycrow 1464
				if ( entries <= newEntries )
212 cycrow 1465
					lastComment = L"//" + sStriped.tokens(L"//", 2);
1466
				sStriped = sStriped.token(L"//", 1);
1467
			}
1468
			sStriped.removeEndSpace();
218 cycrow 1469
			if ( sStriped.right(1) == L";" )
212 cycrow 1470
				sStriped.truncate(-1);
1471
 
1472
			Utils::WString sRemainingLeft;
218 cycrow 1473
			if ( remaining > 0 )
212 cycrow 1474
				sRemainingLeft = sStriped;
1475
			else
1476
			{
1477
				// each line should be a new entry, with some exceptions
1478
				// potection for new lines
1479
				lastType = sStriped.token(L";", 1);
1480
 
1 cycrow 1481
				switch (CXspFile::GetAnimationType(lastType))
1482
				{
1483
					case TAT_SINGLE:
218 cycrow 1484
						remaining = (long)sStriped.token(L";", 5) + 1;
1485
						sRemainingLeft = sStriped.tokens(L";", 6);
1 cycrow 1486
						if ( entries <= newEntries )
218 cycrow 1487
							addEntry = sStriped.tokens(L";", 1, 5) + L";";
1 cycrow 1488
						break;
1489
					case TAT_3:
218 cycrow 1490
						remaining = (long)sStriped.token(L";", 5) + 1;
1491
						sRemainingLeft = sStriped.tokens(L";", 6);
1 cycrow 1492
						if ( entries <= newEntries )
218 cycrow 1493
							addEntry = sStriped.tokens(L";", 1, 5) + L";";
1 cycrow 1494
						break;
1495
 
1496
					default:
1497
						remaining = 0;
1498
						if ( entries <= newEntries )
1499
							addEntry = sStriped;
1500
 
1501
				}
1502
			}
1503
 
39 cycrow 1504
			if ( !sRemainingLeft.empty() )
1 cycrow 1505
			{
1506
				int tatType = CXspFile::GetAnimationType(lastType);
1507
				if ( tatType == TAT_SINGLE )
1508
				{
218 cycrow 1509
					if ( sRemainingLeft.isin(L";") )
1510
						remaining -= sRemainingLeft.countToken(L";");
39 cycrow 1511
					else if ( !sRemainingLeft.empty() )
1 cycrow 1512
						--remaining;
1513
 
1514
					if ( entries <= newEntries )
218 cycrow 1515
						addEntry += sRemainingLeft + L";";
1 cycrow 1516
				}
1517
				else if ( tatType == TAT_3 )
1518
				{
1519
					// last entry
1520
					if ( remaining == 1 )
1521
						--remaining;
218 cycrow 1522
					else if ( sRemainingLeft.isin(L";") )
1 cycrow 1523
					{
218 cycrow 1524
						if ( !sRemainingLeft.isin(L"TATF_COORDS") )
1 cycrow 1525
						{
218 cycrow 1526
							int amt = sRemainingLeft.countToken(L";") / 3;
1 cycrow 1527
							remaining -= amt;
218 cycrow 1528
							if ( remaining == 1 && (sRemainingLeft.countToken(L";") - (amt * 3)) == 1 )
1 cycrow 1529
								--remaining;
1530
						}
1531
						else
1532
						{
218 cycrow 1533
							int iRem = sRemainingLeft.countToken(L";");
1 cycrow 1534
							int iPos = 1;
1535
							while ( iPos < iRem )
1536
							{
218 cycrow 1537
								Utils::WString first = sRemainingLeft.token(L";", iPos);
1538
								if ( first.isin(L"TATF_COORDS") )
1 cycrow 1539
									iPos += 5;
1540
								else
1541
									iPos += 3;
1542
								--remaining;
1543
							}
1544
 
1545
							if ( remaining == 1 && iPos == iRem )
1546
								--remaining;
1547
						}
1548
					}
1549
 
1550
					if ( entries <= newEntries )
218 cycrow 1551
						addEntry += sRemainingLeft + L";";
1 cycrow 1552
				}
1553
			}
1554
 
1555
			if ( remaining <= 0 )
1556
			{
39 cycrow 1557
				if ( entries <= newEntries && !addEntry.empty())
1 cycrow 1558
				{
39 cycrow 1559
					if ( addEntry[(int)addEntry.length() - 1] != ';' )
218 cycrow 1560
						addEntry += L";";
170 cycrow 1561
					lOut.pushBack(addEntry + lastComment);
1 cycrow 1562
				}
1563
				--entries;
1564
			}
1565
		}
1566
	}
1567
 
170 cycrow 1568
	return !lOut.empty();
1 cycrow 1569
}
1570
 
218 cycrow 1571
void CXspFile::addAnimation(const Utils::WStringList &list)
1 cycrow 1572
{
170 cycrow 1573
	for(auto itr = list.begin(); itr != list.end(); itr++)
1574
		this->addAnimation((*itr)->str);
50 cycrow 1575
	_changed();
1 cycrow 1576
}
1577
 
216 cycrow 1578
void CXspFile::addAnimation(const Utils::WString& data) 
170 cycrow 1579
{ 
1580
	if (!_lAnimations.contains(data))
1581
	{
1582
		_lAnimations.pushBack(data);
1583
		_changed();
1584
	}
1585
}
1586
 
1 cycrow 1587
SText *CXspFile::FindShipText(int lang)
1588
{
1589
	if ( m_lText.empty() )
1590
		return NULL;
1591
 
1592
	SText *english = NULL;
1593
	SText *german = NULL;
1594
	SText *found = NULL;
1595
	for ( CListNode<SText> *node = m_lText.Front(); node; node = node->next() )
1596
	{
1597
		SText *text = node->Data();
1598
		// matched language
1599
		if ( text->iId == lang )
1600
			return text;
1601
		else if ( text->iId == 44 )
1602
			english = text;
1603
		else if ( text->iId == 49 )
1604
			german = text;
1605
		else if ( !found )
1606
			found = text;
1607
	}
1608
 
1609
	// if we've found an english version, use that
1610
	if ( english )
1611
		return english;
1612
	// otherwise try a german
1613
	if ( german )
1614
		return german;
1615
	// otherwise use any we've found (usually first one)
1616
	return found;
1617
}
1618
 
206 cycrow 1619
Utils::WString CXspFile::textName(int lang)
1 cycrow 1620
{
1621
	SText *t = FindShipText(lang);
1622
	if ( t )
1623
	{
1624
		// return the correct language text
39 cycrow 1625
		if ( !t->sName.empty() )
1 cycrow 1626
			return t->sName;
1627
		// we have found a text, but there is no ship name ??
1628
		else if ( lang != 44 )
1629
		{
1630
			// reget the english one
1631
			t = FindShipText(44);
39 cycrow 1632
			if ( t && !t->sName.empty() )
1 cycrow 1633
				return t->sName;
1634
		}
1635
	}
1636
 
1637
	// still not found one, return the ships name
203 cycrow 1638
	return this->shipName(lang);
1 cycrow 1639
}
1640
 
206 cycrow 1641
Utils::WString CXspFile::textDescription(int lang)
1 cycrow 1642
{
1643
	SText *t = FindShipText(lang);
1644
	if ( t )
1645
	{
1646
		// return the correct language text
39 cycrow 1647
		if ( !t->sDesc.empty() )
1 cycrow 1648
			return t->sDesc;
1649
		// we have found a text, but there is no ship name ??
1650
		else if ( lang != 44 )
1651
		{
1652
			// reget the english one
1653
			t = FindShipText(44);
39 cycrow 1654
			if ( t && !t->sDesc.empty() )
1 cycrow 1655
				return t->sDesc;
1656
		}
1657
	}
1658
 
1659
	// still not found one, return the ships name
48 cycrow 1660
	if ( !this->description().empty() ) return this->description();
206 cycrow 1661
	return this->shipName(lang);
1 cycrow 1662
}
1663
 
218 cycrow 1664
bool CXspFile::startExtractShip(CVirtualFileSystem *pVfs, const Utils::WString &sId, CProgressInfo *pProgress)
1 cycrow 1665
{
218 cycrow 1666
	m_sID = sId.remove('\r');
217 cycrow 1667
	while ( m_sID.right(1) == L";" )
35 cycrow 1668
		m_sID.truncate(-1);
1 cycrow 1669
 
217 cycrow 1670
	m_sData = pVfs->getTShipsEntry(m_sID);
35 cycrow 1671
 
1 cycrow 1672
	// get scene files
35 cycrow 1673
	if ( pProgress ) pProgress->UpdateStatus(IMPORTSHIP_SCENE);
1674
	if ( !this->extractSceneFiles(pVfs) )
1 cycrow 1675
		return false;
1676
 
1677
	return true;
1678
}
1679
 
218 cycrow 1680
bool CXspFile::extractShip(CVirtualFileSystem *pVfs, const Utils::WString &sId, CProgressInfo *progress)
1 cycrow 1681
{
35 cycrow 1682
	if ( !this->startExtractShip(pVfs, sId, progress) )
1 cycrow 1683
		return false;
1684
 
1685
	// read the scene file and get the files list
35 cycrow 1686
	if ( !this->processSceneFiles(pVfs, progress) )
1 cycrow 1687
		return false;
1688
 
1689
	// pack all the ship files
1690
	this->PackAllFiles();
1691
 
1692
	return true;
1693
}
1694
 
35 cycrow 1695
bool CXspFile::extractSceneFiles(CVirtualFileSystem *pVfs)
1 cycrow 1696
{
217 cycrow 1697
	m_pSceneFile = pVfs->extractGameFileToPackage(this, L"objects\\" + m_sData.token(L";", 17) + L".pbd", FILETYPE_SHIPSCENE, L"objects\\" + m_sData.token(L";", 17) + L".bod");
35 cycrow 1698
	if ( !m_pSceneFile ) return false;
217 cycrow 1699
	m_pCockpitFile = pVfs->extractGameFileToPackage(this, L"objects\\" + m_sData.token(L";", 18) + L".pbd", FILETYPE_COCKPITSCENE, L"objects\\" + m_sData.token(L";", 18) + L".bod");
1 cycrow 1700
 
1701
	return true;
1702
}
1703
 
218 cycrow 1704
bool CXspFile::readSceneModels(Utils::WStringList& out)
1 cycrow 1705
{
1706
	// read the scene file
170 cycrow 1707
	if (!m_pSceneFile)
1 cycrow 1708
		m_pSceneFile = this->GetFirstFile(FILETYPE_SHIPSCENE);
1709
 
170 cycrow 1710
	if (!m_pSceneFile)
1711
		return false;
1 cycrow 1712
 
1713
	// check if its packed
1714
	size_t datasize;
170 cycrow 1715
	unsigned char* data = m_pSceneFile->UncompressData((long*)&datasize, 0);
1716
 
1 cycrow 1717
	// if data wasn't compressed, then copy it itself as we are editing it
1718
	bool deleteData = false;
170 cycrow 1719
	if (data == m_pSceneFile->GetData())
1 cycrow 1720
	{
1721
		data = new unsigned char[m_pSceneFile->GetDataSize()];
1722
		memcpy(data, m_pSceneFile->GetData(), m_pSceneFile->GetDataSize());
1723
		deleteData = true;
1724
	}
1725
 
170 cycrow 1726
	if (data && datasize)
1 cycrow 1727
	{
170 cycrow 1728
		if (m_pSceneFile->CheckPackedExtension())
1 cycrow 1729
			data = UnPCKData(data, datasize, &datasize);
1730
	}
1731
 
170 cycrow 1732
	if (!data || !datasize)
1733
		return false;
1 cycrow 1734
 
1735
	size_t pos = 0;
1736
	bool newline = true;
1737
	bool online = false;
170 cycrow 1738
	while (pos < datasize)
1 cycrow 1739
	{
1740
		char c = data[pos];
1741
		++pos;
1742
 
1743
		// skip until next line
170 cycrow 1744
		if (!newline && !online)
1 cycrow 1745
		{
170 cycrow 1746
			if (c == '\n')
1 cycrow 1747
				newline = true;
1748
			continue;
1749
		}
1750
 
170 cycrow 1751
		if (newline)
1 cycrow 1752
		{
170 cycrow 1753
			if (c == ' ' || c == 9 || c == '\n' || c == '\r')
1 cycrow 1754
				continue;
1755
 
1756
			newline = false;
1757
 
170 cycrow 1758
			if (c == 'P' || c == 'p')
1 cycrow 1759
			{
170 cycrow 1760
				while (data[pos] == ' ') pos++;
1761
				unsigned char* line = (data + pos);
1762
				while (data[pos] != ' ' && data[pos] != ';') pos++;
1 cycrow 1763
				data[pos] = '\0';
170 cycrow 1764
				if (atoi((const char*)line) == out.size())
1 cycrow 1765
					online = true;
1766
			}
1767
		}
1768
		// this line is out model
170 cycrow 1769
		else if (online)
1 cycrow 1770
		{
170 cycrow 1771
			if (c == 'B' || c == 'b')
1 cycrow 1772
			{
170 cycrow 1773
				while (data[pos] == ' ') pos++;
1774
				unsigned char* line = (data + pos);
1775
				while (data[pos] != ';') pos++;
1 cycrow 1776
				data[pos] = '\0';
1777
 
226 cycrow 1778
				out.pushBack(Utils::WString::FromString((char*)line));
1 cycrow 1779
				online = false;
1780
			}
1781
		}
1782
	}
1783
 
170 cycrow 1784
	if (deleteData)
218 cycrow 1785
		delete []data;
1 cycrow 1786
 
170 cycrow 1787
	return true;
1 cycrow 1788
}
1789
 
218 cycrow 1790
void CXspFile::extractCutData(CVirtualFileSystem *pVfs, Utils::WStringList &sceneModels, bool add)
42 cycrow 1791
{
1792
	std::vector<int> cuts;
170 cycrow 1793
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
1794
	{
216 cycrow 1795
		Utils::WString data = node->Data()->sData;
1796
		int states = data.token(L";", 3);
218 cycrow 1797
		for ( int i = 0; i < states; i++ )
1798
		{
216 cycrow 1799
			int cutid = data.token(L";", (i * 2) + 5);
42 cycrow 1800
			if ( !cutid ) continue;
1801
			cuts.push_back(cutid);
1802
		}
1803
	}
1804
 
1805
	if ( cuts.empty() ) return;
1806
 
197 cycrow 1807
	if ( pVfs->extractGameFile(L"types/CutData.pck", CPackages::tempDirectory() + L"tmp.dat").empty()) return;
42 cycrow 1808
 
197 cycrow 1809
	CFileIO File(CPackages::tempDirectory() + L"tmp.dat");
52 cycrow 1810
	if ( !File.exists() ) return;
42 cycrow 1811
 
218 cycrow 1812
	std::vector<Utils::WString> lines;
170 cycrow 1813
	File.readLines(lines);
42 cycrow 1814
	int count = -1;
218 cycrow 1815
	for (auto itr = lines.begin(); itr != lines.end(); itr++)
1816
	{
1817
		Utils::WString line = *itr;
42 cycrow 1818
		line.removeChar('\r');
1819
		line.removeChar(' ');
1820
		line.removeFirstSpace();
1821
		if ( line[0] == '/' ) continue;
218 cycrow 1822
		if ( count == -1 ) count = line.token(L";", 1);
1823
		else 
1824
		{
1825
			std::vector<Utils::WString> words;
1826
			if(line.tokenise(L";", words))
1827
			{
1828
				for (size_t i = 0; i < words.size(); i += 2) {
42 cycrow 1829
					int cutid = words[i];
1830
					if ( !cutid ) continue;
218 cycrow 1831
					for ( std::vector<int>::iterator itr = cuts.begin(); itr != cuts.end(); itr++ )
1832
					{
1833
						if ( (*itr) == cutid )
1834
						{
1835
							this->addCutData(words[i] + L";" + words[i + 1] + L";");
1836
							if ( add ) 
170 cycrow 1837
								sceneModels.pushBack(words[i + 1]);
42 cycrow 1838
							break;
1839
						}
1840
					}
1841
				}
1842
			}
1843
		}
1844
	}
1845
}
1846
 
218 cycrow 1847
void CXspFile::extractDummies(CVirtualFileSystem *pVfs, Utils::WStringList& sceneModels, bool add)
1 cycrow 1848
{
170 cycrow 1849
	if (sceneModels.empty()) return;
31 cycrow 1850
 
1851
	bool extracted = false;
218 cycrow 1852
	if ( !pVfs->extractGameFile(L"types/dummies.pck", CPackages::tempDirectory() + L"tmp.dat").empty()) 
1853
	{
197 cycrow 1854
		CFileIO File(CPackages::tempDirectory() + L"tmp.dat");
52 cycrow 1855
		if ( File.exists() )
1 cycrow 1856
		{
218 cycrow 1857
			Utils::WString section;
1 cycrow 1858
			int secCount = 0;
218 cycrow 1859
			std::vector<Utils::WString> lines;
170 cycrow 1860
			if (File.readLines(lines))
1 cycrow 1861
			{
170 cycrow 1862
				for(auto itr = lines.begin(); itr != lines.end(); itr++)
1863
				{
218 cycrow 1864
					Utils::WString str = itr->remove(9).remove('\r');
170 cycrow 1865
					str.removeFirstSpace();
1866
					if (str.empty())
1867
						continue;
1868
					if (str[0] == '/')
1869
						continue;
1 cycrow 1870
 
170 cycrow 1871
					// not in a section yet
1872
					if (secCount <= 0)
1 cycrow 1873
					{
218 cycrow 1874
						section = str.token(L";", 1);
1875
						secCount = str.token(L";", 2).toInt();
170 cycrow 1876
					}
1877
					else
1878
					{
218 cycrow 1879
						Utils::WString first = str.token(L";", 1);
170 cycrow 1880
						if (sceneModels.contains(first))
1881
						{
216 cycrow 1882
							this->addDummy(section, str);
1 cycrow 1883
 
170 cycrow 1884
							if (add)
1 cycrow 1885
							{
170 cycrow 1886
								int pos = 4;
218 cycrow 1887
								int scene = str.token(L";", 3).toInt();
170 cycrow 1888
								for (int i = 0; i < scene; i++)
1889
								{
218 cycrow 1890
									sceneModels.pushBack(str.token(L";", 5 + (i * 2)));
170 cycrow 1891
									pos += 2;
1892
								}
1893
 
218 cycrow 1894
								int model = str.token(L";", pos).toInt();
170 cycrow 1895
								for (int i = 0; i < model; i++)
218 cycrow 1896
									sceneModels.pushBack(str.token(L";", pos + (i * 2) + 1));
1 cycrow 1897
							}
170 cycrow 1898
						}
1899
						--secCount;
1 cycrow 1900
 
1901
					}
1902
				}
1903
			}
1904
 
52 cycrow 1905
			File.remove();
1 cycrow 1906
		}
1907
	}
1908
}
1909
 
218 cycrow 1910
void CXspFile::extractComponants(CVirtualFileSystem *pVfs, const Utils::WStringList& sceneModels)
1 cycrow 1911
{
170 cycrow 1912
	if (sceneModels.empty()) return;
197 cycrow 1913
	if ( !pVfs->extractGameFile(L"types/components.pck", CPackages::tempDirectory() + L"tmp.dat").empty())
1 cycrow 1914
	{
197 cycrow 1915
		CFileIO File(CPackages::tempDirectory() + L"tmp.dat");
52 cycrow 1916
		if ( File.exists() )
1 cycrow 1917
		{
218 cycrow 1918
			Utils::WString file;
1919
			Utils::WString section;
1 cycrow 1920
			int secCount = 0;
1921
			int secCount2 = 0;
218 cycrow 1922
			std::vector<Utils::WString> lines;
170 cycrow 1923
			if (File.readLines(lines))
1 cycrow 1924
			{
170 cycrow 1925
				for(auto itr = lines.begin(); itr != lines.end(); itr++)
1926
				{
218 cycrow 1927
					Utils::WString str = itr->remove(9).remove('\r');
170 cycrow 1928
					str.removeFirstSpace();
1929
					if (str.empty())
1930
						continue;
1931
					if (str[0] == '/')
1932
						continue;
1 cycrow 1933
 
170 cycrow 1934
					// not in a section yet
1935
					if (secCount2)
1936
					{
1937
						if (sceneModels.contains(file))
216 cycrow 1938
							this->addComponent(section, file, str);
170 cycrow 1939
						--secCount2;
1940
					}
1941
					else if (secCount <= 0)
1942
					{
218 cycrow 1943
						section = str.token(L";", 1);
1944
						secCount = str.token(L";", 2).toInt();
170 cycrow 1945
					}
1946
					else
1947
					{
218 cycrow 1948
						file = str.token(L";", 1);
1949
						secCount2 = str.token(L";", 2).toInt();
170 cycrow 1950
						--secCount;
1951
					}
1 cycrow 1952
				}
1953
			}
1954
 
52 cycrow 1955
			File.remove();
1 cycrow 1956
		}
1957
	}
1958
}
1959
 
197 cycrow 1960
bool CXspFile::getTextureList(Utils::WStringList &list, const unsigned char *olddata, size_t size) const
1 cycrow 1961
{
1962
	if ( !olddata || !size )
1963
		return false;
1964
 
1965
	size_t startLine = 0;
218 cycrow 1966
	Utils::WString line;
1 cycrow 1967
	size_t pos = 0;
1968
 
1969
	unsigned char *data = new unsigned char[size];
1970
	memcpy(data, olddata, size);
1971
 
1972
	while ( (pos++) < size )
1973
	{
1974
		if ( data[pos] == '\n' )
1975
		{
1976
			data[pos] = '\0';
218 cycrow 1977
			line = Utils::WString::FromString((char *)(data + startLine));
114 cycrow 1978
			line.removeChar(9);
1979
			line.removeChar('\r');
1980
			line.removeFirstSpace();
1 cycrow 1981
 
114 cycrow 1982
			if ( !line.empty() && line[0] != '/' )
1 cycrow 1983
			{
218 cycrow 1984
				Utils::WString first = line.token(L":", 1);
1985
				if ( first.Compare(L"MATERIAL6") )
1 cycrow 1986
				{
218 cycrow 1987
					Utils::WString material = line.tokens(L":", 2);
1988
					std::vector<Utils::WString> strs;
1989
					int num = material.token(L";", 5);
1990
					if(material.tokens(L";", 6).tokenise(L"; ", strs))
1 cycrow 1991
					{
218 cycrow 1992
						for(size_t i = 0; i < strs.size(); i++) {
1993
							Utils::WString type = strs[i].token(L";", 1);
1994
							Utils::WString valtype = strs[i].token(L";", 2);			
1995
							if ( valtype.Compare(L"SPTYPE_STRING") ) {
1996
								Utils::WString file = strs[i].token(L";", 3);
170 cycrow 1997
								if(!list.contains(file))
213 cycrow 1998
									list.pushBack(file, L"");
114 cycrow 1999
							}
2000
						}
1 cycrow 2001
					}
2002
				}
2003
			}
2004
 
2005
			startLine = pos + 1;
2006
		}
2007
	}
2008
 
2009
	delete [] data;
2010
 
2011
	return true;
2012
}
2013
 
35 cycrow 2014
void CXspFile::extractTextures(CVirtualFileSystem *pVfs)
1 cycrow 2015
{
197 cycrow 2016
	Utils::WStringList lTextures;
1 cycrow 2017
 
2018
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2019
	{
2020
		C_File *f = node->Data();
2021
		if ( f->GetFileType() != FILETYPE_SHIPMODEL )
2022
			continue;
2023
 
115 cycrow 2024
		bool deleteData = false;
114 cycrow 2025
		unsigned char *data = NULL;
2026
		size_t size;
2027
 
1 cycrow 2028
		// cant do these yet
197 cycrow 2029
		if (f->checkFileExt(L"pbb") || f->checkFileExt(L"bob"))
1 cycrow 2030
		{
115 cycrow 2031
			data = f->BobDecompile(&size);
2032
			if ( !data || !size ) {
114 cycrow 2033
				// search for the pbd or bod files that match and use them instead
197 cycrow 2034
				Utils::WString file;
114 cycrow 2035
 
197 cycrow 2036
				file = CFileIO(f->getNameDirectory(NULL)).changeFileExtension(L"pbd");
2037
				file = pVfs->extractGameFile(file, CPackages::tempDirectory() + L"tmp.tmp");
114 cycrow 2038
 
2039
				if ( file.empty() ) {
197 cycrow 2040
					file = CFileIO(f->getNameDirectory(NULL)).changeFileExtension(L"bod");
2041
					file = pVfs->extractGameFile(file, CPackages::tempDirectory() + L"tmp.tmp");
114 cycrow 2042
				}
2043
 
2044
				if ( !file.empty() ) {
2045
					CFileIO File(file);
2046
					if ( File.exists() ) {
2047
						data = File.readAll(&size);
2048
						File.remove();
2049
					}
2050
				}
2051
 
2052
				if ( data && size ) 
170 cycrow 2053
					this->getTextureList(lTextures, data, size);
1 cycrow 2054
				continue;
114 cycrow 2055
			}
1 cycrow 2056
 
115 cycrow 2057
			deleteData = true;
1 cycrow 2058
		}
2059
 
115 cycrow 2060
		if ( !data || !size ) {
2061
			if ( !f->GetData() )
2062
			{
2063
				if ( !f->ReadFromFile() )
2064
					continue;
2065
			}
1 cycrow 2066
 
115 cycrow 2067
 
213 cycrow 2068
			if ( f->checkFileExt(L"pbb") || f->checkFileExt(L"pbd") )
115 cycrow 2069
				data = f->UnPCKFile(&size);
2070
			else
2071
			{
2072
				data = f->GetData();
2073
				size = f->GetDataSize();
2074
			}
1 cycrow 2075
		}
170 cycrow 2076
		this->getTextureList(lTextures, data, size);
1 cycrow 2077
 
115 cycrow 2078
		if ( deleteData ) delete data;
1 cycrow 2079
	}
2080
 
170 cycrow 2081
	for(auto itr = lTextures.begin(); itr != lTextures.end(); itr++)
1 cycrow 2082
	{
170 cycrow 2083
		CFileIO F((*itr)->str);
196 cycrow 2084
		if ( F.isFileExtension(L"fx") ) {
116 cycrow 2085
			/*
218 cycrow 2086
			if ( !pVfs->extractGameFileToPackage(this, "shader\\1_1\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
116 cycrow 2087
				pVfs->extractGameFileToPackage(this, "shader\\1_1\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
218 cycrow 2088
			if ( !pVfs->extractGameFileToPackage(this, "shader\\1_4\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
116 cycrow 2089
				pVfs->extractGameFileToPackage(this, "shader\\1_4\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
218 cycrow 2090
			if ( !pVfs->extractGameFileToPackage(this, "shader\\2_0\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
116 cycrow 2091
				pVfs->extractGameFileToPackage(this, "shader\\2_0\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
218 cycrow 2092
			if ( !pVfs->extractGameFileToPackage(this, "shader\\2_a\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
116 cycrow 2093
				pVfs->extractGameFileToPackage(this, "shader\\2_a\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
218 cycrow 2094
			if ( !pVfs->extractGameFileToPackage(this, "shader\\2_b\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
116 cycrow 2095
				pVfs->extractGameFileToPackage(this, "shader\\2_b\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
218 cycrow 2096
			if ( !pVfs->extractGameFileToPackage(this, "shader\\3_0\\" + Utils::WString(node->str.ToString()), FILETYPE_SHIPOTHER) )
116 cycrow 2097
				pVfs->extractGameFileToPackage(this, "shader\\3_0\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
2098
				*/
114 cycrow 2099
		}
2100
		else {
197 cycrow 2101
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str, FILETYPE_SHIPOTHER) )
116 cycrow 2102
				continue;
2103
 
197 cycrow 2104
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str.token(L".", -1), FILETYPE_SHIPOTHER) )
116 cycrow 2105
				continue;
2106
 
197 cycrow 2107
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str + L".dds", FILETYPE_SHIPOTHER) )
116 cycrow 2108
				continue;
2109
 
197 cycrow 2110
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + F.changeFileExtension(L"dds"), FILETYPE_SHIPOTHER) )
116 cycrow 2111
				continue;
2112
 
197 cycrow 2113
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str, FILETYPE_SHIPOTHER) )
116 cycrow 2114
				continue;
2115
 
197 cycrow 2116
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str.token(L".", -1), FILETYPE_SHIPOTHER) )
116 cycrow 2117
				continue;
2118
 
197 cycrow 2119
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str + L".jpg", FILETYPE_SHIPOTHER) )
116 cycrow 2120
				continue;
2121
 
197 cycrow 2122
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + F.changeFileExtension(L"jpg"), FILETYPE_SHIPOTHER) )
116 cycrow 2123
				continue;
114 cycrow 2124
		}
1 cycrow 2125
	}
2126
}
2127
 
197 cycrow 2128
bool CXspFile::addTextFromFile(const Utils::WString &sFile, int textId)
1 cycrow 2129
{
197 cycrow 2130
	Utils::WString file = sFile;
39 cycrow 2131
 
1 cycrow 2132
	bool remove = false;
196 cycrow 2133
	if ( CFileIO(file).isFileExtension(L"pck") )
1 cycrow 2134
	{
39 cycrow 2135
		C_File F;
170 cycrow 2136
		F.setFilename(file);
1 cycrow 2137
		F.UnPCKFile();
197 cycrow 2138
		if (F.writeToFile(CPackages::tempDirectory() + L"tmp.dat"))
1 cycrow 2139
		{
2140
			remove = true;
197 cycrow 2141
			file = CPackages::tempDirectory() + L"tmp.dat";
1 cycrow 2142
		}
2143
	}
2144
 
78 cycrow 2145
	/*
68 cycrow 2146
	std::wfstream fileStream(file.c_str());
2147
	if ( fileStream.is_open() ) {
2148
		while(!fileStream.eof()) {
2149
			std::wstring line;
2150
			std::getline(fileStream, line);
2151
			int i =0;
2152
		}
2153
		fileStream.close();
2154
	}
78 cycrow 2155
	*/
68 cycrow 2156
 
118 cycrow 2157
	CFileIO F(file);
2158
	if ( F.exists() && F.startRead() ) {
2159
		bool ret = this->_addTextFromFile(F, textId);
2160
		F.close();
1 cycrow 2161
 
52 cycrow 2162
		if ( remove ) CFileIO::Remove(file);
50 cycrow 2163
		_changed();
1 cycrow 2164
		return ret;
2165
	}
2166
 
2167
	return false;
2168
}
2169
 
218 cycrow 2170
bool CXspFile::importBodies(const Utils::WStringList &sceneModels, const Utils::WString &filename)
1 cycrow 2171
{
2172
	CFileIO File(filename);
52 cycrow 2173
	if ( File.exists() )
1 cycrow 2174
	{
218 cycrow 2175
		Utils::WString sSection;
1 cycrow 2176
		int section = 0;
218 cycrow 2177
		std::vector<Utils::WString> lines;
170 cycrow 2178
		if (File.readLines(lines))
1 cycrow 2179
		{
170 cycrow 2180
			for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 2181
			{
218 cycrow 2182
				Utils::WString l = *itr;
170 cycrow 2183
				l.removeChar(9);
2184
				l.removeChar('\r');
2185
				l.removeFirstSpace();
2186
				if (l.empty())
2187
					continue;
2188
				if (l[0] == '/')
2189
					continue;
2190
 
2191
				// are we looking for a section
2192
				if (section <= 0)
1 cycrow 2193
				{
218 cycrow 2194
					sSection = l.token(L";", 1);
2195
					section = l.token(L";", 2).toInt();
170 cycrow 2196
				}
2197
				else
2198
				{
218 cycrow 2199
					std::vector<Utils::WString> strs;
2200
					if(l.tokenise(L";", strs))
1 cycrow 2201
					{
218 cycrow 2202
						for (size_t i = 0; i < strs.size(); i++)
170 cycrow 2203
						{
2204
							strs[i].removeEndSpace();
2205
							strs[i].removeFirstSpace();
2206
							if (strs[i].empty())
2207
								continue;
2208
							if (sceneModels.contains(strs[i]))
2209
								this->addBody(sSection, strs[i]);
2210
							--section;
2211
						}
1 cycrow 2212
					}
2213
				}
2214
			}
170 cycrow 2215
			return true;
1 cycrow 2216
		}
2217
	}
2218
 
2219
	return false;
2220
}
2221
 
218 cycrow 2222
bool CXspFile::ImportCockpits(const Utils::WString &filename)
1 cycrow 2223
{
2224
	CFileIO File(filename);
52 cycrow 2225
	if ( File.exists() )
1 cycrow 2226
	{
217 cycrow 2227
		std::vector<Utils::WString> lines;
170 cycrow 2228
		if (File.readLines(lines))
1 cycrow 2229
		{
170 cycrow 2230
			int entries = 0;
2231
			auto itr = lines.begin();
2232
			while(itr != lines.end())
1 cycrow 2233
			{
217 cycrow 2234
				Utils::WString str = itr->remove(9).remove('\r');
170 cycrow 2235
				str.removeFirstSpace();
2236
				if (str.empty())
2237
					itr = lines.erase(itr);
2238
				else if (str[0] == '/')
2239
					itr = lines.erase(itr);
2240
				else if (!entries)
2241
				{
217 cycrow 2242
					entries = str.token(L";", 2).toInt();
170 cycrow 2243
					itr = lines.erase(itr);
2244
				}
2245
				else
2246
					itr++;
1 cycrow 2247
			}
2248
 
170 cycrow 2249
			// now get all the entries from TShips
2250
			for (int i = 0; i < 6; i++)
1 cycrow 2251
			{
217 cycrow 2252
				int idx = m_sData.token(L";", 32 + (i * 2));
170 cycrow 2253
				if (static_cast<size_t>(idx) < lines.size() && idx)
2254
				{
216 cycrow 2255
					Utils::WString turret = lines[idx];
170 cycrow 2256
					int pos = -1;
216 cycrow 2257
					Utils::WString id;
2258
					while (id.empty() && pos > -100) id = turret.token(L";", pos--);
217 cycrow 2259
					m_sData = m_sData.replaceToken(L";", 32 + (i * 2), id + L"(" + (long)idx + L")");
1 cycrow 2260
 
216 cycrow 2261
					this->addCockpit(turret, 0);
170 cycrow 2262
				}
1 cycrow 2263
			}
2264
		}
2265
		return true;
2266
	}
2267
	return false;
2268
}
2269
 
35 cycrow 2270
bool CXspFile::extractCockpits(CVirtualFileSystem *pVfs)
1 cycrow 2271
{
197 cycrow 2272
	if ( !pVfs->extractGameFile(L"types/TCockpits.pck", CPackages::tempDirectory() + L"tmp.dat").empty() ) {
218 cycrow 2273
		bool ret = this->ImportCockpits((CPackages::tempDirectory() + L"tmp.dat"));
197 cycrow 2274
		CFileIO::Remove(CPackages::tempDirectory() + L"tmp.dat");
1 cycrow 2275
 
2276
		return ret;
2277
	}
2278
 
2279
	return false;
2280
}
2281
 
218 cycrow 2282
bool CXspFile::extractBodies(CVirtualFileSystem *pVfs, const Utils::WStringList &sceneModels)
1 cycrow 2283
{
170 cycrow 2284
	if (sceneModels.empty()) return false;
31 cycrow 2285
 
197 cycrow 2286
	if ( !pVfs->extractGameFile(L"types/Bodies.pck", CPackages::tempDirectory() + L"tmp.dat").empty() ) {
218 cycrow 2287
		bool ret = this->importBodies(sceneModels, (CPackages::tempDirectory() + L"tmp.dat"));
197 cycrow 2288
		CFileIO::Remove(CPackages::tempDirectory() + L"tmp.dat");
1 cycrow 2289
 
2290
		return ret;
2291
	}
2292
 
2293
	return false;
2294
}
2295
 
118 cycrow 2296
bool CXspFile::_addTextFromFile(CFileIO &F, int textId)
1 cycrow 2297
{
14 cycrow 2298
	if ( textId == -1 && !m_sData.empty() )
217 cycrow 2299
		textId = m_sData.token(L";", 7);
1 cycrow 2300
 
2301
	if ( textId <= 0 )
2302
		return false;
2303
 
118 cycrow 2304
	if ( !F.isOpened() )
1 cycrow 2305
		return false;
2306
 
2307
	bool added = false;
2308
 
217 cycrow 2309
	Utils::WString shipName;
2310
	Utils::WString shipDesc;
1 cycrow 2311
 
68 cycrow 2312
	int lastAddedGameID = 0;
2313
	int currentGameID = 0;
1 cycrow 2314
	int lang = 0;
2315
	bool inpage = false;
118 cycrow 2316
 
2317
	while(!F.atEnd()) {
39 cycrow 2318
		if ( !shipName.empty() && !shipDesc.empty() )
1 cycrow 2319
		{
2320
			added = true;
2321
			break;
2322
		}
2323
 
217 cycrow 2324
		Utils::WString line = F.readEndOfLine();
39 cycrow 2325
		line.removeChar(9);
2326
		line.removeChar('\r');
2327
		line.removeFirstSpace();
118 cycrow 2328
 
1 cycrow 2329
		if ( inpage )
2330
		{
217 cycrow 2331
			if ( line.left(6).Compare(L"</page") ) {
68 cycrow 2332
				inpage = false;
2333
				continue;
2334
			}
1 cycrow 2335
 
2336
			// find matching id
217 cycrow 2337
			if ( line.left(6).Compare(L"<t id=") )
1 cycrow 2338
			{
217 cycrow 2339
				int pos = line.findPos(L"id=\"", 0);
1 cycrow 2340
				if ( pos != -1 )
2341
				{
68 cycrow 2342
					pos += 4;
217 cycrow 2343
					int endpos = line.findPos(L"\"", pos);
1 cycrow 2344
					if ( endpos != -1 )
2345
					{
68 cycrow 2346
						int id = line.mid(pos, endpos);
1 cycrow 2347
						if ( id == textId || id == (textId + 1) )
2348
						{
217 cycrow 2349
							pos = line.findPos(L">", endpos);
1 cycrow 2350
							if ( pos != -1 )
2351
							{
226 cycrow 2352
								endpos = line.findPos(L"</t>", pos);
1 cycrow 2353
								if ( endpos != -1 )
2354
								{
2355
									if ( id == textId )
68 cycrow 2356
										shipName = line.mid(pos + 1, endpos);
1 cycrow 2357
									else
68 cycrow 2358
										shipDesc = line.mid(pos + 1, endpos);
2359
									lastAddedGameID = currentGameID;
1 cycrow 2360
								}
2361
							}
2362
						}
2363
					}
2364
				}
2365
			}
2366
		}
2367
		else if ( lang ) // search for page 17
2368
		{
217 cycrow 2369
			if ( line.left(8).Compare(L"<page id") )
1 cycrow 2370
			{
217 cycrow 2371
				int pos = line.findPos(L"id=\"");
1 cycrow 2372
				if ( pos != -1 )
2373
				{
68 cycrow 2374
					pos += 4;
217 cycrow 2375
					int endpos = line.findPos(L"\"", pos);
1 cycrow 2376
					if ( endpos != -1 )
2377
					{
217 cycrow 2378
						Utils::WString sId = line.mid(pos, endpos);
39 cycrow 2379
						int id = sId;
68 cycrow 2380
						if ( sId.length() > 4 ) {
2381
							id = sId.right(4);
2382
							currentGameID = sId.left(sId.length() - 4);
2383
						}
2384
 
2385
						if ( currentGameID >= lastAddedGameID && id == 17 )
1 cycrow 2386
							inpage = true;
2387
					}
2388
				}
2389
			}
2390
		}
217 cycrow 2391
		else if ( line.left(12).Compare(L"<language id") )
1 cycrow 2392
		{
217 cycrow 2393
			int pos = line.findPos(L"id=\"");
1 cycrow 2394
			if ( pos != -1 )
2395
			{
68 cycrow 2396
				// move past the id=
2397
				pos += 4;
2398
 
217 cycrow 2399
				Utils::WString s = line.right(-pos);
2400
				Utils::WString s2 = line.mid(pos, -1);
2401
				int endpos = line.findPos(L"\"", pos);
1 cycrow 2402
				if ( endpos != -1 )
68 cycrow 2403
					lang = line.mid(pos, endpos);
1 cycrow 2404
			}
2405
		}
2406
	}
2407
 
2408
	// incase we only found the shipname
39 cycrow 2409
	if ( !shipName.empty() )
1 cycrow 2410
		added = true;
2411
 
2412
	if ( added )
2413
	{
50 cycrow 2414
		if ( lang == 44 || this->name().empty())
1 cycrow 2415
		{
50 cycrow 2416
			this->setName(shipName);
217 cycrow 2417
			this->setDescription(shipDesc.findReplace(L"&amp", L"&"));
1 cycrow 2418
		}
216 cycrow 2419
		this->addText(lang, shipName, shipDesc);
1 cycrow 2420
		return true;	
2421
	}
2422
 
2423
	return false;
2424
}
2425
 
31 cycrow 2426
void CXspFile::ExtractTexts(CCatFile *catFile, CCatFile *secondCatFile, int textId)
1 cycrow 2427
{
124 cycrow 2428
	for (auto itr = catFile->GetFiles()->begin(); itr != catFile->GetFiles()->end(); itr++ )
1 cycrow 2429
	{
124 cycrow 2430
		SInCatFile *f = *itr;
213 cycrow 2431
		if ( !f->sFile.left(2).Compare(L"t\\") && !f->sFile.left(2).Compare(L"t/") )
1 cycrow 2432
			continue;
2433
 
2434
		// extract the text file and read in the data
213 cycrow 2435
		bool extracted = catFile->extractFile(f->sFile, CPackages::tempDirectory() + L"/tmp.dat");
2436
		if ( !extracted && secondCatFile ) extracted = secondCatFile->extractFile(f->sFile, CPackages::tempDirectory() + L"/tmp.dat");
31 cycrow 2437
		if ( extracted ) {
197 cycrow 2438
			this->addTextFromFile(CPackages::tempDirectory() + L"/tmp.dat", textId);
2439
			CFileIO::Remove(CPackages::tempDirectory() + L"/tmp.dat");
1 cycrow 2440
		}
2441
	}
2442
}
2443
 
218 cycrow 2444
bool CXspFile::processSceneFileSection(int section, CVirtualFileSystem *pVfs, Utils::WStringList &lModels, CProgressInfo *progress)
1 cycrow 2445
{
2446
	if ( progress ) progress->UpdateStatus(section);
2447
 
2448
	switch ( section )
2449
	{
2450
		case IMPORTSHIP_COMPONANT:
170 cycrow 2451
			if (lModels.empty()) return false;
35 cycrow 2452
			this->extractComponants(pVfs, lModels);
1 cycrow 2453
			break;
2454
 
2455
		case IMPORTSHIP_MODELS:
2456
			{
170 cycrow 2457
				if (lModels.empty()) return false;
2458
				for(auto itr = lModels.begin(); itr != lModels.end(); itr++)
1 cycrow 2459
				{
170 cycrow 2460
					if ((*itr)->str.isNumber() ) // count be componants or dummy
1 cycrow 2461
						continue;
218 cycrow 2462
					if ( pVfs->extractGameFileToPackage(this, L"objects\\" + (*itr)->str + L".pbb", FILETYPE_SHIPMODEL, L"objects\\" + (*itr)->str + L".bob") )
1 cycrow 2463
						continue;
218 cycrow 2464
					if ( pVfs->extractGameFileToPackage(this, L"objects\\" + (*itr)->str + ".pbd", FILETYPE_SHIPMODEL, L"objects\\" + (*itr)->str + L".bod") )
1 cycrow 2465
						continue;
2466
				}
2467
			}
2468
			break;
2469
 
2470
		case IMPORTSHIP_DUMMIES:
170 cycrow 2471
			if (lModels.empty()) return false;
35 cycrow 2472
			this->extractDummies(pVfs, lModels, true);
42 cycrow 2473
			this->extractCutData(pVfs, lModels, true);
1 cycrow 2474
			break;
2475
 
2476
		// extract the textures
2477
		case IMPORTSHIP_TEXTURES:
35 cycrow 2478
			this->extractTextures(pVfs);
1 cycrow 2479
			break;
2480
 
2481
		case IMPORTSHIP_TEXTS:
2482
			// extract the text file entries
217 cycrow 2483
			pVfs->extractTexts(this, m_sData.token(L";", 7));
1 cycrow 2484
			break;
2485
 
2486
		case IMPORTSHIP_BODIES:
2487
			// extract the bodies entries
170 cycrow 2488
			if (lModels.empty()) return false;
35 cycrow 2489
			this->extractBodies(pVfs, lModels);
1 cycrow 2490
			break;
2491
 
2492
		case IMPORTSHIP_COCKPITS:
2493
			// extract the cockpit entries
35 cycrow 2494
			this->extractCockpits(pVfs);
1 cycrow 2495
			break;
2496
	}
2497
 
2498
	return true;
2499
}
2500
 
35 cycrow 2501
bool CXspFile::processSceneFiles(CVirtualFileSystem *pVfs, CProgressInfo *progress)
1 cycrow 2502
{
2503
	// now lets parse our files
2504
	if ( progress ) progress->UpdateStatus(IMPORTSHIP_EXTRACTSCENE);
218 cycrow 2505
	Utils::WStringList lModels;
170 cycrow 2506
	if(!readSceneModels(lModels))
1 cycrow 2507
		return false;
2508
 
2509
	// extract componants, and add extra items to list
35 cycrow 2510
	if ( !this->processSceneFileSection(IMPORTSHIP_COMPONANT, pVfs, lModels, progress) )
1 cycrow 2511
		return false;
2512
 
2513
	//lets first find any model files
35 cycrow 2514
	if ( !this->processSceneFileSection(IMPORTSHIP_MODELS, pVfs, lModels, progress) )
1 cycrow 2515
		return false;
2516
 
2517
	// extract the dummies
35 cycrow 2518
	if ( !this->processSceneFileSection(IMPORTSHIP_DUMMIES, pVfs, lModels, progress) )
1 cycrow 2519
		return false;
2520
 
2521
	// extract the textures
35 cycrow 2522
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTURES, pVfs, lModels, progress) )
1 cycrow 2523
		return false;
2524
 
2525
	// extract the text file entries
35 cycrow 2526
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTS, pVfs, lModels, progress) )
1 cycrow 2527
		return false;
2528
 
2529
	// extract the bodies entries
35 cycrow 2530
	if ( !this->processSceneFileSection(IMPORTSHIP_BODIES, pVfs, lModels, progress) )
1 cycrow 2531
		return false;
2532
 
2533
	// extract the cockpit entries
35 cycrow 2534
	if ( !this->processSceneFileSection(IMPORTSHIP_COCKPITS, pVfs, lModels, progress) )
1 cycrow 2535
		return false;
2536
 
2537
	return true;
2538
}
2539
 
2540
 
2541
void CXspFile::PackAllFiles()
2542
{
2543
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2544
	{
2545
		C_File *f = node->Data();
2546
		if ( f->GetFileType() == FILETYPE_SHIPSCENE || f->GetFileType() == FILETYPE_COCKPITSCENE || f->GetFileType() == FILETYPE_SHIPMODEL || f->GetFileType() == FILETYPE_SHIPOTHER )
41 cycrow 2547
		{	
2548
			/*
1 cycrow 2549
			if ( f->CheckFileExt("bod") )
2550
			{
2551
				if ( f->PCKFile() )
2552
					f->ChangeFileExt("pbd");
41 cycrow 2553
			}	
42 cycrow 2554
 
213 cycrow 2555
			else */if ( f->checkFileExt(L"bob") )
1 cycrow 2556
			{
2557
				if ( f->PCKFile() )
213 cycrow 2558
					f->changeFileExt(L"pbb");
42 cycrow 2559
			}
1 cycrow 2560
		}
2561
	}
2562
}
2563
 
2564
void CXspFile::AdjustCockpits()
2565
{
2566
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
2567
	{
2568
		SCockpit *c = node->Data();
2569
		if ( c->iIndex < 0 )
2570
			continue;
2571
 
216 cycrow 2572
		Utils::WString id = c->sCockpit.token(L";", 19);
1 cycrow 2573
 
2574
		for ( int i = 0; i < 6; i++ )
2575
		{
217 cycrow 2576
			Utils::WString tId = m_sData.token(L";", 32 + (i * 2));
39 cycrow 2577
			if ( tId.isNumber() && ((int)tId) == c->iIndex )
217 cycrow 2578
				m_sData = m_sData.replaceToken(L";", 32 + (i * 2), id + L"(" + Utils::WString::Number(c->iIndex) + L")");
1 cycrow 2579
		}
2580
	}
2581
}
2582
 
216 cycrow 2583
Utils::WString CXspFile::formatShipData(const Utils::WStringList &cockpits, int *text, int game)
1 cycrow 2584
{
217 cycrow 2585
	Utils::WString data = (game == GAME_X3) ? this->getX3ShipData() : this->getTCShipData();
1 cycrow 2586
	// do turrets
2587
	for ( int t = 0; t < 6; t++ )
2588
	{
2589
		int oldPos = 0;
216 cycrow 2590
		Utils::WString turret = data.token(L";", 32 + (t * 2));
39 cycrow 2591
		if ( !turret.isNumber() )
1 cycrow 2592
		{
216 cycrow 2593
			if ( turret.contains(L"(") )
1 cycrow 2594
			{
216 cycrow 2595
				oldPos = turret.tokens(L"(", 2).token(L")", 1);
2596
				turret = turret.token(L"(", 1);
1 cycrow 2597
			}
170 cycrow 2598
			int pos = cockpits.findPos(turret);
1 cycrow 2599
			if ( pos < 0 )	pos = oldPos;
170 cycrow 2600
			if (static_cast<size_t>(pos) >= cockpits.size()) pos = 0;
216 cycrow 2601
			data = data.replaceToken(L";", 32 + (t * 2), (long)pos);
1 cycrow 2602
		}
2603
	}
2604
	// adjust the weapons
2605
	int mask = this->GetLaserMask(game - 1);
2606
	if ( mask != -1 )
216 cycrow 2607
		data = data.replaceToken(L";", 19, (long)mask);
1 cycrow 2608
	mask = this->GetMissileMask(game - 1);
2609
	if ( mask != -1 )
216 cycrow 2610
		data = data.replaceToken(L";", 25, (long)mask);
1 cycrow 2611
 
2612
	// fix the ship text
2613
	if ( m_iOrgDesc > 0 )
2614
		(*text) = m_iOrgDesc;
216 cycrow 2615
	data = data.replaceToken(L";", 7, (long)*text);
1 cycrow 2616
 
2617
	// add the ware id
39 cycrow 2618
	data.removeChar(9);
2619
	data.removeEndSpace();
1 cycrow 2620
	// remove the end ;
216 cycrow 2621
	while ( data.right(1) == L";" ) data.truncate(-1);
217 cycrow 2622
	data = data.replaceToken(L";", data.countToken(L";"), this->shipID());
216 cycrow 2623
	if ( data.right(1) != L";" )
2624
		data += L";";
1 cycrow 2625
 
2626
	return data;
35 cycrow 2627
}
2628