Subversion Repositories spk

Rev

Rev 211 | Rev 213 | 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
 
39 cycrow 61
void CXspFile::AddText ( int id, const Utils::String &name, const Utils::String &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
 
39 cycrow 100
void CXspFile::AddDummy ( const Utils::String &section, const Utils::String &data )
1 cycrow 101
{
102
	SDummy *d = new SDummy;
103
	d->sData = data;
104
	d->sSection = section;
105
 
39 cycrow 106
	if ( d->sData.right(1) != ";" )
1 cycrow 107
		d->sData += ";";
108
 
109
	m_lDummy.push_back ( d );
110
 
50 cycrow 111
	_changed();
1 cycrow 112
}
113
 
39 cycrow 114
void CXspFile::AddComponent ( const Utils::String &section, const Utils::String &section2, const Utils::String &data )
1 cycrow 115
{
116
	SComponent *c = new SComponent;
117
	c->sData = data;
118
	c->sSection = section;
119
	c->sSection2 = section2;
120
 
39 cycrow 121
	if ( c->sData.right(1) != ";" )
1 cycrow 122
		c->sData += ";";
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" ";
212
		values += cockpit->sCockpit.toWString() + L"\n";
1 cycrow 213
	}
214
 
14 cycrow 215
	for ( CListNode<SText> *tNode = m_lText.Front(); tNode; tNode = tNode->next() )
207 cycrow 216
		values += Utils::WString(L"Text: ") + (long)tNode->Data()->iId + L"|" + tNode->Data()->sName.toWString().findReplace(L"|", L"<::PiPe::>") + L"|" + tNode->Data()->sDesc.toWString() + L"\n";
1 cycrow 217
 
14 cycrow 218
	for ( CListNode<SComponent> *cNode = m_lComponent.Front(); cNode; cNode = cNode->next() )
207 cycrow 219
		values += L"Component: " + cNode->Data()->sData.toWString().findReplace(L"|", L"<::PiPe::>") + L"|" + cNode->Data()->sSection.toWString().findReplace(L"|", L"<::PiPe::>") + L"|" + cNode->Data()->sSection2.toWString() + L"\n";
1 cycrow 220
 
14 cycrow 221
	for ( CListNode<SDummy> *dNode = m_lDummy.Front(); dNode; dNode = dNode->next() )
207 cycrow 222
		values += L"Dummy: " + dNode->Data()->sData.toWString().findReplace(L"|", L"<::PiPe::>") + L"|" + dNode->Data()->sSection.toWString() + 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++)
207 cycrow 229
		values += L"CutData: " + (*itr)->str.toWString() + L"\n";
170 cycrow 230
	for (auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
207 cycrow 231
		values += L"Bodies: " + (*itr)->str.toWString() + L"\n";
170 cycrow 232
	for (auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
207 cycrow 233
		values += L"Animations: " + (*itr)->str.toWString() + 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") )
256
		this->addCutData(rest.toString());
257
	else if ( first.Compare(L"Bodies") )
258
		this->addBodies(rest.toString());
259
	else if ( first.Compare(L"Animations") )
260
		this->addAnimation(rest.toString());
261
	else if ( first.Compare(L"Cockpit") )
262
		this->AddCockpit(rest.toString(), 0);
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);
267
		this->AddCockpit(cockpit.toString(), 0, -1);
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));
273
			this->AddCockpit(cockpit.toString(), 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);
285
		text->sName = rest.token(L"|", 2).toString();
286
		text->sName = text->sName.findReplace(L"<::PiPe::>", L"|");
287
		text->sDesc = rest.tokens(L"|", 3).toString();
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;
207 cycrow 293
		c->sData = rest.token(L"|", 1).toString();
294
		c->sData = c->sData.findReplace (L"<::PiPe::>", L"|");
295
		c->sSection = rest.token(L"|", 2).toString();
296
		c->sSection = c->sSection.findReplace (L"<::PiPe::>", L"|");
297
		c->sSection2 = rest.tokens(L"|", 3).toString();
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;
207 cycrow 303
		d->sData = rest.token(L"|", 1).toString();
304
		d->sData = d->sData.findReplace (L"<::PiPe::>", L"|");
