Subversion Repositories spk

Rev

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

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