Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
 
2
#include "ModDiff.h"
3
#include "File_IO.h"
4
#include "CatFile.h"
5
 
58 cycrow 6
CModDiff::CModDiff(const Utils::String &dir, const Utils::String &sAddon, int maxPatch) : m_pCatFile(NULL), m_sAddon(sAddon), m_sTempDir("."), m_iMaxPatch(maxPatch)
1 cycrow 7
{
58 cycrow 8
	m_bLoaded = this->LoadDirectory(dir);
1 cycrow 9
}
10
 
11
CModDiff::~CModDiff(void)
12
{
58 cycrow 13
	delete m_pCatFile;
1 cycrow 14
}
15
 
58 cycrow 16
bool CModDiff::LoadDirectory(const Utils::String &dir)
1 cycrow 17
{
18
	m_sCurrentDir = dir;
101 cycrow 19
	m_fileSystem.setAddon(m_sAddon);
58 cycrow 20
	return m_fileSystem.LoadFilesystem(dir, m_iMaxPatch);
1 cycrow 21
}
22
 
58 cycrow 23
bool CModDiff::startDiff(const Utils::String &sModFile)
1 cycrow 24
{
25
	ClearError();
58 cycrow 26
	if ( !CFileIO::Exists(sModFile) ) { m_iError = MDERR_FILENOTFOUND; return false; }
1 cycrow 27
 
58 cycrow 28
	delete m_pCatFile;
29
	m_pCatFile = new CCatFile;
30
 
125 cycrow 31
	if ( m_pCatFile->open(sModFile, m_sAddon, CATREAD_CATDECRYPT, false) != CATERR_NONE ) { 
58 cycrow 32
		delete m_pCatFile;
33
		m_pCatFile = NULL;
34
		m_iError = MDERR_CANTOPENMOD; 
35
		return false; 
36
	}
37
 
38
	return true;
39
}
40
 
41
Utils::String CModDiff::_extractFile(const Utils::String &sFile, const Utils::String &sTo)
42
{
181 cycrow 43
	SInCatFile *c = m_pCatFile->findData(sFile);
44
	if ( !c ) c = m_pCatFile->findData(m_sAddon + "/" + sFile);
58 cycrow 45
	if ( !c ) return m_fileSystem.ExtractGameFile(sFile, sTo);
181 cycrow 46
	if (m_pCatFile->extractFile(c, sTo)) return sTo;
58 cycrow 47
	return "";
48
}
49
 
50
bool CModDiff::doDiff(const Utils::String &sModFile)
51
{
52
	// find the file in the loaded cat
181 cycrow 53
	SInCatFile *c = m_pCatFile->findData(sModFile);
54
	if ( !c ) c = m_pCatFile->findData(m_sAddon + "/" + sModFile);
58 cycrow 55
	if ( !c ) return false;
56
 
196 cycrow 57
	Utils::WString temp = m_sTempDir.toWString();
58
 
58 cycrow 59
	// extract the matching file
196 cycrow 60
	Utils::String sToFile = CFileIO(temp + L"/" + CFileIO(c->sFile).filename()).fullFilenameStr();
181 cycrow 61
	if ( !m_pCatFile->extractFile(sModFile, sToFile) ) return false;
58 cycrow 62
 
63
	// create a diff
124 cycrow 64
	Utils::String to = m_fileSystem.ExtractGameFile(c->sFile, sToFile + ".compare");
58 cycrow 65
	if ( !to.empty() ) {
124 cycrow 66
		SDiffFile *diff = diffFile(to, sToFile, c->sFile);
58 cycrow 67
		if ( diff ) { 
68
			this->_adjustFile(sModFile, diff, false);
69
		}
70
		CFileIO::Remove(to);
71
	}
72
 
73
	CFileIO::Remove(sToFile);
74
 
75
	return true;
76
}
77
 
78
 