305
		d->sSection = rest.tokens(L"|", 2).toString();
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
			{
203 cycrow 324
				name = text->sName.toWString();
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
 
170 cycrow 405
			C_File *newFile = this->addFile(m_sID + "_" + (long)(this->countFiles(FILETYPE_SCREEN) + 1) + "." + ext, "", 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
			{
178 cycrow 468
				if (newFile->checkFileExt("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") )
39 cycrow 630
			this->AddText(rest.token(":", 1), rest.token(":", 2), rest.tokens(":", 3));
1 cycrow 631
		else if ( first.Compare("Component") )
39 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;
39 cycrow 636
			d->sData = rest.tokens(";", 2);
637
			d->sSection = rest.token(";", 1);
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
 
39 cycrow 661
Utils::String GetShipyardName (int s)
1 cycrow 662
{
663
	switch (s)
664
	{
665
		case SHIPYARD_ARGON:
666
			return "Argon";
667
		case SHIPYARD_BORON:
668
			return "Boron";
669
		case SHIPYARD_PARANID:
670
			return "Paranid";
671
		case SHIPYARD_SPLIT:
672
			return "Split";
673
		case SHIPYARD_TELADI:
674
			return "Teladi";
675
		case SHIPYARD_PIRATES:
676
			return "Pirates";
677
		case SHIPYARD_FRIEND:
678
			return "Friendly";
679
		case SHIPYARD_XENON:
680
			return "Xenon";
681
		case SHIPYARD_TERRAN:
682
			return "Terran";
683
	}
684
 
685
	return "Unknown";
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) )
210 cycrow 798
				list->pushBack(L"Shipyard: " + GetShipyardName(i).toWString());
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()) {
210 cycrow 833
			list->pushBack(Utils::WString(L"ShipText: ") + (long)node->Data()->iId + L" " + node->Data()->sName.toWString() + L"|" + node->Data()->sDesc.toWString());
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
 
126 cycrow 854
		list->pushBack("");
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()) {
210 cycrow 860
			list->pushBack(Utils::WString(L"Component: ") + node->Data()->sSection.toWString() + L" " + node->Data()->sSection2.toWString() + L" " + node->Data()->sData.toWString());
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()) {
210 cycrow 868
			list->pushBack(L"Dummy: " + node->Data()->sSection.toWString() + L" " + node->Data()->sData.toWString());
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()) {
210 cycrow 876
			list->pushBack(L"Cockpit: " + node->Data()->sCockpit.toWString().token(L";", 19) + L" " + node->Data()->sCockpit.toWString());
108 cycrow 877
			for(SWeaponMask *mask = node->Data()->lWeaponMask.First(); mask; mask = node->Data()->lWeaponMask.Next()) {
210 cycrow 878
				list->pushBack(L"CockpitWeapon: " + node->Data()->sCockpit.toWString().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++)
210 cycrow 889
			list->pushBack(L"CutData: " + (*itr)->str.toWString());
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++)
210 cycrow 897
			list->pushBack(L"Bodies: " + (*itr)->str.toWString());
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++)
210 cycrow 905
			list->pushBack(L"Animation: " + (*itr)->str.toWString());	
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
 
113 cycrow 918
void CXspFile::_addSection(Utils::CList<STypesSection> &list, const Utils::String &section, const Utils::String &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
 
934
	currentSubSection->lEntries.pushBack(data, "");
935
}
936
 
165 cycrow 937
void CXspFile::_addDataSection(Utils::CStringList& list, Utils::CList<STypesSection>& sectionList, bool bUseFirst)
938
{
939
	for(auto itr = list.begin(); itr != list.end(); itr++)
940
	{
941
		if (bUseFirst) {
942
			Utils::String data = (*itr)->str;
943
			_addSection(sectionList, data.token(";", 1), data.tokens(";", 2));
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
{
995
	TCHAR buf[5000];
996
 
997
	CFileIO tmpFile(CPackages::tempDirectory() + "/temp.tmp");
998
 
999
	for(int i = 0; i < 5; i++) {
1000
		Utils::String type;
1001
		Utils::String data;
1002
		switch(i) {
1003
			case 0:
1004
				data = "50;1\r\n" + this->m_sData;
1005
				type = "TShips";
1006
				break;
1007
			case 1:
1008
				if ( !this->m_lCockpit.empty() ) {
1009
					data = Utils::String("51;") + (long)this->m_lCockpit.size() + ";\r\n";
1010
					for(CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next()) {
1011
						data += node->Data()->sCockpit + "\r\n";
1012
					}
1013
					type = "TCockpits";
1014
				}
1015
				break;
1016
			case 2:
1017
				if ( !this->m_lComponent.empty() ) {
1018
					type = "Components";
1019
					CLinkList<SComponentEntry> componentList;
1020
					this->addComponentsToList(componentList);
1021
					for(CListNode<SComponentEntry> *node = componentList.Front(); node; node = node->next()) {
1022
						data += node->Data()->sSection + "; " + (long)node->Data()->lEntries.size() + ";\r\n";
1023
						data += CXspFile::TypesListToString(node->Data()->lEntries, true);
1024
					}
1025
				}
1026
				break;
1027
			case 3:
1028
				GENERATESECTION("Dummies", SDummy, this->m_lDummy);
1029
				break;
1030
			case 4:
170 cycrow 1031
				GENERATESTRINGSECTION("Bodies", this->_lBodies, true);
109 cycrow 1032
				break;
1033
		}
1034
 
1035
		if ( type.empty() ) continue;
1036
 
1037
		Utils::String fname = "GENERATED/types/" + type + ".txt";
1038
 
1039
		Utils::String fileData = "// Exported " + type + " file, Generated by SPK Libraries V" + Utils::String::FromFloat(GetLibraryVersion(), 2) + "\r\n" + data;
1040
		if ( tmpFile.startWrite() ) {
1041
			tmpFile.write(fileData.c_str(), fileData.length());
1042
			tmpFile.close();
1043
		}
1044
 
1045
		// tships files
1046
		wsprintf(buf, L"%hs", fname.c_str());
1047
 
1048
		if ( tmpFile.startRead() ) {
1049
			size_t dataSize = 0;
1050
			unsigned char *data = tmpFile.readAll(&dataSize);
1051
			ZipAdd(hz, buf, data, dataSize);
1052
		}
1053
	}
1054
}
1055
 
197 cycrow 1056
bool CXspFile::loadPackageData(const Utils::WString &sFirst, const Utils::WString &sRest, const Utils::WString &sMainGame, Utils::WStringList &otherGames, Utils::WStringList &gameAddons, CProgressInfo *progress)
1 cycrow 1057
{
197 cycrow 1058
	if ( sFirst.Compare(L"Shipyard") )
1 cycrow 1059
	{
1060
		for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 )
1061
		{
39 cycrow 1062
			if ( sRest.Compare(GetShipyardName(i)) )
1 cycrow 1063
			{
1064
				this->AddShipyard(i);
1065
				break;
1066
			}
1067
		}
1068
	}
197 cycrow 1069
	else if ( sFirst.Compare(L"OriginalDescription") )
14 cycrow 1070
		m_iOrgDesc = sRest;
197 cycrow 1071
	else if ( sFirst.Compare(L"ShipData") )
1072
		m_sData = sRest.toString();
1073
	else if ( sFirst.Compare(L"ReadData") ) // read data from a tships file
1 cycrow 1074
	{
1075
		CPackages p;
197 cycrow 1076
		m_sData = p.readShipData(sRest.tokens(L" ", 2).toString(), sRest.token(L" ", 1).toString());
1 cycrow 1077
	}
197 cycrow 1078
	else if ( sFirst.Compare(L"ExistingShip") )
1 cycrow 1079
		m_bExistingShip = true;
197 cycrow 1080
	else if ( sFirst.Compare(L"ShipID") )
1081
		m_sID = sRest.toString();
1082
	else if ( sFirst.Compare(L"ShipText") )
1083
		this->AddText(sRest.token(L" ", 1).toLong(), sRest.tokens(L" ", 2).token(L"|", 1).toString(), sRest.tokens(L" ", 2).tokens(L"|", 2).toString());
1084
	else if ( sFirst.Compare(L"Component") )
1085
		this->AddComponent(sRest.token(L" ", 1).toString(), sRest.token(L" ", 2).toString(), sRest.tokens(L" ", 3).toString());
1086
	else if ( sFirst.Compare(L"Cockpit") )
1087
		this->AddCockpit(sRest.tokens(L" ", 2).replaceToken(L";", 19, sRest.token(L" ", 1)).toString(), 0);
1088
	else if ( sFirst.Compare(L"CockpitWeapon") )
1089
		this->AddCockpitWeapon(sRest.token(L" ", 1).toString(), sRest.token(L" ", 2), sRest.token(L" ", 3));
1090
	else if ( sFirst.Compare(L"WeaponMask") )
1091
		this->AddWeaponMask(sRest.token(L" ", 1), sRest.token(L" ", 2));
1092
	else if ( sFirst.Compare(L"MissileMask") )
1093
		this->AddMissileMask(sRest.token(L" ", 1), sRest.token(L" ", 2));
1094
	else if ( sFirst.Compare(L"Dummy") )
1095
		this->AddDummy(sRest.token(L" ", 1).toString(), sRest.token(L" ", 2).toString());
1096
	else if ( sFirst.Compare(L"CutData") )
1097
		this->addCutData(sRest.toString());
1098
	else if ( sFirst.Compare(L"Animation") )
1099
		this->addAnimation(sRest.toString());
1100
	else if ( sFirst.Compare(L"Bodies") )
1101
		this->addBodies(sRest.toString());
1102
	else if ( !CBaseFile::loadPackageData(sFirst, sRest, sMainGame, otherGames, gameAddons, progress) )
1 cycrow 1103
	{
1104
		return false;
1105
	}
1106
 
1107
	return true;
1108
}
1109
 
1110
 
39 cycrow 1111
Utils::String CXspFile::GetX3ShipData()
1 cycrow 1112
{
39 cycrow 1113
	Utils::String data = m_sData;
1 cycrow 1114
 
1115
	// change the ship subtype, Reunion uses number, TC uses a define
211 cycrow 1116
	Utils::WString sSubType = data.token(";", 6);
1117
	if ( !((long)sSubType) && sSubType != L"0" )
170 cycrow 1118
		data = data.replaceToken(";", 6, (long)CShipData::ConvertShipSubType(sSubType));
1 cycrow 1119
 
39 cycrow 1120
	Utils::String sClass = data.token(";", TSHIPPOS_CLASS);
1121
	if ( !((long)sClass) && sClass != "0" )
1 cycrow 1122
	{
1123
		int num = 0;
1124
		for ( int i = 0; i < OBJ_SHIP_MAX; i++ )
1125
		{
211 cycrow 1126
			if ( sClass.Compare(CShipData::ConvertShipClass(CShipData::GetShipClassFromNum(i)).toString()) )
1 cycrow 1127
			{
1128
				num = i;
1129
				break;
1130
			}
1131
		}
1132
 
39 cycrow 1133
		data = data.replaceToken(";", TSHIPPOS_CLASS, (long)num);
1 cycrow 1134
	}
1135
 
1136
	return data;
1137
}
1138
 
39 cycrow 1139
Utils::String CXspFile::GetTCShipData()
1 cycrow 1140
{
39 cycrow 1141
	Utils::String data = m_sData;
1 cycrow 1142
 
211 cycrow 1143
	Utils::WString sSubType = data.token(";", 6);
1144
	if ( ((long)sSubType) || sSubType == L"0" )
1145
		data = data.replaceToken(";", 6, CShipData::ConvertShipSubType((long)sSubType).toString());
1 cycrow 1146
 
39 cycrow 1147
	Utils::String sClass = data.token(";", TSHIPPOS_CLASS);
1148
	if ( ((long)sClass) || sClass == "0" )
211 cycrow 1149
		data = data.replaceToken(";", TSHIPPOS_CLASS, CShipData::ConvertShipClass((long)sClass).toString());
1 cycrow 1150
 
1151
	return data;
1152
}
1153
 
170 cycrow 1154
bool CXspFile::removeCockpit(const Utils::String &sCockpitId)
1 cycrow 1155
{
39 cycrow 1156
	Utils::String cockpitid = sCockpitId;
1 cycrow 1157
	// if its a whole line, just get the end
39 cycrow 1158
	if ( cockpitid.isin(";") )
1 cycrow 1159
	{
39 cycrow 1160
		cockpitid = cockpitid.tokens(";", -2);
1161
		while ( cockpitid.right(1) == ";" )
1162
			cockpitid.truncate(-1);
1 cycrow 1163
	}
1164
 
1165
	bool ret = false;
1166
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1167
	{
39 cycrow 1168
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 1169
		if ( id.Compare(cockpitid) )
1170
		{
1171
			node->DeleteData();
1172
			ret = true;
1173
			break;
1174
		}
1175
	}
1176
 
1177
	m_lCockpit.RemoveEmpty();
1178
 
1179
	return ret;
1180
}
1181
 
170 cycrow 1182
bool CXspFile::removeComponent(const Utils::String &section1, const Utils::String &section2, const Utils::String &data)
1 cycrow 1183
{
1184
	bool ret = false;
1185
	for ( CListNode<SComponent> *node = m_lComponent.Front(); node; node = node->next() )
1186
	{
1187
		if ( node->Data()->sSection.Compare(section1) && node->Data()->sSection2.Compare(section2) && node->Data()->sData.Compare(data) )
1188
		{
1189
			ret = true;
1190
			node->DeleteData();
1191
			break;
1192
		}
1193
	}
1194
	m_lComponent.RemoveEmpty();
1195
	return ret;
1196
}
1197
 
170 cycrow 1198
bool CXspFile::removeDummy(const Utils::String &section, const Utils::String &data)
1 cycrow 1199
{
1200
	bool ret = false;
1201
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
1202
	{
1203
		if ( node->Data()->sSection.Compare(section) && node->Data()->sData.Compare(data) )
1204
		{
1205
			ret = true;
1206
			node->DeleteData();
1207
			break;
1208
		}
1209
	}
1210
	m_lDummy.RemoveEmpty();
1211
 
1212
	return ret;
1213
}
1214
 
39 cycrow 1215
Utils::String CXspFile::GetCockpitData(const Utils::String &cid)
1 cycrow 1216
{
1217
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1218
	{
39 cycrow 1219
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 1220
		if ( id.Compare(cid) )
1221
			return node->Data()->sCockpit;
1222
	}
1223
 
39 cycrow 1224
	return "";
1 cycrow 1225
}
1226
 
39 cycrow 1227
SCockpit *CXspFile::FindCockpit(const Utils::String &cid)
1 cycrow 1228
{
1229
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1230
	{
39 cycrow 1231
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 1232
		if ( id.Compare(cid) )
1233
			return node->Data();
1234
	}
1235
 
1236
	return NULL;
1237
}
1238
 
39 cycrow 1239
void CXspFile::EditCockpit(const Utils::String &cid, const Utils::String &cockpit)
1 cycrow 1240
{
1241
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1242
	{
39 cycrow 1243
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 1244
		if ( id.Compare(cid) )
1245
		{
1246
			node->Data()->sCockpit = cockpit;
1247
			break;
1248
		}
1249
	}
1250
}
1251
 
39 cycrow 1252
void CXspFile::EditCockpit(const Utils::String &cid, const Utils::String &scene, int mask)
1 cycrow 1253
{
1254
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
1255
	{
39 cycrow 1256
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1 cycrow 1257
		if ( id.Compare(cid) )
1258
		{
39 cycrow 1259
			Utils::String cockpit = node->Data()->sCockpit;
1260
			cockpit = cockpit.replaceToken(";", 8, scene);
1261
			cockpit = cockpit.replaceToken(";", 9, (long)mask);
1 cycrow 1262
			node->Data()->sCockpit = cockpit;
1263
			break;
1264
		}
1265
	}
1266
}
39 cycrow 1267
void CXspFile::NewCockpit(const Utils::String &id, const Utils::String &scene, int mask)
1 cycrow 1268
{
39 cycrow 1269
	Utils::String cockpit = "0;0;0;0;0;0;0;";
1 cycrow 1270
	cockpit += scene + ";";
39 cycrow 1271
	cockpit += (long)mask;
1 cycrow 1272
	cockpit += ";0;0;0;0;0;0;-100000;0;0;";
1273
	cockpit += id + ";";
1274
	this->AddCockpit(cockpit, -1);
1275
}
1276
 
165 cycrow 1277
bool CXspFile::removeCutData(const Utils::String &cut)
1 cycrow 1278
{
1279
	bool ret = false;
165 cycrow 1280
	for(size_t i = 0; i < _lCutData.size(); i++)
1 cycrow 1281
	{
165 cycrow 1282
		Utils::String str = _lCutData[i]->str;
1283
		if (str.token(";", 1).Compare(cut.token(";", 1)))
1 cycrow 1284
		{
1285
			ret = true;
165 cycrow 1286
			_lCutData.remove(str);
1 cycrow 1287
			break;
1288
		}
1289
	}
1290
 
1291
	return ret;
1292
}
1293
 
170 cycrow 1294
bool CXspFile::removeBodies(const Utils::String &cut)
1 cycrow 1295
{
1296
	bool ret = false;
170 cycrow 1297
	for (auto itr = _lBodies.begin(); itr != _lBodies.end(); itr++)
1 cycrow 1298
	{
170 cycrow 1299
		if ((*itr)->str.remove(' ').Compare(cut.remove(' ')))
1 cycrow 1300
		{
170 cycrow 1301
			_lBodies.remove(itr);
1302
			return true;
1 cycrow 1303
		}
1304
	}
1305
 
170 cycrow 1306
	return false;
1 cycrow 1307
}
1308
 
170 cycrow 1309
bool CXspFile::removeAnimation(const Utils::String &cut)
1 cycrow 1310
{
170 cycrow 1311
	for(auto itr = _lAnimations.begin(); itr != _lAnimations.end(); itr++)
1 cycrow 1312
	{
170 cycrow 1313
		if ((*itr)->str.remove(' ').remove('\n').Compare(cut.remove(' ').remove('\n')))
1 cycrow 1314
		{
170 cycrow 1315
			_lAnimations.remove(itr);
1316
			return true;
1 cycrow 1317
		}
1318
	}
1319
 
170 cycrow 1320
	return false;
1 cycrow 1321
}
1322
 
108 cycrow 1323
SCockpit *CXspFile::_findCockpit(const Utils::String &sID)
1 cycrow 1324
{
108 cycrow 1325
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() ) {
1326
		Utils::String id = node->Data()->sCockpit.token(";", 19);
1327
		if ( id.Compare(sID) )
1328
			return node->Data();
1329
	}
1 cycrow 1330
 
108 cycrow 1331
	return NULL;
1332
}
1333
 
1334
void CXspFile::AddCockpitWeapon(const Utils::String &cockpit, int game, int mask)
1335
{
1336
	SCockpit *pCockpit = _findCockpit(cockpit);
1337
 
1338
	// search if the game mask already exists
1339
	SWeaponMask *wm = NULL;
1340
	for ( CListNode<SWeaponMask> *node = pCockpit->lWeaponMask.Front(); node; node = node->next() )
1 cycrow 1341
	{
108 cycrow 1342
		if ( node->Data()->iGame == game )
1 cycrow 1343
		{
108 cycrow 1344
			wm = node->Data();
1 cycrow 1345
			break;
1346
		}
1347
	}
1348
 
108 cycrow 1349
	if ( !wm )
1350
	{
1351
		wm = new SWeaponMask;
1352
		pCockpit->lWeaponMask.push_back(wm);
1353
	}
1354
 
1355
	wm->iGame = game;
1356
	if ( mask == -1 )
1357
		wm->iMask = pCockpit->sCockpit.token(";", 9);
1358
	else
1359
		wm->iMask = mask;
1360
	_changed();
1361
}
1362
 
1363
void CXspFile::AddCockpit(const Utils::String &cockpit, int game, int mask, int index)
1364
{
1365
	Utils::String cid = cockpit.token(";", 19);
1366
	SCockpit *pCockpit = _findCockpit(cid);
1367
 
1 cycrow 1368
	if ( !pCockpit )
1369
	{
1370
		pCockpit = new SCockpit;
1371
		pCockpit->sCockpit = cockpit;
1372
		pCockpit->iIndex = index;
1373
		m_lCockpit.push_back(pCockpit);
1374
	}
1375
	if ( index != -1 )
1376
		pCockpit->iIndex = index;
1377
 
1378
	// now add the game mask
1379
	if ( game > 0 )
108 cycrow 1380
		AddCockpitWeapon(cid, game, mask);
50 cycrow 1381
	_changed();
1 cycrow 1382
}
1383
 
170 cycrow 1384
void CXspFile::addBody(const Utils::String &section, const Utils::String &data)
1 cycrow 1385
{
170 cycrow 1386
	this->addBodies(section + ";" + data);
50 cycrow 1387
	_changed();
1 cycrow 1388
}
170 cycrow 1389
void CXspFile::addBodies(const Utils::String &sData)
1 cycrow 1390
{
39 cycrow 1391
	Utils::String data = sData;
1392
	if ( !data.isNumber() )
1 cycrow 1393
	{
39 cycrow 1394
		if ( data[(int)(data.length() - 5)] == '.' )
1395
			data = data.left(-5);
1396
		else if ( data[(int)(data.length() - 4)] == '.' )
1397
			data = data.left(-4);
1398
		if ( data.right(1) != ";" )
1 cycrow 1399
			data += ";";
1400
	}
170 cycrow 1401
	if(!_lBodies.contains(data))
1402
		_lBodies.pushBack(data);
50 cycrow 1403
	_changed();
1 cycrow 1404
}
1405
 
165 cycrow 1406
void CXspFile::addCutData(const Utils::String& data)
1407
{ 
1408
	if (!_lCutData.contains(data))
1409
	{
1410
		_lCutData.pushBack(data);
1411
		_changed();
1412
	}
1413
}
1414
 
1415
 
39 cycrow 1416
int CXspFile::GetAnimationType(const Utils::String &type)
1 cycrow 1417
{
1418
	if ( type.Compare("TAT_TAGSINGLESTEP") )
1419
		return TAT_SINGLE;
1420
	else if ( type.Compare("TAT_TAGONESHOT") 
1421
				|| type.Compare("TAT_TAGONESHOT_REINIT") 
1422
				|| type.Compare("TAT_PINGPONG")
1423
				|| type.Compare("TAT_TAGLOOP") )
1424
		return TAT_3;
1425
 
1426
	return TAT_NONE;
1427
}
1428
 
113 cycrow 1429
Utils::String CXspFile::TypesListToString(Utils::CList<STypesSection> &list, bool deleteAfter)
109 cycrow 1430
{
1431
	Utils::String data;
1432
 
113 cycrow 1433
	for(Utils::CList<STypesSection>::iterator itr = list.begin(); itr != list.end(); itr++) {
109 cycrow 1434
		data += (*itr)->sSection + "; " + (long)(*itr)->lEntries.size() + ";\r\n";
112 cycrow 1435
		for(Utils::SStringList *str = (*itr)->lEntries.first(); str; str = (*itr)->lEntries.next()) {
109 cycrow 1436
			data += str->str + "\r\n";
1437
		}
1438
 
1439
		if ( deleteAfter ) {
112 cycrow 1440
			(*itr)->lEntries.clear();
109 cycrow 1441
		}
1442
	}
1443
 
1444
	return data;
1445
}
1446
 
212 cycrow 1447
bool CXspFile::ReadAnimations(const Utils::WStringList& lIn, Utils::WStringList& lOut, int startRecord)
1448
{
1449
	Utils::WString lastComment;
1450
	Utils::WString addEntry;
1451
	int remaining = 0;
1452
	Utils::WString lastType;
1453
	int newEntries = 0;
1454
	int entries = -1;
1455
	for (auto itr = lIn.begin(); itr != lIn.end(); itr++)
1456
	{
1457
		Utils::WString line = (*itr)->str;
1458
		line.removeChar('\r');
1459
		line.removeChar(9);
1460
		if (line.empty() || line[0] == '/')
1461
			continue;
1462
		if (entries == -1)
1463
		{
1464
			entries = line.token(L";", 1);
1465
			newEntries = entries - startRecord;
1466
		}
1467
		else
1468
		{
1469
			// remove comments, endspaces and last ;
1470
			Utils::WString sStriped = line;
1471
			if (sStriped.isin("//"))
1472
			{
1473
				if (entries <= newEntries)
1474
					lastComment = L"//" + sStriped.tokens(L"//", 2);
1475
				sStriped = sStriped.token(L"//", 1);
1476
			}
1477
			sStriped.removeEndSpace();
1478
			if (sStriped.right(1) == L";")
1479
				sStriped.truncate(-1);
1480
 
1481
			Utils::WString sRemainingLeft;
1482
			if (remaining > 0)
1483
				sRemainingLeft = sStriped;
1484
			else
1485
			{
1486
				// each line should be a new entry, with some exceptions
1487
				// potection for new lines
1488
				lastType = sStriped.token(L";", 1);
1489
 
1490
				switch (CXspFile::GetAnimationType(lastType.toString()))
1491
				{
1492
				case TAT_SINGLE:
1493
					remaining = (long)sStriped.token(L";", 5) + 1;
1494
					sRemainingLeft = sStriped.tokens(L";", 6);
1495
					if (entries <= newEntries)
1496
						addEntry = sStriped.tokens(L";", 1, 5) + L";";
1497
					break;
1498
				case TAT_3:
1499
					remaining = (long)sStriped.token(L";", 5) + 1;
1500
					sRemainingLeft = sStriped.tokens(L";", 6);
1501
					if (entries <= newEntries)
1502
						addEntry = sStriped.tokens(L";", 1, 5) + L";";
1503
					break;
1504
 
1505
				default:
1506
					remaining = 0;
1507
					if (entries <= newEntries)
1508
						addEntry = sStriped;
1509
 
1510
				}
1511
			}
1512
 
1513
			if (!sRemainingLeft.empty())
1514
			{
1515
				int tatType = CXspFile::GetAnimationType(lastType.toString());
1516
				if (tatType == TAT_SINGLE)
1517
				{
1518
					if (sRemainingLeft.contains(L";"))
1519
						remaining -= sRemainingLeft.countToken(L";");
1520
					else if (!sRemainingLeft.empty())
1521
						--remaining;
1522
 
1523
					if (entries <= newEntries)
1524
						addEntry += sRemainingLeft + L";";
1525
				}
1526
				else if (tatType == TAT_3)
1527
				{
1528
					// last entry
1529
					if (remaining == 1)
1530
						--remaining;
1531
					else if (sRemainingLeft.contains(L";"))
1532
					{
1533
						if (!sRemainingLeft.contains(L"TATF_COORDS"))
1534
						{
1535
							int amt = sRemainingLeft.countToken(L";") / 3;
1536
							remaining -= amt;
1537
							if (remaining == 1 && (sRemainingLeft.countToken(L";") - (amt * 3)) == 1)
1538
								--remaining;
1539
						}
1540
						else
1541
						{
1542
							int iRem = sRemainingLeft.countToken(L";");
1543
							int iPos = 1;
1544
							while (iPos < iRem)
1545
							{
1546
								Utils::WString first = sRemainingLeft.token(L";", iPos);
1547
								if (first.contains(L"TATF_COORDS"))
1548
									iPos += 5;
1549
								else
1550
									iPos += 3;
1551
								--remaining;
1552
							}
1553
 
1554
							if (remaining == 1 && iPos == iRem)
1555
								--remaining;
1556
						}
1557
					}
1558
 
1559
					if (entries <= newEntries)
1560
						addEntry += sRemainingLeft + L";";
1561
				}
1562
			}
1563
 
1564
			if (remaining <= 0)
1565
			{
1566
				if (entries <= newEntries && !addEntry.empty())
1567
				{
1568
					if (addEntry[(int)addEntry.length() - 1] != ';')
1569
						addEntry += L";";
1570
					lOut.pushBack(addEntry + lastComment);
1571
				}
1572
				--entries;
1573
			}
1574
		}
1575
	}
1576
 
1577
	return !lOut.empty();
1578
}
1579
 
1580
 
170 cycrow 1581
bool CXspFile::ReadAnimations(const Utils::CStringList &lIn, Utils::CStringList &lOut, int startRecord)
1 cycrow 1582
{
39 cycrow 1583
	Utils::String lastComment;
1584
	Utils::String addEntry;
1 cycrow 1585
	int remaining = 0;
39 cycrow 1586
	Utils::String lastType;
1 cycrow 1587
	int newEntries = 0;
1588
	int entries = -1;
170 cycrow 1589
	for(auto itr = lIn.begin(); itr != lIn.end(); itr++)
1 cycrow 1590
	{
170 cycrow 1591
		Utils::String line = (*itr)->str;
39 cycrow 1592
		line.removeChar('\r');
1593
		line.removeChar(9);
1594
		if ( line.empty() || line[0] == '/' )
1 cycrow 1595
			continue;
1596
		if ( entries == -1)
1597
		{
39 cycrow 1598
			entries	= line.token(";", 1);
1 cycrow 1599
			newEntries = entries - startRecord;
1600
		}
1601
		else
1602
		{
1603
			// remove comments, endspaces and last ;
39 cycrow 1604
			Utils::String sStriped = line;
1605
			if ( sStriped.isin("//") )
1 cycrow 1606
			{
1607
				if ( entries <= newEntries )
39 cycrow 1608
					lastComment = "//" + sStriped.tokens("//", 2);
1609
				sStriped = sStriped.token("//", 1);
1 cycrow 1610
			}
39 cycrow 1611
			sStriped.removeEndSpace();
1612
			if ( sStriped.right(1) == ";" )
1613
				sStriped.truncate(-1);
1 cycrow 1614
 
39 cycrow 1615
			Utils::String sRemainingLeft;
1 cycrow 1616
			if ( remaining > 0 )
1617
				sRemainingLeft = sStriped;
1618
			else
1619
			{
1620
				// each line should be a new entry, with some exceptions
1621
				// potection for new lines
39 cycrow 1622
				lastType = sStriped.token(";", 1);
1 cycrow 1623
 
1624
				switch (CXspFile::GetAnimationType(lastType))
1625
				{
1626
					case TAT_SINGLE:
39 cycrow 1627
						remaining = (long)sStriped.token(";", 5) + 1;
1628
						sRemainingLeft = sStriped.tokens(";", 6);
1 cycrow 1629
						if ( entries <= newEntries )
39 cycrow 1630
							addEntry = sStriped.tokens(";", 1, 5) + ";";
1 cycrow 1631
						break;
1632
					case TAT_3:
39 cycrow 1633
						remaining = (long)sStriped.token(";", 5) + 1;
1634
						sRemainingLeft = sStriped.tokens(";", 6);
1 cycrow 1635
						if ( entries <= newEntries )
39 cycrow 1636
							addEntry = sStriped.tokens(";", 1, 5) + ";";
1 cycrow 1637
						break;
1638
 
1639
					default:
1640
						remaining = 0;
1641
						if ( entries <= newEntries )
1642
							addEntry = sStriped;
1643
 
1644
				}
1645
			}
1646
 
39 cycrow 1647
			if ( !sRemainingLeft.empty() )
1 cycrow 1648
			{
1649
				int tatType = CXspFile::GetAnimationType(lastType);
1650
				if ( tatType == TAT_SINGLE )
1651
				{
39 cycrow 1652
					if ( sRemainingLeft.isin(";") )
1653
						remaining -= sRemainingLeft.countToken(";");
1654
					else if ( !sRemainingLeft.empty() )
1 cycrow 1655
						--remaining;
1656
 
1657
					if ( entries <= newEntries )
1658
						addEntry += sRemainingLeft + ";";
1659
				}
1660
				else if ( tatType == TAT_3 )
1661
				{
1662
					// last entry
1663
					if ( remaining == 1 )
1664
						--remaining;
39 cycrow 1665
					else if ( sRemainingLeft.isin(";") )
1 cycrow 1666
					{
39 cycrow 1667
						if ( !sRemainingLeft.isin("TATF_COORDS") )
1 cycrow 1668
						{
39 cycrow 1669
							int amt = sRemainingLeft.countToken(";") / 3;
1 cycrow 1670
							remaining -= amt;
39 cycrow 1671
							if ( remaining == 1 && (sRemainingLeft.countToken(";") - (amt * 3)) == 1 )
1 cycrow 1672
								--remaining;
1673
						}
1674
						else
1675
						{
39 cycrow 1676
							int iRem = sRemainingLeft.countToken(";");
1 cycrow 1677
							int iPos = 1;
1678
							while ( iPos < iRem )
1679
							{
39 cycrow 1680
								Utils::String first = sRemainingLeft.token(";", iPos);
1681
								if ( first.isin("TATF_COORDS") )
1 cycrow 1682
									iPos += 5;
1683
								else
1684
									iPos += 3;
1685
								--remaining;
1686
							}
1687
 
1688
							if ( remaining == 1 && iPos == iRem )
1689
								--remaining;
1690
						}
1691
					}
1692
 
1693
					if ( entries <= newEntries )
1694
						addEntry += sRemainingLeft + ";";
1695
				}
1696
			}
1697
 
1698
			if ( remaining <= 0 )
1699
			{
39 cycrow 1700
				if ( entries <= newEntries && !addEntry.empty())
1 cycrow 1701
				{
39 cycrow 1702
					if ( addEntry[(int)addEntry.length() - 1] != ';' )
1 cycrow 1703
						addEntry += ";";
170 cycrow 1704
					lOut.pushBack(addEntry + lastComment);
1 cycrow 1705
				}
1706
				--entries;
1707
			}
1708
		}
1709
	}
1710
 
170 cycrow 1711
	return !lOut.empty();
1 cycrow 1712
}
1713
 
170 cycrow 1714
void CXspFile::addAnimation(const Utils::CStringList &list)
1 cycrow 1715
{
170 cycrow 1716
	for(auto itr = list.begin(); itr != list.end(); itr++)
1717
		this->addAnimation((*itr)->str);
50 cycrow 1718
	_changed();
1 cycrow 1719
}
1720
 
170 cycrow 1721
void CXspFile::addAnimation(const Utils::String& data) 
1722
{ 
1723
	if (!_lAnimations.contains(data))
1724
	{
1725
		_lAnimations.pushBack(data);
1726
		_changed();
1727
	}
1728
}
1729
 
1 cycrow 1730
SText *CXspFile::FindShipText(int lang)
1731
{
1732
	if ( m_lText.empty() )
1733
		return NULL;
1734
 
1735
	SText *english = NULL;
1736
	SText *german = NULL;
1737
	SText *found = NULL;
1738
	for ( CListNode<SText> *node = m_lText.Front(); node; node = node->next() )
1739
	{
1740
		SText *text = node->Data();
1741
		// matched language
1742
		if ( text->iId == lang )
1743
			return text;
1744
		else if ( text->iId == 44 )
1745
			english = text;
1746
		else if ( text->iId == 49 )
1747
			german = text;
1748
		else if ( !found )
1749
			found = text;
1750
	}
1751
 
1752
	// if we've found an english version, use that
1753
	if ( english )
1754
		return english;
1755
	// otherwise try a german
1756
	if ( german )
1757
		return german;
1758
	// otherwise use any we've found (usually first one)
1759
	return found;
1760
}
1761
 
206 cycrow 1762
Utils::WString CXspFile::textName(int lang)
1 cycrow 1763
{
1764
	SText *t = FindShipText(lang);
1765
	if ( t )
1766
	{
1767
		// return the correct language text
39 cycrow 1768
		if ( !t->sName.empty() )
1 cycrow 1769
			return t->sName;
1770
		// we have found a text, but there is no ship name ??
1771
		else if ( lang != 44 )
1772
		{
1773
			// reget the english one
1774
			t = FindShipText(44);
39 cycrow 1775
			if ( t && !t->sName.empty() )
1 cycrow 1776
				return t->sName;
1777
		}
1778
	}
1779
 
1780
	// still not found one, return the ships name
203 cycrow 1781
	return this->shipName(lang);
1 cycrow 1782
}
1783
 
206 cycrow 1784
Utils::WString CXspFile::textDescription(int lang)
1 cycrow 1785
{
1786
	SText *t = FindShipText(lang);
1787
	if ( t )
1788
	{
1789
		// return the correct language text
39 cycrow 1790
		if ( !t->sDesc.empty() )
1 cycrow 1791
			return t->sDesc;
1792
		// we have found a text, but there is no ship name ??
1793
		else if ( lang != 44 )
1794
		{
1795
			// reget the english one
1796
			t = FindShipText(44);
39 cycrow 1797
			if ( t && !t->sDesc.empty() )
1 cycrow 1798
				return t->sDesc;
1799
		}
1800
	}
1801
 
1802
	// still not found one, return the ships name
48 cycrow 1803
	if ( !this->description().empty() ) return this->description();
206 cycrow 1804
	return this->shipName(lang);
1 cycrow 1805
}
1806
 
35 cycrow 1807
bool CXspFile::startExtractShip(CVirtualFileSystem *pVfs, const Utils::String &sId, CProgressInfo *pProgress)
1 cycrow 1808
{
39 cycrow 1809
	m_sID = sId.remove('\r');
35 cycrow 1810
	while ( m_sID.right(1) == ";" )
1811
		m_sID.truncate(-1);
1 cycrow 1812
 
197 cycrow 1813
	m_sData = pVfs->getTShipsEntry(m_sID).toString();
35 cycrow 1814
 
1 cycrow 1815
	// get scene files
35 cycrow 1816
	if ( pProgress ) pProgress->UpdateStatus(IMPORTSHIP_SCENE);
1817
	if ( !this->extractSceneFiles(pVfs) )
1 cycrow 1818
		return false;
1819
 
1820
	return true;
1821
}
1822
 
35 cycrow 1823
bool CXspFile::extractShip(CVirtualFileSystem *pVfs, const Utils::String &sId, CProgressInfo *progress)
1 cycrow 1824
{
35 cycrow 1825
	if ( !this->startExtractShip(pVfs, sId, progress) )
1 cycrow 1826
		return false;
1827
 
1828
	// read the scene file and get the files list
35 cycrow 1829
	if ( !this->processSceneFiles(pVfs, progress) )
1 cycrow 1830
		return false;
1831
 
1832
	// pack all the ship files
1833
	this->PackAllFiles();
1834
 
1835
	return true;
1836
}
1837
 
35 cycrow 1838
bool CXspFile::extractSceneFiles(CVirtualFileSystem *pVfs)
1 cycrow 1839
{
35 cycrow 1840
	m_pSceneFile = pVfs->extractGameFileToPackage(this, "objects\\" + m_sData.token(";", 17) + ".pbd", FILETYPE_SHIPSCENE, "objects\\" + m_sData.token(";", 17) + ".bod");
1841
	if ( !m_pSceneFile ) return false;
1842
	m_pCockpitFile = pVfs->extractGameFileToPackage(this, "objects\\" + m_sData.token(";", 18) + ".pbd", FILETYPE_COCKPITSCENE, "objects\\" + m_sData.token(";", 18) + ".bod");
1 cycrow 1843
 
1844
	return true;
1845
}
1846
 
170 cycrow 1847
bool CXspFile::readSceneModels(Utils::CStringList& out)
1 cycrow 1848
{
1849
	// read the scene file
170 cycrow 1850
	if (!m_pSceneFile)
1 cycrow 1851
		m_pSceneFile = this->GetFirstFile(FILETYPE_SHIPSCENE);
1852
 
170 cycrow 1853
	if (!m_pSceneFile)
1854
		return false;
1 cycrow 1855
 
1856
	// check if its packed
1857
	size_t datasize;
170 cycrow 1858
	unsigned char* data = m_pSceneFile->UncompressData((long*)&datasize, 0);
1859
 
1 cycrow 1860
	// if data wasn't compressed, then copy it itself as we are editing it
1861
	bool deleteData = false;
170 cycrow 1862
	if (data == m_pSceneFile->GetData())
1 cycrow 1863
	{
1864
		data = new unsigned char[m_pSceneFile->GetDataSize()];
1865
		memcpy(data, m_pSceneFile->GetData(), m_pSceneFile->GetDataSize());
1866
		deleteData = true;
1867
	}
1868
 
170 cycrow 1869
	if (data && datasize)
1 cycrow 1870
	{
170 cycrow 1871
		if (m_pSceneFile->CheckPackedExtension())
1 cycrow 1872
			data = UnPCKData(data, datasize, &datasize);
1873
	}
1874
 
170 cycrow 1875
	if (!data || !datasize)
1876
		return false;
1 cycrow 1877
 
1878
	size_t pos = 0;
1879
	bool newline = true;
1880
	bool online = false;
170 cycrow 1881
	while (pos < datasize)
1 cycrow 1882
	{
1883
		char c = data[pos];
1884
		++pos;
1885
 
1886
		// skip until next line
170 cycrow 1887
		if (!newline && !online)
1 cycrow 1888
		{
170 cycrow 1889
			if (c == '\n')
1 cycrow 1890
				newline = true;
1891
			continue;
1892
		}
1893
 
170 cycrow 1894
		if (newline)
1 cycrow 1895
		{
170 cycrow 1896
			if (c == ' ' || c == 9 || c == '\n' || c == '\r')
1 cycrow 1897
				continue;
1898
 
1899
			newline = false;
1900
 
170 cycrow 1901
			if (c == 'P' || c == 'p')
1 cycrow 1902
			{
170 cycrow 1903
				while (data[pos] == ' ') pos++;
1904
				unsigned char* line = (data + pos);
1905
				while (data[pos] != ' ' && data[pos] != ';') pos++;
1 cycrow 1906
				data[pos] = '\0';
170 cycrow 1907
				if (atoi((const char*)line) == out.size())
1 cycrow 1908
					online = true;
1909
			}
1910
		}
1911
		// this line is out model
170 cycrow 1912
		else if (online)
1 cycrow 1913
		{
170 cycrow 1914
			if (c == 'B' || c == 'b')
1 cycrow 1915
			{
170 cycrow 1916
				while (data[pos] == ' ') pos++;
1917
				unsigned char* line = (data + pos);
1918
				while (data[pos] != ';') pos++;
1 cycrow 1919
				data[pos] = '\0';
1920
 
170 cycrow 1921
				out.pushBack((char*)line);
1 cycrow 1922
				online = false;
1923
			}
1924
		}
1925
	}
1926
 
170 cycrow 1927
	if (deleteData)
1 cycrow 1928
		delete data;
1929
 
170 cycrow 1930
	return true;
1 cycrow 1931
}
1932
 
170 cycrow 1933
void CXspFile::extractCutData(CVirtualFileSystem *pVfs, Utils::CStringList &sceneModels, bool add)
42 cycrow 1934
{
1935
	std::vector<int> cuts;
170 cycrow 1936
	for ( CListNode<SDummy> *node = m_lDummy.Front(); node; node = node->next() )
1937
	{
42 cycrow 1938
		Utils::String data = node->Data()->sData;
1939
		int states = data.token(";", 3);
1940
		for ( int i = 0; i < states; i++ ) {
1941
			int cutid = data.token(";", (i * 2) + 5);
1942
			if ( !cutid ) continue;
1943
			cuts.push_back(cutid);
1944
		}
1945
	}
1946
 
1947
	if ( cuts.empty() ) return;
1948
 
197 cycrow 1949
	if ( pVfs->extractGameFile(L"types/CutData.pck", CPackages::tempDirectory() + L"tmp.dat").empty()) return;
42 cycrow 1950
 
197 cycrow 1951
	CFileIO File(CPackages::tempDirectory() + L"tmp.dat");
52 cycrow 1952
	if ( !File.exists() ) return;
42 cycrow 1953
 
170 cycrow 1954
	std::vector<Utils::String> lines;
1955
	File.readLines(lines);
42 cycrow 1956
	int count = -1;
170 cycrow 1957
	for (auto itr = lines.begin(); itr != lines.end(); itr++) {
1958
		Utils::String line = *itr;
42 cycrow 1959
		line.removeChar('\r');
1960
		line.removeChar(' ');
1961
		line.removeFirstSpace();
1962
		if ( line[0] == '/' ) continue;
1963
		if ( count == -1 ) count = line.token(";", 1);
1964
		else {
1965
			int max;
1966
			Utils::String *words = line.tokenise(";", &max);
1967
			if ( words && max ) {
1968
				for ( int i = 0; i < max; i += 2 ) {
1969
					int cutid = words[i];
1970
					if ( !cutid ) continue;
1971
					for ( std::vector<int>::iterator itr = cuts.begin(); itr != cuts.end(); itr++ ) {
1972
						if ( (*itr) == cutid ) {
165 cycrow 1973
							this->addCutData(words[i] + ";" + words[i + 1] + ";");
42 cycrow 1974
							if ( add ) {
170 cycrow 1975
								sceneModels.pushBack(words[i + 1]);
42 cycrow 1976
							}
1977
							break;
1978
						}
1979
					}
1980
				}
1981
				CLEANSPLIT(words, max);
1982
			}
1983
		}
1984
	}
1985
}
1986
 
170 cycrow 1987
void CXspFile::extractDummies(CVirtualFileSystem *pVfs, Utils::CStringList& sceneModels, bool add)
1 cycrow 1988
{
170 cycrow 1989
	if (sceneModels.empty()) return;
31 cycrow 1990
 
1991
	bool extracted = false;
197 cycrow 1992
	if ( !pVfs->extractGameFile(L"types/dummies.pck", CPackages::tempDirectory() + L"tmp.dat").empty()) {
1993
		CFileIO File(CPackages::tempDirectory() + L"tmp.dat");
52 cycrow 1994
		if ( File.exists() )
1 cycrow 1995
		{
39 cycrow 1996
			Utils::String section;
1 cycrow 1997
			int secCount = 0;
170 cycrow 1998
			std::vector<Utils::String> lines;
1999
			if (File.readLines(lines))
1 cycrow 2000
			{
170 cycrow 2001
				for(auto itr = lines.begin(); itr != lines.end(); itr++)
2002
				{
2003
					Utils::String str = itr->remove(9).remove('\r');
2004
					str.removeFirstSpace();
2005
					if (str.empty())
2006
						continue;
2007
					if (str[0] == '/')
2008
						continue;
1 cycrow 2009
 
170 cycrow 2010
					// not in a section yet
2011
					if (secCount <= 0)
1 cycrow 2012
					{
170 cycrow 2013
						section = str.token(";", 1);
2014
						secCount = str.token(";", 2).toInt();
2015
					}
2016
					else
2017
					{
2018
						Utils::String first = str.token(";", 1);
2019
						if (sceneModels.contains(first))
2020
						{
2021
							this->AddDummy(section, str);
1 cycrow 2022
 
170 cycrow 2023
							if (add)
1 cycrow 2024
							{
170 cycrow 2025
								int pos = 4;
2026
								int scene = str.token(";", 3).toInt();
2027
								for (int i = 0; i < scene; i++)
2028
								{
2029
									sceneModels.pushBack(str.token(";", 5 + (i * 2)));
2030
									pos += 2;
2031
								}
2032
 
2033
								int model = str.token(";", pos).toInt();
2034
								for (int i = 0; i < model; i++)
2035
									sceneModels.pushBack(str.token(";", pos + (i * 2) + 1));
1 cycrow 2036
							}
170 cycrow 2037
						}
2038
						--secCount;
1 cycrow 2039
 
2040
					}
2041
				}
2042
			}
2043
 
52 cycrow 2044
			File.remove();
1 cycrow 2045
		}
2046
	}
2047
}
2048
 
170 cycrow 2049
void CXspFile::extractComponants(CVirtualFileSystem *pVfs, const Utils::CStringList& sceneModels)
1 cycrow 2050
{
170 cycrow 2051
	if (sceneModels.empty()) return;
197 cycrow 2052
	if ( !pVfs->extractGameFile(L"types/components.pck", CPackages::tempDirectory() + L"tmp.dat").empty())
1 cycrow 2053
	{
197 cycrow 2054
		CFileIO File(CPackages::tempDirectory() + L"tmp.dat");
52 cycrow 2055
		if ( File.exists() )
1 cycrow 2056
		{
39 cycrow 2057
			Utils::String file;
2058
			Utils::String section;
1 cycrow 2059
			int secCount = 0;
2060
			int secCount2 = 0;
170 cycrow 2061
			std::vector<Utils::String> lines;
2062
			if (File.readLines(lines))
1 cycrow 2063
			{
170 cycrow 2064
				for(auto itr = lines.begin(); itr != lines.end(); itr++)
2065
				{
2066
					Utils::String str = itr->remove(9).remove('\r');
2067
					str.removeFirstSpace();
2068
					if (str.empty())
2069
						continue;
2070
					if (str[0] == '/')
2071
						continue;
1 cycrow 2072
 
170 cycrow 2073
					// not in a section yet
2074
					if (secCount2)
2075
					{
2076
						if (sceneModels.contains(file))
2077
							this->AddComponent(section, file, str);
2078
						--secCount2;
2079
					}
2080
					else if (secCount <= 0)
2081
					{
2082
						section = str.token(";", 1);
2083
						secCount = str.token(";", 2).toInt();
2084
					}
2085
					else
2086
					{
2087
						file = str.token(";", 1);
2088
						secCount2 = str.token(";", 2).toInt();
2089
						--secCount;
2090
					}
1 cycrow 2091
				}
2092
			}
2093
 
52 cycrow 2094
			File.remove();
1 cycrow 2095
		}
2096
	}
2097
}
2098
 
197 cycrow 2099
bool CXspFile::getTextureList(Utils::WStringList &list, const unsigned char *olddata, size_t size) const
1 cycrow 2100
{
2101
	if ( !olddata || !size )
2102
		return false;
2103
 
2104
	size_t startLine = 0;
114 cycrow 2105
	Utils::String line;
1 cycrow 2106
	size_t pos = 0;
2107
 
2108
	unsigned char *data = new unsigned char[size];
2109
	memcpy(data, olddata, size);
2110
 
2111
	while ( (pos++) < size )
2112
	{
2113
		if ( data[pos] == '\n' )
2114
		{
2115
			data[pos] = '\0';
2116
			line = (char *)(data + startLine);
114 cycrow 2117
			line.removeChar(9);
2118
			line.removeChar('\r');
2119
			line.removeFirstSpace();
1 cycrow 2120
 
114 cycrow 2121
			if ( !line.empty() && line[0] != '/' )
1 cycrow 2122
			{
114 cycrow 2123
				Utils::String first = line.token(":", 1);
1 cycrow 2124
				if ( first.Compare("MATERIAL6") )
2125
				{
2126
					int max;
114 cycrow 2127
					Utils::String material = line.tokens(":", 2);
2128
					Utils::String *strs = material.tokens(";", 6).tokenise("; ", &max);
1 cycrow 2129
 
114 cycrow 2130
					int num = material.token(";", 5);
1 cycrow 2131
					if ( strs && max >= 2)
2132
					{
114 cycrow 2133
						for(int i = 0; i < max; i++) {
2134
							Utils::String type = strs[i].token(";", 1);
2135
							Utils::String valtype = strs[i].token(";", 2);			
2136
							if ( valtype.Compare("SPTYPE_STRING") ) {
2137
								Utils::String file = strs[i].token(";", 3);
170 cycrow 2138
								if(!list.contains(file))
2139
									list.pushBack(file, "");
114 cycrow 2140
							}
2141
						}
1 cycrow 2142
					}
2143
 
2144
					CLEANSPLIT(strs, max)
2145
				}
2146
			}
2147
 
2148
			startLine = pos + 1;
2149
		}
2150
	}
2151
 
2152
	delete [] data;
2153
 
2154
	return true;
2155
}
2156
 
35 cycrow 2157
void CXspFile::extractTextures(CVirtualFileSystem *pVfs)
1 cycrow 2158
{
197 cycrow 2159
	Utils::WStringList lTextures;
1 cycrow 2160
 
2161
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2162
	{
2163
		C_File *f = node->Data();
2164
		if ( f->GetFileType() != FILETYPE_SHIPMODEL )
2165
			continue;
2166
 
115 cycrow 2167
		bool deleteData = false;
114 cycrow 2168
		unsigned char *data = NULL;
2169
		size_t size;
2170
 
1 cycrow 2171
		// cant do these yet
197 cycrow 2172
		if (f->checkFileExt(L"pbb") || f->checkFileExt(L"bob"))
1 cycrow 2173
		{
115 cycrow 2174
			data = f->BobDecompile(&size);
2175
			if ( !data || !size ) {
114 cycrow 2176
				// search for the pbd or bod files that match and use them instead
197 cycrow 2177
				Utils::WString file;
114 cycrow 2178
 
197 cycrow 2179
				file = CFileIO(f->getNameDirectory(NULL)).changeFileExtension(L"pbd");
2180
				file = pVfs->extractGameFile(file, CPackages::tempDirectory() + L"tmp.tmp");
114 cycrow 2181
 
2182
				if ( file.empty() ) {
197 cycrow 2183
					file = CFileIO(f->getNameDirectory(NULL)).changeFileExtension(L"bod");
2184
					file = pVfs->extractGameFile(file, CPackages::tempDirectory() + L"tmp.tmp");
114 cycrow 2185
				}
2186
 
2187
				if ( !file.empty() ) {
2188
					CFileIO File(file);
2189
					if ( File.exists() ) {
2190
						data = File.readAll(&size);
2191
						File.remove();
2192
					}
2193
				}
2194
 
2195
				if ( data && size ) 
170 cycrow 2196
					this->getTextureList(lTextures, data, size);
1 cycrow 2197
				continue;
114 cycrow 2198
			}
1 cycrow 2199
 
115 cycrow 2200
			deleteData = true;
1 cycrow 2201
		}
2202
 
115 cycrow 2203
		if ( !data || !size ) {
2204
			if ( !f->GetData() )
2205
			{
2206
				if ( !f->ReadFromFile() )
2207
					continue;
2208
			}
1 cycrow 2209
 
115 cycrow 2210
 
178 cycrow 2211
			if ( f->checkFileExt("pbb") || f->checkFileExt("pbd") )
115 cycrow 2212
				data = f->UnPCKFile(&size);
2213
			else
2214
			{
2215
				data = f->GetData();
2216
				size = f->GetDataSize();
2217
			}
1 cycrow 2218
		}
170 cycrow 2219
		this->getTextureList(lTextures, data, size);
1 cycrow 2220
 
115 cycrow 2221
		if ( deleteData ) delete data;
1 cycrow 2222
	}
2223
 
170 cycrow 2224
	for(auto itr = lTextures.begin(); itr != lTextures.end(); itr++)
1 cycrow 2225
	{
170 cycrow 2226
		CFileIO F((*itr)->str);
196 cycrow 2227
		if ( F.isFileExtension(L"fx") ) {
116 cycrow 2228
			/*
2229
			if ( !pVfs->extractGameFileToPackage(this, "shader\\1_1\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER) )
2230
				pVfs->extractGameFileToPackage(this, "shader\\1_1\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
2231
			if ( !pVfs->extractGameFileToPackage(this, "shader\\1_4\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER) )
2232
				pVfs->extractGameFileToPackage(this, "shader\\1_4\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
2233
			if ( !pVfs->extractGameFileToPackage(this, "shader\\2_0\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER) )
2234
				pVfs->extractGameFileToPackage(this, "shader\\2_0\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
2235
			if ( !pVfs->extractGameFileToPackage(this, "shader\\2_a\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER) )
2236
				pVfs->extractGameFileToPackage(this, "shader\\2_a\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
2237
			if ( !pVfs->extractGameFileToPackage(this, "shader\\2_b\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER) )
2238
				pVfs->extractGameFileToPackage(this, "shader\\2_b\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
2239
			if ( !pVfs->extractGameFileToPackage(this, "shader\\3_0\\" + Utils::String(node->str.ToString()), FILETYPE_SHIPOTHER) )
2240
				pVfs->extractGameFileToPackage(this, "shader\\3_0\\" + CFileIO(node->str.ToString()).ChangeFileExtension("fb").ToString(), FILETYPE_SHIPOTHER);
2241
				*/
114 cycrow 2242
		}
2243
		else {
197 cycrow 2244
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str, FILETYPE_SHIPOTHER) )
116 cycrow 2245
				continue;
2246
 
197 cycrow 2247
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str.token(L".", -1), FILETYPE_SHIPOTHER) )
116 cycrow 2248
				continue;
2249
 
197 cycrow 2250
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + (*itr)->str + L".dds", FILETYPE_SHIPOTHER) )
116 cycrow 2251
				continue;
