Subversion Repositories spk

Rev

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