79
bool CModDiff::_adjustTShips(SDiffFile *pDiff, bool bReverse)
80
{
81
	// need to read TCockpits
82
	Utils::String sTo = this->_extractFile("types/TCockpits.pck", "TCockpits.xml");
83
	if ( sTo.empty() ) return false;
84
	CFileIO TCockpits("TCockpits.xml");
85
	if ( !TCockpits.exists() ) return false;
173 cycrow 86
	std::vector<Utils::String> lines;
87
	if (!TCockpits.readLines(lines))
88
		return false;
58 cycrow 89
 
90
	// remove all the comments
173 cycrow 91
	auto itr = lines.begin();
92
	while(itr != lines.end())
93
	{
94
		if ((*itr)[0] == '/')
95
			itr = lines.erase(itr);
96
		else
97
			itr++;
58 cycrow 98
	}
173 cycrow 99
	lines.erase(lines.begin());
58 cycrow 100
 
84 cycrow 101
	std::map<Utils::String, int> fileSet;
58 cycrow 102
	int iPos = 0;
173 cycrow 103
	for(itr = lines.begin(); itr != lines.end(); itr++)
104
		fileSet[itr->token(";", -2)] = iPos++;
58 cycrow 105
 
106
	// now cycle through ships and adjust the cockpits
107
	int iCount = -1;
108
	for ( SDiffEntry *pEntry = pDiff->m_lEntries.First(); pEntry; pEntry = pDiff->m_lEntries.Next() ) {
109
		switch (pEntry->iType) {
110
			case DIFFTYPE_ADDITION:
111
				{
112
					SDiffEntryAddition *pAddition = static_cast<SDiffEntryAddition *>(pEntry);
113
					if ( pAddition ) {
114
						for ( int t = 0; t < 6; t++ ) {
115
							Utils::String sE = pAddition->sEntry.token(";", 32 + (t * 2));
173 cycrow 116
							if ( !bReverse && sE.isNumber() )
117
							{
58 cycrow 118
								int iTurret = sE;
173 cycrow 119
								if ( iTurret && static_cast<size_t>(iTurret) < lines.size()) 
120
								{
121
									Utils::String sCockpit = lines[iTurret];
58 cycrow 122
									pAddition->sEntry = pAddition->sEntry.replaceToken(";", 32 + (t * 2), sCockpit.token(";", -2) + ":" + static_cast<long>(iTurret));
123
								}
124
							}
125
							else if ( bReverse && !sE.isNumber() ) {
126
								int iUnfound = 0;
127
								if ( sE.isin(":") ) {
128
									iUnfound = sE.token(":", 2);
129
									sE = sE.token(":", 1);
130
								}
131
								int iEntry = (fileSet.find(sE) == fileSet.end()) ? iUnfound : fileSet[sE];
132
								pAddition->sEntry = pAddition->sEntry.replaceToken(";", 32 + (t * 2), static_cast<long>(iEntry));
133
							}
134
						}
135
					}
136
				}
137
				break;
138
			case DIFFTYPE_CHANGE:
139
				{
140
					SDiffEntryChange *pChange = static_cast<SDiffEntryChange *>(pEntry);
141
					if ( pChange->iPos >= 32 && pChange->iPos <= 42 && (pChange->iPos % 2) && pChange->sEntry.isNumber() ) {
173 cycrow 142
						Utils::String sCockpit = lines[pChange->sEntry.toInt()];
58 cycrow 143
						pChange->sEntry = sCockpit.token(";", -2) + ":" + pChange->sEntry;
144
					}
145
				}
146
				break;
147
		}
148
	}
149
 
150
	return true;
151
}
152
 
196 cycrow 153
int CModDiff::_specialType(const Utils::WString &sFile) const
58 cycrow 154
{
196 cycrow 155
	if ( sFile.Compare(L"TShips") ) return MERGETYPE_TSHIPS;
58 cycrow 156
	return MERGETYPE_NONE;
157
}
158
 
159
void CModDiff::_adjustFile(const Utils::String &sFile, SDiffFile *pDiff, bool bReverse)
160
{
161
	// check if we need to adjust the file
162
	CFileIO File(sFile);
163
	int iType = _specialType(File.baseName());
164
	if ( iType == MERGETYPE_NONE ) return;
165
 
166
	// read in the file data
167
	switch(iType) {
168
		case MERGETYPE_TSHIPS:
169
			this->_adjustTShips(pDiff, bReverse);
170
			break;
171
	}
172
}
173
 