2252
 
197 cycrow 2253
			if ( pVfs->extractGameFileToPackage(this, L"dds\\" + F.changeFileExtension(L"dds"), FILETYPE_SHIPOTHER) )
116 cycrow 2254
				continue;
2255
 
197 cycrow 2256
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str, FILETYPE_SHIPOTHER) )
116 cycrow 2257
				continue;
2258
 
197 cycrow 2259
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str.token(L".", -1), FILETYPE_SHIPOTHER) )
116 cycrow 2260
				continue;
2261
 
197 cycrow 2262
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + (*itr)->str + L".jpg", FILETYPE_SHIPOTHER) )
116 cycrow 2263
				continue;
2264
 
197 cycrow 2265
			if ( pVfs->extractGameFileToPackage(this, L"textures\\" + F.changeFileExtension(L"jpg"), FILETYPE_SHIPOTHER) )
116 cycrow 2266
				continue;
114 cycrow 2267
		}
1 cycrow 2268
	}
2269
}
2270
 
197 cycrow 2271
bool CXspFile::addTextFromFile(const Utils::WString &sFile, int textId)
1 cycrow 2272
{
197 cycrow 2273
	Utils::WString file = sFile;
39 cycrow 2274
 
1 cycrow 2275
	bool remove = false;
196 cycrow 2276
	if ( CFileIO(file).isFileExtension(L"pck") )
1 cycrow 2277
	{
39 cycrow 2278
		C_File F;
170 cycrow 2279
		F.setFilename(file);
1 cycrow 2280
		F.UnPCKFile();
197 cycrow 2281
		if (F.writeToFile(CPackages::tempDirectory() + L"tmp.dat"))
1 cycrow 2282
		{
2283
			remove = true;
197 cycrow 2284
			file = CPackages::tempDirectory() + L"tmp.dat";
1 cycrow 2285
		}
2286
	}
2287
 
78 cycrow 2288
	/*
68 cycrow 2289
	std::wfstream fileStream(file.c_str());
2290
	if ( fileStream.is_open() ) {
2291
		while(!fileStream.eof()) {
2292
			std::wstring line;
2293
			std::getline(fileStream, line);
2294
			int i =0;
2295
		}
2296
		fileStream.close();
2297
	}
78 cycrow 2298
	*/
68 cycrow 2299
 
118 cycrow 2300
	CFileIO F(file);
2301
	if ( F.exists() && F.startRead() ) {
2302
		bool ret = this->_addTextFromFile(F, textId);
2303
		F.close();
1 cycrow 2304
 
52 cycrow 2305
		if ( remove ) CFileIO::Remove(file);
50 cycrow 2306
		_changed();
1 cycrow 2307
		return ret;
2308
	}
2309
 
2310
	return false;
2311
}
2312
 
