Subversion Repositories spk

Rev

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