174
bool CModDiff::CreateDiff(const Utils::String &modfile)
175
{
176
	ClearError();
177
 
1 cycrow 178
	//check for valid parameters
52 cycrow 179
	if ( !CFileIO(modfile).ExistsOld() ) { m_iError = MDERR_FILENOTFOUND; return false; }
1 cycrow 180
 
58 cycrow 181
	Utils::String addonDir = "";
182
	int addonSize = addonDir.length() + 1;
1 cycrow 183
 
184
	// try and open the mod file
185
	CCatFile cat;
125 cycrow 186
	if ( cat.open(modfile, addonDir, CATREAD_DAT, false) != CATERR_NONE ) { m_iError = MDERR_CANTOPENMOD; return false; }
1 cycrow 187
 
196 cycrow 188
	Utils::WString temp = m_sTempDir.toWString();
189
 
1 cycrow 190
	// we'll need to read in all the types/text files
125 cycrow 191
	for (unsigned int i = 0; i < cat.GetNumFiles(); i++)
1 cycrow 192
	{
193
		SInCatFile *f = cat.GetFile(i);
124 cycrow 194
		Utils::String checkFile = f->sFile.findReplace("\\", "/");
58 cycrow 195
		if ( (checkFile.left(6).Compare("types/") || checkFile.left(2).Compare("t/") || checkFile.left(6 + addonSize).Compare(addonDir + "/types/") || checkFile.left(2 + addonSize).Compare(addonDir + "/t/")) && _validFile(checkFile) )
1 cycrow 196
		{
197
			// extract the file to the temp dir
196 cycrow 198
			Utils::String toFile = CFileIO(temp + L"/" + CFileIO(f->sFile).filename()).fullFilenameStr();
181 cycrow 199
			if (cat.extractFile(f, toFile ))
1 cycrow 200
			{
201
				// now extract the matching file from the game dir
124 cycrow 202
				if ( m_fileSystem.ExtractGameFile(f->sFile, toFile + ".compare") )
1 cycrow 203
				{
124 cycrow 204
					diffFile(toFile + ".compare", toFile, f->sFile);
58 cycrow 205
					CFileIO::Remove(toFile + ".compare");
1 cycrow 206
				}
207
				// make sure we clear up afterwards
58 cycrow 208
				CFileIO::Remove(toFile);
1 cycrow 209
			}
210
		}
211
	}
212
 
213
	return true;
214
}
215
 
58 cycrow 216
SDiffFile *CModDiff::diffFile(const Utils::String &baseFile, const Utils::String &modFile, const Utils::String &fileType)
1 cycrow 217
{
218
	int type = 0;
219
 
220
	SDiffFile *diffFile = new SDiffFile;
221
	diffFile->sFile = fileType;
222
 
223
	// read both files and compare them
224
	CFileIO Base(baseFile);
173 cycrow 225
	std::vector<Utils::String> baseLines;
226
	if(Base.readLines(baseLines))
1 cycrow 227
	{
228
		CFileIO Mod(modFile);
173 cycrow 229
		std::vector<Utils::String> lines;
230
		if(Mod.readLines(lines))
1 cycrow 231
		{
232
			int id = -1;
173 cycrow 233
			std::vector<Utils::String>::iterator node[2];
234
			node[0] = baseLines.begin();
235
			node[1] = lines.begin();
236
			std::vector<Utils::String>::iterator endNode[2];
237
			endNode[0] = baseLines.end();
238
			endNode[1] = lines.end();
1 cycrow 239
 
58 cycrow 240
			Utils::String prev[2];
1 cycrow 241
 
173 cycrow 242
			while (node[0] != endNode[0] || node[1] != endNode[1])
1 cycrow 243
			{
58 cycrow 244
				Utils::String str[2];
1 cycrow 245
 
246
				for ( int i = 0; i < 2; i++ )
247
				{
173 cycrow 248
					while (node[i] != endNode[i])
1 cycrow 249
					{
173 cycrow 250
						Utils::String l = *node[i];
251
						node[i]++;
1 cycrow 252
 
58 cycrow 253
						l.removeFirstSpace();
254
						l.removeChar('\r');
255
						if ( !l.empty() && l.left(1) != "/") {
1 cycrow 256
							str[i] += l;
58 cycrow 257
							if ( _isLineComplete(str[i], fileType, (id == -1) ? true : false) ) 
1 cycrow 258
								break;
259
						}
260
					}
261
				}
262
 
263
				if ( id == -1 )
264
					id = 0;
265
				else
266
				{
267
					// first check for mismatch amount, one of the nodes will be empty
58 cycrow 268
					if ( str[0].empty() && !str[1].empty() ) // mod file has more entries (these must be additions)
1 cycrow 269
					{
270
						SDiffEntryAddition *entry = new SDiffEntryAddition;
271
						entry->iID = id;
272
						entry->sEntry = str[1];
273
						diffFile->m_lEntries.push_back(entry);
274
					}
58 cycrow 275
					else if ( str[1].empty() && !str[0].empty() ) // mod file has less entries (must have removed some)
1 cycrow 276
					{
277
						SDiffEntry *entry = new SDiffEntryRemoval;
278
						entry->iID = id;
279
						diffFile->m_lEntries.push_back(entry);
280
					}
281
					else // we have a line for both, we need to compare them
282
					{
283
						// we migth have multiple entries to add when changed
58 cycrow 284
						if ( str[0].empty() || str[1].empty() ) continue;
285
						_compareLine(str[0], str[1], type, id, diffFile);						
1 cycrow 286
					}
287
 
288
					++id;
289
				}
290
			}
291
		}
292
	}
293
 
58 cycrow 294
	if ( diffFile->m_lEntries.empty() ) {
1 cycrow 295
		delete diffFile;
58 cycrow 296
		return NULL;
297
	}
298
	else {
1 cycrow 299
		m_lFiles.push_back(diffFile);
58 cycrow 300
		return diffFile;
301
	}
1 cycrow 302
}
303
 