170 cycrow 2313
bool CXspFile::importBodies(const Utils::CStringList &sceneModels, const Utils::String &filename)
1 cycrow 2314
{
2315
	CFileIO File(filename);
52 cycrow 2316
	if ( File.exists() )
1 cycrow 2317
	{
39 cycrow 2318
		Utils::String sSection;
1 cycrow 2319
		int section = 0;
170 cycrow 2320
		std::vector<Utils::String> lines;
2321
		if (File.readLines(lines))
1 cycrow 2322
		{
170 cycrow 2323
			for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 2324
			{
170 cycrow 2325
				Utils::String l = *itr;
2326
				l.removeChar(9);
2327
				l.removeChar('\r');
2328
				l.removeFirstSpace();
2329
				if (l.empty())
2330
					continue;
2331
				if (l[0] == '/')
2332
					continue;
2333
 
2334
				// are we looking for a section
2335
				if (section <= 0)
1 cycrow 2336
				{
170 cycrow 2337
					sSection = l.token(";", 1);
2338
					section = l.token(";", 2).toInt();
2339
				}
2340
				else
2341
				{
2342
					int max;
2343
					Utils::String* strs = l.tokenise(";", &max);
2344
					if (strs && max)
1 cycrow 2345
					{
170 cycrow 2346
						for (int i = 0; i < max; i++)
2347
						{
2348
							strs[i].removeEndSpace();
2349
							strs[i].removeFirstSpace();
2350
							if (strs[i].empty())
2351
								continue;
2352
							if (sceneModels.contains(strs[i]))
2353
								this->addBody(sSection, strs[i]);
2354
							--section;
2355
						}
1 cycrow 2356
					}
170 cycrow 2357
					CLEANSPLIT(strs, max)
1 cycrow 2358
				}
2359
			}
170 cycrow 2360
			return true;
1 cycrow 2361
		}
2362
	}
2363
 
2364
	return false;
2365
}
2366
 
