Subversion Repositories spk

Rev

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