58 cycrow 304
int CModDiff::_amountPosition(const Utils::String &fileType)
1 cycrow 305
{
306
	return 2;
307
}
308
 
58 cycrow 309
bool CModDiff::_isLineComplete(const Utils::String &line, const Utils::String &fileType, bool first)
1 cycrow 310
{
311
	if ( first )
312
	{
58 cycrow 313
		if ( line.countToken(";") > _amountPosition(fileType) ) return true;
1 cycrow 314
		return false;
315
	}
316
 
317
	return true;
318
}
319
 
58 cycrow 320
void CModDiff::_compareLine(const Utils::String &line1, const Utils::String &line2, int type, int id, SDiffFile *diffFile)
1 cycrow 321
{
322
	int max1, max2;
58 cycrow 323
	Utils::String *str1 = line1.tokenise(";", &max1);
324
	Utils::String *str2 = line2.tokenise(";", &max2);
1 cycrow 325
 
326
	if ( !str1 || !str2 ) return;
327
 
328
	int max = ((max1 > max2) ? max2 : max1);
329
	for ( int i = 0; i < max; i++ )
330
	{
331
		if ( str1[i] == str2[i] ) continue;
332
		if ( str1[i].Compare(str2[i]) ) continue;
58 cycrow 333
		if ( str1[i].empty() && str2[i].empty() ) continue;
334
		if ( str1[i].length() && str1[i][0] == '\0' && str2[i].length() && str2[i][0] == '\0' ) continue;
1 cycrow 335
		SDiffEntryChange *diff = new SDiffEntryChange;
336
		diff->iID = id;
337
		diff->iPos = i;
338
		diff->sEntry = str2[i];
339
		diff->sFrom = str1[i];
340
		diffFile->m_lEntries.push_back(diff);
341
	}
342
}
343
 
344
void CModDiff::Clean()
345
{
346
	for ( CListNode<SDiffFile> *node = m_lFiles.Front(); node; node = node->next() )
347
	{
348
		node->Data()->m_lEntries.clear();
349
		node->DeleteData();
350
	}
351
	m_lFiles.clear();
352
}
353
 
58 cycrow 354
bool CModDiff::WriteDiff(const Utils::String &file)
1 cycrow 355
{
356
	if ( m_lFiles.empty() ) return false;
357
 
160 cycrow 358
	Utils::CStringList lines;
1 cycrow 359
 
360
	for ( CListNode<SDiffFile> *node = m_lFiles.Front(); node; node = node->next() )
361
	{
160 cycrow 362
		lines.pushBack("$$" + node->Data()->sFile);
1 cycrow 363
		for ( CListNode<SDiffEntry> *node2 = node->Data()->m_lEntries.Front(); node2; node2 = node2->next() )
364
		{
365
			switch(node2->Data()->iType)
366
			{
367
				case DIFFTYPE_ADDITION:
160 cycrow 368
					lines.pushBack("+++:" + Utils::String::Number((long)node2->Data()->iID) + ":" + ((SDiffEntryAddition *)node2->Data())->sEntry);
1 cycrow 369
					break;
370
				case DIFFTYPE_REMOVAL:
160 cycrow 371
					lines.pushBack("---:" + Utils::String::Number((long)node2->Data()->iID));
1 cycrow 372
					break;
373
				case DIFFTYPE_CHANGE:
160 cycrow 374
					lines.pushBack("///:" + Utils::String::Number((long)node2->Data()->iID) + ":" + Utils::String::Number((long)((SDiffEntryChange *)node2->Data())->iPos) + ":" + ((SDiffEntryChange *)node2->Data())->sEntry);
1 cycrow 375
					break;
376
			}
377
		}
378
	}
379
 
380
 
381
	CFileIO File(file);
160 cycrow 382
	return File.writeFile(&lines);
1 cycrow 383
}
384
 