39 cycrow 2367
bool CXspFile::ImportCockpits(const Utils::String &filename)
1 cycrow 2368
{
2369
	CFileIO File(filename);
52 cycrow 2370
	if ( File.exists() )
1 cycrow 2371
	{
170 cycrow 2372
		std::vector<Utils::String> lines;
2373
		if (File.readLines(lines))
1 cycrow 2374
		{
170 cycrow 2375
			int entries = 0;
2376
			auto itr = lines.begin();
2377
			while(itr != lines.end())
1 cycrow 2378
			{
170 cycrow 2379
				Utils::String str = itr->remove(9).remove('\r');
2380
				str.removeFirstSpace();
2381
				if (str.empty())
2382
					itr = lines.erase(itr);
2383
				else if (str[0] == '/')
2384
					itr = lines.erase(itr);
2385
				else if (!entries)
2386
				{
2387
					entries = str.token(";", 2).toInt();
2388
					itr = lines.erase(itr);
2389
				}
2390
				else
2391
					itr++;
1 cycrow 2392
			}
2393
 
170 cycrow 2394
			// now get all the entries from TShips
2395
			for (int i = 0; i < 6; i++)
1 cycrow 2396
			{
170 cycrow 2397
				int idx = m_sData.token(";", 32 + (i * 2));
2398
				if (static_cast<size_t>(idx) < lines.size() && idx)
2399
				{
2400
					Utils::String turret = lines[idx];
2401
					int pos = -1;
2402
					Utils::String id;
2403
					while (id.empty() && pos > -100) id = turret.token(";", pos--);
2404
					m_sData = m_sData.replaceToken(";", 32 + (i * 2), id + "(" + (long)idx + ")");
1 cycrow 2405
 
170 cycrow 2406
					this->AddCockpit(turret, 0);
2407
				}
1 cycrow 2408
			}
2409
		}
2410
		return true;
2411
	}
2412
	return false;
2413
}
2414
 
35 cycrow 2415
bool CXspFile::extractCockpits(CVirtualFileSystem *pVfs)
1 cycrow 2416
{
197 cycrow 2417
	if ( !pVfs->extractGameFile(L"types/TCockpits.pck", CPackages::tempDirectory() + L"tmp.dat").empty() ) {
2418
		bool ret = this->ImportCockpits((CPackages::tempDirectory() + L"tmp.dat").toString());
2419
		CFileIO::Remove(CPackages::tempDirectory() + L"tmp.dat");
1 cycrow 2420
 
2421
		return ret;
2422
	}
2423
 
2424
	return false;
2425
}
2426
 
170 cycrow 2427
bool CXspFile::extractBodies(CVirtualFileSystem *pVfs, const Utils::CStringList &sceneModels)
1 cycrow 2428
{
170 cycrow 2429
	if (sceneModels.empty()) return false;
31 cycrow 2430
 
197 cycrow 2431
	if ( !pVfs->extractGameFile(L"types/Bodies.pck", CPackages::tempDirectory() + L"tmp.dat").empty() ) {
2432
		bool ret = this->importBodies(sceneModels, (CPackages::tempDirectory() + L"tmp.dat").toString());
2433
		CFileIO::Remove(CPackages::tempDirectory() + L"tmp.dat");
1 cycrow 2434
 
2435
		return ret;
2436
	}
2437
 
2438
	return false;
2439
}
2440
 