58 cycrow 385
bool CModDiff::ReadDiff(const Utils::String &file)
1 cycrow 386
{
387
	Clean();
388
 
389
	CFileIO File(file);
52 cycrow 390
	if ( !File.exists() ) return false;
1 cycrow 391
 
173 cycrow 392
	std::vector<Utils::String> lines;
393
	if(File.readLines(lines))
1 cycrow 394
	{
395
		SDiffFile *diffFile = NULL;
173 cycrow 396
		for(auto itr = lines.begin(); itr != lines.end(); itr++)
1 cycrow 397
		{
173 cycrow 398
			if (itr->left(2).Compare("$$") )
1 cycrow 399
			{
400
				diffFile = new SDiffFile;
401
				m_lFiles.push_back(diffFile);
173 cycrow 402
				diffFile->sFile = itr->right(-2);
1 cycrow 403
			}
404
			else if ( diffFile )
405
			{
173 cycrow 406
				if ( itr->left(4).Compare("+++:") )
1 cycrow 407
				{
408
					SDiffEntryAddition *addition = new SDiffEntryAddition;
173 cycrow 409
					addition->iID = itr->token(":", 2).toInt();
410
					addition->sEntry = itr->tokens(":", 3);
1 cycrow 411
					diffFile->m_lEntries.push_back(addition);
412
				}
173 cycrow 413
				else if ( itr->left(4).Compare("---:") )
1 cycrow 414
				{
415
					SDiffEntryRemoval *entry = new SDiffEntryRemoval;
173 cycrow 416
					entry->iID = itr->token(":", 2).toInt();
1 cycrow 417
					diffFile->m_lEntries.push_back(entry);
418
				}
173 cycrow 419
				else if (itr->left(4).Compare("///:") )
1 cycrow 420
				{
421
					SDiffEntryChange *entry = new SDiffEntryChange;
173 cycrow 422
					entry->iID = itr->token(":", 2).toInt();
423
					entry->iPos = itr->token(":", 3).toInt();
424
					entry->sEntry = itr->tokens(":", 4);
1 cycrow 425
					diffFile->m_lEntries.push_back(entry);
426
				}
427
			}
428
		}
429
 
430
		return true;
431
	}
432
 
433
	return false;
434
}
435
 
58 cycrow 436
bool CModDiff::ApplyMod(const Utils::String &mod)
1 cycrow 437
{
58 cycrow 438
	return m_fileSystem.addMod(mod);
1 cycrow 439
}
440
 