118 cycrow 2441
bool CXspFile::_addTextFromFile(CFileIO &F, int textId)
1 cycrow 2442
{
14 cycrow 2443
	if ( textId == -1 && !m_sData.empty() )
2444
		textId = m_sData.token(";", 7);
1 cycrow 2445
 
2446
	if ( textId <= 0 )
2447
		return false;
2448
 
118 cycrow 2449
	if ( !F.isOpened() )
1 cycrow 2450
		return false;
2451
 
2452
	bool added = false;
2453
 
39 cycrow 2454
	Utils::String shipName;
2455
	Utils::String shipDesc;
1 cycrow 2456
 
68 cycrow 2457
	int lastAddedGameID = 0;
2458
	int currentGameID = 0;
1 cycrow 2459
	int lang = 0;
2460
	bool inpage = false;
118 cycrow 2461
 
2462
	while(!F.atEnd()) {
39 cycrow 2463
		if ( !shipName.empty() && !shipDesc.empty() )
1 cycrow 2464
		{
2465
			added = true;
2466
			break;
2467
		}
2468
 
197 cycrow 2469
		Utils::String line = F.readEndOfLineStr();
39 cycrow 2470
		line.removeChar(9);
2471
		line.removeChar('\r');
2472
		line.removeFirstSpace();
118 cycrow 2473
 
1 cycrow 2474
		if ( inpage )
2475
		{
68 cycrow 2476
			if ( line.left(6).Compare("</page") ) {
2477
				inpage = false;
2478
				continue;
2479
			}
1 cycrow 2480
 
2481
			// find matching id
39 cycrow 2482
			if ( line.left(6).Compare("<t id=") )
1 cycrow 2483
			{
39 cycrow 2484
				int pos = line.findPos("id=\"", 0);
1 cycrow 2485
				if ( pos != -1 )
2486
				{
68 cycrow 2487
					pos += 4;
2488
					int endpos = line.findPos("\"", pos);
1 cycrow 2489
					if ( endpos != -1 )
2490
					{
68 cycrow 2491
						int id = line.mid(pos, endpos);
1 cycrow 2492
						if ( id == textId || id == (textId + 1) )
2493
						{
39 cycrow 2494
							pos = line.findPos(">", endpos);
1 cycrow 2495
							if ( pos != -1 )
2496
							{
39 cycrow 2497
								endpos = line.findPos("</t>", pos);
1 cycrow 2498
								if ( endpos != -1 )
2499
								{
2500
									if ( id == textId )
68 cycrow 2501
										shipName = line.mid(pos + 1, endpos);
1 cycrow 2502
									else
68 cycrow 2503
										shipDesc = line.mid(pos + 1, endpos);
2504
									lastAddedGameID = currentGameID;
1 cycrow 2505
								}
2506
							}
2507
						}
2508
					}
2509
				}
2510
			}
2511
		}
2512
		else if ( lang ) // search for page 17
2513
		{
39 cycrow 2514
			if ( line.left(8).Compare("<page id") )
1 cycrow 2515
			{
39 cycrow 2516
				int pos = line.findPos("id=\"");
1 cycrow 2517
				if ( pos != -1 )
2518
				{
68 cycrow 2519
					pos += 4;
2520
					int endpos = line.findPos("\"", pos);
1 cycrow 2521
					if ( endpos != -1 )
2522
					{
68 cycrow 2523
						Utils::String sId = line.mid(pos, endpos);
39 cycrow 2524
						int id = sId;
68 cycrow 2525
						if ( sId.length() > 4 ) {
2526
							id = sId.right(4);
2527
							currentGameID = sId.left(sId.length() - 4);
2528
						}
2529
 
2530
						if ( currentGameID >= lastAddedGameID && id == 17 )
1 cycrow 2531
							inpage = true;
2532
					}
2533
				}
2534
			}
2535
		}
39 cycrow 2536
		else if ( line.left(12).Compare("<language id") )
1 cycrow 2537
		{
39 cycrow 2538
			int pos = line.findPos("id=\"");
1 cycrow 2539
			if ( pos != -1 )
2540
			{
68 cycrow 2541
				// move past the id=
2542
				pos += 4;
2543
 
2544
				Utils::String s = line.right(-pos);
2545
				Utils::String s2 = line.mid(pos, -1);
2546
				int endpos = line.findPos("\"", pos);
1 cycrow 2547
				if ( endpos != -1 )
68 cycrow 2548
					lang = line.mid(pos, endpos);
1 cycrow 2549
			}
2550
		}
2551
	}
2552
 
2553
	// incase we only found the shipname
39 cycrow 2554
	if ( !shipName.empty() )
1 cycrow 2555
		added = true;
2556
 
2557
	if ( added )
2558
	{
50 cycrow 2559
		if ( lang == 44 || this->name().empty())
1 cycrow 2560
		{
50 cycrow 2561
			this->setName(shipName);
48 cycrow 2562
			this->setDescription(shipDesc.findReplace("&amp", "&"));
1 cycrow 2563
		}
2564
		this->AddText(lang, shipName, shipDesc);
2565
		return true;	
2566
	}
2567
 
2568
	return false;
2569
}
2570
 
31 cycrow 2571
void CXspFile::ExtractTexts(CCatFile *catFile, CCatFile *secondCatFile, int textId)
1 cycrow 2572
{
124 cycrow 2573
	for (auto itr = catFile->GetFiles()->begin(); itr != catFile->GetFiles()->end(); itr++ )
1 cycrow 2574
	{
124 cycrow 2575
		SInCatFile *f = *itr;
2576
		if ( !f->sFile.left(2).Compare("t\\") && !f->sFile.left(2).Compare("t/") )
1 cycrow 2577
			continue;
2578
 
2579
		// extract the text file and read in the data
181 cycrow 2580
		bool extracted = catFile->extractFile(f->sFile, CPackages::tempDirectory() + "/tmp.dat");
2581
		if ( !extracted && secondCatFile ) extracted = secondCatFile->extractFile(f->sFile, CPackages::tempDirectory() + "/tmp.dat");
31 cycrow 2582
		if ( extracted ) {
197 cycrow 2583
			this->addTextFromFile(CPackages::tempDirectory() + L"/tmp.dat", textId);
2584
			CFileIO::Remove(CPackages::tempDirectory() + L"/tmp.dat");
1 cycrow 2585
		}
2586
	}
2587
}
2588
 
170 cycrow 2589
bool CXspFile::processSceneFileSection(int section, CVirtualFileSystem *pVfs, Utils::CStringList &lModels, CProgressInfo *progress)
1 cycrow 2590
{
2591
	if ( progress ) progress->UpdateStatus(section);
2592
 
2593
	switch ( section )
2594
	{
2595
		case IMPORTSHIP_COMPONANT:
170 cycrow 2596
			if (lModels.empty()) return false;
35 cycrow 2597
			this->extractComponants(pVfs, lModels);
1 cycrow 2598
			break;
2599
 
2600
		case IMPORTSHIP_MODELS:
2601
			{
170 cycrow 2602
				if (lModels.empty()) return false;
2603
				for(auto itr = lModels.begin(); itr != lModels.end(); itr++)
1 cycrow 2604
				{
170 cycrow 2605
					if ((*itr)->str.isNumber() ) // count be componants or dummy
1 cycrow 2606
						continue;
170 cycrow 2607
					if ( pVfs->extractGameFileToPackage(this, "objects\\" + (*itr)->str + ".pbb", FILETYPE_SHIPMODEL, "objects\\" + (*itr)->str + ".bob") )
1 cycrow 2608
						continue;
170 cycrow 2609
					if ( pVfs->extractGameFileToPackage(this, "objects\\" + (*itr)->str + ".pbd", FILETYPE_SHIPMODEL, "objects\\" + (*itr)->str + ".bod") )
1 cycrow 2610
						continue;
2611
				}
2612
			}
2613
			break;
2614
 
2615
		case IMPORTSHIP_DUMMIES:
170 cycrow 2616
			if (lModels.empty()) return false;
35 cycrow 2617
			this->extractDummies(pVfs, lModels, true);
42 cycrow 2618
			this->extractCutData(pVfs, lModels, true);
1 cycrow 2619
			break;
2620
 
2621
		// extract the textures
2622
		case IMPORTSHIP_TEXTURES:
35 cycrow 2623
			this->extractTextures(pVfs);
1 cycrow 2624
			break;
2625
 
2626
		case IMPORTSHIP_TEXTS:
2627
			// extract the text file entries
35 cycrow 2628
			pVfs->extractTexts(this, m_sData.token(";", 7));
1 cycrow 2629
			break;
2630
 
2631
		case IMPORTSHIP_BODIES:
2632
			// extract the bodies entries
170 cycrow 2633
			if (lModels.empty()) return false;
35 cycrow 2634
			this->extractBodies(pVfs, lModels);
1 cycrow 2635
			break;
2636
 
2637
		case IMPORTSHIP_COCKPITS:
2638
			// extract the cockpit entries
35 cycrow 2639
			this->extractCockpits(pVfs);
1 cycrow 2640
			break;
2641
	}
2642
 
2643
	return true;
2644
}
2645
 
35 cycrow 2646
bool CXspFile::processSceneFiles(CVirtualFileSystem *pVfs, CProgressInfo *progress)
1 cycrow 2647
{
2648
	// now lets parse our files
2649
	if ( progress ) progress->UpdateStatus(IMPORTSHIP_EXTRACTSCENE);
170 cycrow 2650
	Utils::CStringList lModels;
2651
	if(!readSceneModels(lModels))
1 cycrow 2652
		return false;
2653
 
2654
	// extract componants, and add extra items to list
35 cycrow 2655
	if ( !this->processSceneFileSection(IMPORTSHIP_COMPONANT, pVfs, lModels, progress) )
1 cycrow 2656
		return false;
2657
 
2658
	//lets first find any model files
35 cycrow 2659
	if ( !this->processSceneFileSection(IMPORTSHIP_MODELS, pVfs, lModels, progress) )
1 cycrow 2660
		return false;
2661
 
2662
	// extract the dummies
35 cycrow 2663
	if ( !this->processSceneFileSection(IMPORTSHIP_DUMMIES, pVfs, lModels, progress) )
1 cycrow 2664
		return false;
2665
 
2666
	// extract the textures
35 cycrow 2667
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTURES, pVfs, lModels, progress) )
1 cycrow 2668
		return false;
2669
 
2670
	// extract the text file entries
35 cycrow 2671
	if ( !this->processSceneFileSection(IMPORTSHIP_TEXTS, pVfs, lModels, progress) )
1 cycrow 2672
		return false;
2673
 
2674
	// extract the bodies entries
35 cycrow 2675
	if ( !this->processSceneFileSection(IMPORTSHIP_BODIES, pVfs, lModels, progress) )
1 cycrow 2676
		return false;
2677
 
2678
	// extract the cockpit entries
35 cycrow 2679
	if ( !this->processSceneFileSection(IMPORTSHIP_COCKPITS, pVfs, lModels, progress) )
1 cycrow 2680
		return false;
2681
 
2682
	return true;
2683
}
2684
 
2685
 
2686
void CXspFile::PackAllFiles()
2687
{
2688
	for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
2689
	{
2690
		C_File *f = node->Data();
2691
		if ( f->GetFileType() == FILETYPE_SHIPSCENE || f->GetFileType() == FILETYPE_COCKPITSCENE || f->GetFileType() == FILETYPE_SHIPMODEL || f->GetFileType() == FILETYPE_SHIPOTHER )
41 cycrow 2692
		{	
2693
			/*
1 cycrow 2694
			if ( f->CheckFileExt("bod") )
2695
			{
2696
				if ( f->PCKFile() )
2697
					f->ChangeFileExt("pbd");
41 cycrow 2698
			}	
42 cycrow 2699
 
178 cycrow 2700
			else */if ( f->checkFileExt("bob") )
1 cycrow 2701
			{
2702
				if ( f->PCKFile() )
178 cycrow 2703
					f->changeFileExt("pbb");
42 cycrow 2704
			}
1 cycrow 2705
		}
2706
	}
2707
}
2708
 
2709
void CXspFile::AdjustCockpits()
2710
{
2711
	for ( CListNode<SCockpit> *node = m_lCockpit.Front(); node; node = node->next() )
2712
	{
2713
		SCockpit *c = node->Data();
2714
		if ( c->iIndex < 0 )
2715
			continue;
2716
 
39 cycrow 2717
		Utils::String id = c->sCockpit.token(";", 19);
1 cycrow 2718
 
2719
		for ( int i = 0; i < 6; i++ )
2720
		{
39 cycrow 2721
			Utils::String tId = m_sData.token(";", 32 + (i * 2));
2722
			if ( tId.isNumber() && ((int)tId) == c->iIndex )
50 cycrow 2723
				m_sData = m_sData.replaceToken(";", 32 + (i * 2), (id + "(" + Utils::String::Number(c->iIndex) + ")").c_str());
1 cycrow 2724
		}
2725
	}
2726
}
2727
 
170 cycrow 2728
Utils::String CXspFile::formatShipData(const Utils::CStringList &cockpits, int *text, int game)
1 cycrow 2729
{
39 cycrow 2730
	Utils::String data = (game == GAME_X3) ? this->GetX3ShipData() : this->GetTCShipData();
1 cycrow 2731
	// do turrets
2732
	for ( int t = 0; t < 6; t++ )
2733
	{
2734
		int oldPos = 0;
39 cycrow 2735
		Utils::String turret = data.token(";", 32 + (t * 2));
2736
		if ( !turret.isNumber() )
1 cycrow 2737
		{
39 cycrow 2738
			if ( turret.isin("(") )
1 cycrow 2739
			{
39 cycrow 2740
				oldPos = turret.tokens("(", 2).token(")", 1);
2741
				turret = turret.token("(", 1);
1 cycrow 2742
			}
170 cycrow 2743
			int pos = cockpits.findPos(turret);
1 cycrow 2744
			if ( pos < 0 )	pos = oldPos;
170 cycrow 2745
			if (static_cast<size_t>(pos) >= cockpits.size()) pos = 0;
39 cycrow 2746
			data = data.replaceToken(";", 32 + (t * 2), (long)pos);
1 cycrow 2747
		}
2748
	}
2749
	// adjust the weapons
2750
	int mask = this->GetLaserMask(game - 1);
2751
	if ( mask != -1 )
39 cycrow 2752
		data = data.replaceToken(";", 19, (long)mask);
1 cycrow 2753
	mask = this->GetMissileMask(game - 1);
2754
	if ( mask != -1 )
39 cycrow 2755
		data = data.replaceToken(";", 25, (long)mask);
1 cycrow 2756
 
2757
	// fix the ship text
2758
	if ( m_iOrgDesc > 0 )
2759
		(*text) = m_iOrgDesc;
39 cycrow 2760
	data = data.replaceToken(";", 7, (long)*text);
1 cycrow 2761
 
2762
	// add the ware id
39 cycrow 2763
	data.removeChar(9);
2764
	data.removeEndSpace();
1 cycrow 2765
	// remove the end ;
39 cycrow 2766
	while ( data.right(1) == ";" ) data.truncate(-1);
2767
	data = data.replaceToken(";", data.countToken(";"), this->GetShipID());
2768
	if ( data.right(1) != ";" )
1 cycrow 2769
		data += ";";
2770
 
2771
	return data;
35 cycrow 2772
}
2773