58 cycrow 441
bool CModDiff::ApplyDiff(const Utils::String &mod)
1 cycrow 442
{
443
	if ( m_lFiles.empty() ) return false;
444
 
58 cycrow 445
	this->ApplyMod(mod);
446
 
1 cycrow 447
	bool ret = false;
448
 
196 cycrow 449
	Utils::WString temp = m_sTempDir.toWString();
125 cycrow 450
	Utils::String addonDir = "";
1 cycrow 451
 
452
	CCatFile cat;
125 cycrow 453
	if ( !CCatFile::Opened(cat.open(mod, addonDir, CATREAD_CATDECRYPT, true)) )
1 cycrow 454
		return false;
455
 
456
	for ( CListNode<SDiffFile> *node = m_lFiles.Front(); node; node = node->next() )
457
	{
458
		// extract the file from the game
459
		SDiffFile *f = node->Data();
460
 
160 cycrow 461
		Utils::CStringList writeLines;
1 cycrow 462
		int id;
160 cycrow 463
		if ( _readGameFile(f->sFile, writeLines, &id) )
1 cycrow 464
		{
465
			// now apply the diff
58 cycrow 466
			this->_adjustFile(f->sFile, f, true);
1 cycrow 467
			for ( CListNode<SDiffEntry> *eNode = f->m_lEntries.Front(); eNode; eNode = eNode->next() )
468
			{
469
				switch ( eNode->Data()->iType )
470
				{
471
					case DIFFTYPE_ADDITION:
160 cycrow 472
						writeLines.pushBack(((SDiffEntryAddition *)eNode->Data())->sEntry);
1 cycrow 473
						break;
474
					case DIFFTYPE_REMOVAL:
160 cycrow 475
						writeLines.removeAt(eNode->Data()->iID);
1 cycrow 476
						break;
477
					case DIFFTYPE_CHANGE:
478
						{
160 cycrow 479
							auto strAt = writeLines.get(eNode->Data()->iID);
1 cycrow 480
							if ( strAt )
160 cycrow 481
								strAt->str = strAt->str.replaceToken(";", ((SDiffEntryChange *)eNode->Data())->iPos, ((SDiffEntryChange *)eNode->Data())->sEntry);
1 cycrow 482
						}
483
						break;
484
				}
485
			}
486
 
487
			// add our comments and info
160 cycrow 488
			writeLines.pushFront(Utils::String((long)id) + ";" + (long)writeLines.size() + ";");
489
			writeLines.pushFront("// Generated by ModDiff (SPK Version: " + Utils::String::FromFloat(GetLibraryVersion(), 2) + ")");
1 cycrow 490
 
491
			// now write the file
196 cycrow 492
			CFileIO WriteFile(temp + L"/" + CFileIO(f->sFile).filename());
160 cycrow 493
			if ( WriteFile.writeFile(&writeLines) )
1 cycrow 494
			{
196 cycrow 495
				if ( cat.appendFile(m_sTempDir + "/" + CFileIO(f->sFile).filenameStr(), f->sFile) )
1 cycrow 496
					ret = true;
58 cycrow 497
				WriteFile.remove();
1 cycrow 498
			}
499
		}
500
	}
501
 
502
	if ( ret )
503
		cat.WriteCatFile();
504
 
505
	return ret;
506
}
507
 
160 cycrow 508
bool CModDiff::_readGameFile(const Utils::String &file, Utils::CStringList &writeLines, int *id)
1 cycrow 509
{
510
	bool ret = false;
511
 
196 cycrow 512
	Utils::String sTo = m_fileSystem.ExtractGameFile(file, m_sTempDir + "/" + CFileIO(file).filenameStr());
58 cycrow 513
	if ( !sTo.empty() ) {
514
		CFileIO File(sTo);
1 cycrow 515
 
160 cycrow 516
		Utils::CStringList *lines = File.readLinesStr();
1 cycrow 517
		if ( lines )
518
		{
519
			int entries = -1;
160 cycrow 520
			for(auto itr = lines->begin(); itr != lines->end(); itr++)
1 cycrow 521
			{
160 cycrow 522
				Utils::String l = (*itr)->str;
523
				l.removeFirstSpace();
524
				if ( l.empty() ) continue;
525
				if ( l.left(1) == "/" ) continue;
1 cycrow 526
 
527
				if ( entries == -1 )
528
				{
160 cycrow 529
					entries = l.token(":", 2).toInt();
1 cycrow 530
					if ( id )
160 cycrow 531
						(*id) = l.token(":", 1).toInt();
1 cycrow 532
				}
533
				else
160 cycrow 534
					writeLines.pushBack(l);
1 cycrow 535
			}
536
			delete lines;
537
			ret = true;
538
		}
58 cycrow 539
		File.close();
52 cycrow 540
		File.remove();
1 cycrow 541
	}
542
 
543
	return ret;
544
}
545
 
546
 
58 cycrow 547
bool CModDiff::_validFile(const Utils::String &file)
1 cycrow 548
{
549
	return CModDiff::CanBeDiffed(file);
550
}
551
 
58 cycrow 552
bool CModDiff::CanBeDiffed(const Utils::String &file)
1 cycrow 553
{
196 cycrow 554
	Utils::WString checkFile = file.toWString();
555
	checkFile = CFileIO(file).dir() + L"/" + CFileIO(file).baseName();
1 cycrow 556
 
557
	// all t files are the same format
196 cycrow 558
	if ( checkFile.left(7).Compare(L"types/T") )
1 cycrow 559
		return true;
560
 
561
	return false;
35 cycrow 562
}