Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
#include "CatFile.h"
2
#include <time.h>
3
#include "File.h"
4
#include "DirIO.h"
65 cycrow 5
#include "logging/Log.h"
1 cycrow 6
 
53 cycrow 7
CCatFile::CCatFile () : m_bCatChanged(false)
1 cycrow 8
{
9
	m_iDataType = CATFILE_NONE;
10
	m_sData = NULL;
11
	m_lSize = 0;
12
	m_bCreate = false;
124 cycrow 13
	_lFiles = new std::vector<SInCatFile *>;
1 cycrow 14
}
15
 
16
CCatFile::~CCatFile ()
17
{
52 cycrow 18
	m_fDatFile.close();
19
	m_fCatFile.close();
53 cycrow 20
 
21
	if ( m_bCatChanged ) {
22
		WriteCatFile ();
23
		m_fCatFile.close();
24
	}
25
 
85 cycrow 26
	_clearFiles();
124 cycrow 27
	delete _lFiles;
85 cycrow 28
 
29
	if ( m_sData ) delete []m_sData;
30
}
31
 
32
void CCatFile::_clearFiles()
33
{
124 cycrow 34
	for(auto itr = _lFiles->begin(); itr != _lFiles->end(); itr++)
1 cycrow 35
	{
124 cycrow 36
		if ((*itr)->sData )
37
			delete [](*itr)->sData;
38
		delete (*itr);
1 cycrow 39
	}
53 cycrow 40
 
124 cycrow 41
	_lFiles->clear();
1 cycrow 42
}
43
 
127 cycrow 44
bool CCatFile::IsAddonDir(const Utils::String &dir)
1 cycrow 45
{
127 cycrow 46
	Utils::String d = dir.findReplace("\\", "/");
125 cycrow 47
	d = d.token("/", 1);
1 cycrow 48
 
127 cycrow 49
	if (d.Compare("types"))
1 cycrow 50
		return true;
127 cycrow 51
	if (d.Compare("scripts"))
1 cycrow 52
		return true;
127 cycrow 53
	if (d.Compare("t"))
54
		return true;
55
	if (d.Compare("mov"))
56
		return true;
57
	if (d.Compare("loadscr"))
58
		return true;
59
	if (d.Compare("l"))
60
		return true;
1 cycrow 61
	if ( d.Compare("maps") )
62
		return true;
63
	if ( d.Compare("director") )
64
		return true;
65
	if ( d.Compare("cutscenes") )
66
		return true;
67
	return false;
68
}
69
 
70
bool CCatFile::Opened(int error, bool allowCreate) 
71
{
72
	if ( error == CATERR_NONE ) return true;
73
	if ( allowCreate && error == CATERR_CREATED ) return true;
74
	return false;
75
}
125 cycrow 76
int CCatFile::open(const Utils::String &sCatfile, const Utils::String &addon, int readtype, bool create)
1 cycrow 77
{
125 cycrow 78
	Utils::String catfile = sCatfile;
51 cycrow 79
 
1 cycrow 80
	m_bCreate = false;
51 cycrow 81
	Utils::String datfile;
82
	if ( !catfile.right(4).Compare(".cat") ) {
1 cycrow 83
		datfile = catfile + ".dat";
84
		catfile += ".cat";
85
	}
51 cycrow 86
	else datfile = catfile.left(-4) + ".dat";
1 cycrow 87
 
51 cycrow 88
	if ( readtype == CATREAD_JUSTCONTENTS ) create = false;
1 cycrow 89
 
90
	// first check if the dat file exists and opens
91
	bool created = false;
51 cycrow 92
	if ( readtype != CATREAD_JUSTCONTENTS ) {
85 cycrow 93
		if ( !CFileIO::Exists(datfile) ) {
51 cycrow 94
			if ( create ) created = true;
95
			else		  return CATERR_NODATFILE;
1 cycrow 96
		}
97
	}
98
 
99
	// now open the cat file to read
82 cycrow 100
	CFileIO File(catfile);
101
	if ( !File.startRead() ) {
51 cycrow 102
		if ( create ) created = true;
103
		else		  return CATERR_NOCATFILE;
1 cycrow 104
	}
105
 
51 cycrow 106
	if ( created ) {
118 cycrow 107
		m_fCatFile.open(catfile);
108
		m_fDatFile.open(datfile);
1 cycrow 109
		m_bCreate = true;
110
		return CATERR_CREATED;
111
	}
112
 
113
	// find the file size
82 cycrow 114
	if ( !File.fileSize() ) {
51 cycrow 115
		File.close();
1 cycrow 116
		return CATERR_FILEEMPTY;
117
	}
118
 
119
	// size must be multiples of 5
82 cycrow 120
	size_t size = File.fileSize() + ((File.fileSize() % 5) ? 5 - (File.fileSize() % 5) : 0);
1 cycrow 121
 
122
	// read cat to buffer
51 cycrow 123
	try {
53 cycrow 124
		if ( m_sData ) delete [] m_sData;
51 cycrow 125
		m_sData = new unsigned char[size + 1];
126
	}
127
	catch (std::exception &e) {
128
		CLog::logf(CLog::Log_IO, 2, "Memory Exception error, unable to alloc enough memory to store file data, %d (%s)", size + 1, e.what());
129
		return CATERR_MALLOC;
130
	}
131
 
1 cycrow 132
	m_lSize = size;
51 cycrow 133
	try {
82 cycrow 134
		File.read(m_sData, m_lSize);
51 cycrow 135
	} catch (std::exception &e) {
136
		CLog::logf(CLog::Log_IO, 3, "CCatFile::Open() unable to read from cat file, %s", e.what());
1 cycrow 137
		RemoveData ();
51 cycrow 138
		File.close();
1 cycrow 139
		return CATERR_READCAT;
140
	}
141
 
51 cycrow 142
	m_sData[size] = 0;
1 cycrow 143
	m_iDataType = CATFILE_READ;
51 cycrow 144
	File.close();
1 cycrow 145
 
51 cycrow 146
	if ( readtype != CATREAD_CAT ) {
147
		if ( !DecryptData () ) return CATERR_DECRYPT;
82 cycrow 148
		m_sData[File.fileSize()] = 0;
85 cycrow 149
		readFiles ();
1 cycrow 150
	}
151
 
125 cycrow 152
	_sAddonDir = addon;
1 cycrow 153
 
118 cycrow 154
	m_fCatFile.open ( catfile );
1 cycrow 155
 
51 cycrow 156
	if ( readtype != CATREAD_JUSTCONTENTS ) {
118 cycrow 157
		m_fDatFile.open ( datfile );
1 cycrow 158
 
159
		// check the file size matches
160
		long compare = 0;
82 cycrow 161
		if ( m_fDatFile.startRead() ) {
162
			compare = m_fDatFile.fileSize();
163
			m_fDatFile.close();
1 cycrow 164
		}
124 cycrow 165
 
166
		SInCatFile *c = _lFiles->back();
167
		if (c && (c->lSize + c->lOffset) != compare ) {
85 cycrow 168
//			return CATERR_MISMATCH;
169
		}
1 cycrow 170
	}
171
 
51 cycrow 172
	if ( readtype >= CATREAD_DAT ) LoadDatFile ();
1 cycrow 173
 
174
	return CATERR_NONE;
175
}
176
 
124 cycrow 177
bool CCatFile::removeFile(const Utils::String &file)
1 cycrow 178
{
124 cycrow 179
	if ( !_sAddonDir.empty() ) {
180
		SInCatFile *f = findData(_sAddonDir + "\\" + file);
1 cycrow 181
		if ( f )
124 cycrow 182
			removeFile(f);
1 cycrow 183
	}
184
	{
124 cycrow 185
		SInCatFile *f = findData("addon\\" + file);
1 cycrow 186
		if ( f )
124 cycrow 187
			removeFile(f);
1 cycrow 188
	}
124 cycrow 189
	SInCatFile *f = findData(file);
1 cycrow 190
	if ( !f )
191
	{
192
		m_iError = CATERR_NOFILE;
193
		return false;
194
	}
195
 
124 cycrow 196
	return removeFile(f);
1 cycrow 197
}
198
 
199
void CCatFile::LoadDatFile ()
200
{
201
	if ( m_fDatFile.NoFile() )
202
		return;
203
 
124 cycrow 204
	if ( m_fDatFile.startRead() ) 
205
	{
206
		for(auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr)
1 cycrow 207
		{
124 cycrow 208
			SInCatFile *c = *itr;
51 cycrow 209
			if ( c->sData )	delete c->sData;
1 cycrow 210
 
51 cycrow 211
			try {
212
				c->sData = new unsigned char[c->lSize + 1];
213
			}
214
			catch (std::exception &e) {
215
				CLog::logf(CLog::Log_IO, 2, "CCatFile::LoadDatFile() unable to malloc data storage: %s, %d (%s)", c->sFile.c_str(), c->lSize, e.what());
216
				continue;
217
			}
218
 
219
			try {
82 cycrow 220
				m_fDatFile.read(c->sData, c->lSize);
51 cycrow 221
			}
222
			catch(std::exception &e) {
223
				CLog::logf(CLog::Log_IO, 2, "CCatFile::LoadDatFile() unable to read file data: %s, %d (%s)", c->sFile.c_str(), c->lSize, e.what());
224
				continue;
225
			}
58 cycrow 226
			c->bDecrypted = false;
51 cycrow 227
			this->DecryptDAT(c);
1 cycrow 228
		}
82 cycrow 229
		m_fDatFile.close();
1 cycrow 230
	}
231
}
232
 
85 cycrow 233
bool CCatFile::readFiles ()
1 cycrow 234
{
235
	size_t offset = 0;
85 cycrow 236
	int max = 0;
1 cycrow 237
 
85 cycrow 238
	Utils::String *lines = Utils::String(m_sData).tokenise("\n", &max);
239
 
240
	_clearFiles();
241
 
242
	if ( lines && max ) {
243
		int start = 1;
244
		_sReadFilename = lines[0];
245
		if ( _sReadFilename.token(" ", -1).isNumber() ) {
246
			_sReadFilename.clear();
247
			start = 0;
248
		}
249
 
250
		for(int i = start; i < max; i++) {
251
			Utils::String l = lines[i];
252
 
253
			SInCatFile *catfile = new SInCatFile;
254
 
255
			catfile->lSize = static_cast<size_t>(l.token(" ", -1).toLong());
256
			catfile->sFile = l.tokens(" ", 1, -2);
257
			catfile->lOffset = offset;
258
			catfile->sData = 0;
259
 
260
			offset += catfile->lSize;
261
 
124 cycrow 262
			_lFiles->push_back(catfile);
85 cycrow 263
		}
264
	}
265
 
266
	CLEANSPLIT(lines, max);
267
/*
1 cycrow 268
	unsigned char *data = m_sData;
269
	int spacePos = -1;
53 cycrow 270
	while ( m_sData[num] != '\0' ) {
271
		if ( m_sData[num] == '\n' ) {
1 cycrow 272
			m_sData[num] = 0;
273
			if ( spacePos != -1 )
274
			{
181 cycrow 275
				Utils::String file;
1 cycrow 276
				int size = 0;
277
 
278
				m_sData[spacePos] = '\0';
279
				file = (char *)data;
280
				data = (m_sData + (spacePos + 1));
181 cycrow 281
				if ( !Utils::String((char *)data).isNumber() )
1 cycrow 282
					size = 0;
283
				else
284
					size = atoi((const char *)data);
285
 
286
				if ( size )
287
				{
288
					SInCatFile *catfile = new SInCatFile;
289
 
290
					catfile->lSize = size;
291
					catfile->sFile = file;
292
					catfile->lOffset = offset;
293
					catfile->sData = 0;
294
 
295
					offset += catfile->lSize;
296
 
297
					m_lFiles.push_back ( catfile );
298
				}
299
			}
300
			data = (m_sData + (num + 1));
301
			spacePos = -1;
302
		}
303
		else if ( m_sData[num] == ' ' )
304
			spacePos = num;
305
		++num;
306
	}
85 cycrow 307
*/
1 cycrow 308
	return true;
309
}
310
 
311
bool CCatFile::DecryptData ( unsigned char *data, size_t size )
312
{
313
	unsigned char cl=0xDB, dh=0xDC, dl=0xDD, ah=0xDE, ch=0xDF, al;
314
	unsigned char *ptr = data, *end = data + size;
315
	for ( ptr = data; ptr < end; ptr += 5)
316
	{
317
		al=ch;
318
		ch+=5;
319
		*(ptr + 4) ^= al;
320
		al=ah;
321
		ah+=5;
322
		*(ptr + 3) ^= al;
323
		al=dl;
324
		dl+=5;
325
		*(ptr + 2) ^= al;
326
		al=dh;
327
		dh+=5;
328
		*(ptr + 1) ^= al;
329
		al=cl;
330
		cl+=5;
331
		*(ptr + 0) ^= al;
332
	}
333
 
334
	return true;
335
}
336
 
337
bool CCatFile::DecryptData ()
338
{
51 cycrow 339
	if ( !DecryptData ( m_sData, m_lSize ) ) return false;
1 cycrow 340
 
341
	m_iDataType = CATERR_DECRYPT;
342
 
343
	return true;
344
}
345
 
346
void CCatFile::RemoveData ()
347
{
53 cycrow 348
	delete m_sData;
1 cycrow 349
	m_sData = NULL;
350
	m_iDataType = CATFILE_NONE;
351
	m_lSize = 0;
352
}
353
 
181 cycrow 354
bool CCatFile::readFileToData(const Utils::String &filename)
1 cycrow 355
{
181 cycrow 356
	SInCatFile *c = findData(filename);
357
	return readFileToData(c);
1 cycrow 358
}
359
 
181 cycrow 360
bool CCatFile::readFileToData(SInCatFile *c)
1 cycrow 361
{
41 cycrow 362
	if ( !c ) return false;
1 cycrow 363
	size_t size = 0;
53 cycrow 364
	if ( !c->sData ) c->sData = readData ( c, &size );
41 cycrow 365
	if ( c->sData )	return true;
1 cycrow 366
	return false;
367
}
368
 
181 cycrow 369
unsigned char *CCatFile::readData(SInCatFile *c, size_t *size)
1 cycrow 370
{
371
	*size = c->lSize;
372
 
53 cycrow 373
	if ( !c->sData ) {
374
		if ( m_fDatFile.startRead() ) {
375
			m_fDatFile.seek(c->lOffset);
376
			c->sData = m_fDatFile.read(c->lSize);
58 cycrow 377
			c->bDecrypted = false;
53 cycrow 378
			m_fDatFile.close();
51 cycrow 379
 
53 cycrow 380
			if ( !c->sData ) (*size) = 0;
381
			else {
382
				c->sData[c->lSize] = '\0';
58 cycrow 383
				DecryptDAT(c);
53 cycrow 384
			}
51 cycrow 385
		}
1 cycrow 386
	}
387
 
53 cycrow 388
	return c->sData;
1 cycrow 389
}
390
 
41 cycrow 391
void CCatFile::DecryptDAT(SInCatFile *pFile) 
392
{
393
	if ( pFile->bDecrypted ) return;
394
	pFile->bDecrypted = true;
395
	this->DecryptDAT(pFile->sData, pFile->lSize);
396
}
1 cycrow 397
void CCatFile::DecryptDAT(unsigned char *buffer, size_t size)
398
{
399
	for(unsigned char *pos=buffer, *end=buffer + size; pos < end; pos++){
400
		*pos^=0x33;
401
	}
402
}
181 cycrow 403
unsigned char *CCatFile::readData(const Utils::String &filename, size_t *size)
1 cycrow 404
{
405
	*size = 0;
406
 
53 cycrow 407
	if ( !m_fDatFile.NoFile() ) {
181 cycrow 408
		SInCatFile *c = findData(filename);
53 cycrow 409
		if ( c ) return readData ( c, size );
1 cycrow 410
	}
411
 
412
	return NULL;
413
}
414
 
41 cycrow 415
unsigned char *CCatFile::UnpackFile ( SInCatFile *c, size_t *size)
1 cycrow 416
{
417
	*size = 0;
418
	if ( !c )
419
		return NULL;
420
 
41 cycrow 421
	this->DecryptDAT(c);
1 cycrow 422
 
41 cycrow 423
	int iFiletype = this->_checkFiletype(c->sData, 3);
424
 
425
	// plain file
426
	if ( iFiletype == FILETYPE_PLAIN ) {
427
		*size = c->lSize;
428
		return c->sData;
429
	}
430
 
431
	//otherwise unpack it
432
 
433
//	if ( IsDataPCK ( (const unsigned char *)c->sData, c->lSize ) || forcepck )
434
	/*int iOffset = 0;
435
	if ( iFiletype == FILETYPE_PCK ) {
436
		iOffset = 1;
437
		for(size_t i=0; i < c->lSize; i++){
438
			c->sData[i] ^= magic;
439
		}
440
	}
441
 
442
 
443
	return UnPCKData ( c->sData + iOffset, c->lSize - iOffset, size );*/
96 cycrow 444
	unsigned char *data = UnPCKData(c->sData, c->lSize, size, false);
445
	if ( !data ) data = UnPCKData(c->sData, c->lSize, size, true);
446
	return data;
1 cycrow 447
}
448
 
124 cycrow 449
bool CCatFile::removeFile(SInCatFile *f)
1 cycrow 450
{
124 cycrow 451
	if ( (m_bCreate) || (_lFiles->empty()) )
1 cycrow 452
		return false;
453
 
454
	if ( !f )
455
		return false;
456
 
457
	int err = m_fDatFile.TruncateFile ( f->lOffset, f->lSize );
458
	if ( err == FILEERR_TOSMALL )
459
	{
460
		if ( (int)m_fDatFile.GetFilesize() > this->GetEndOffset() )
461
			m_fDatFile.TruncateFile( this->GetEndOffset(), m_fDatFile.GetFilesize() - this->GetEndOffset() );
462
	}
463
	else if ( err != FILEERR_NONE )
464
		return false;
465
 
16 cycrow 466
	// adjust the file positions
40 cycrow 467
	int iOffset = -1;
124 cycrow 468
	for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr)
469
	{
470
		SInCatFile *c = *itr;
471
		if (c == f) {
472
			iOffset = c->lOffset;
40 cycrow 473
		}
474
		else if ( iOffset >= 0 ) {
124 cycrow 475
			c->lOffset = iOffset;
476
			iOffset += c->lSize;
16 cycrow 477
		}
478
	}
479
 
1 cycrow 480
	// now just write the new cat file
124 cycrow 481
	auto findItr = std::find(_lFiles->begin(), _lFiles->end(), f);
482
	if (findItr != _lFiles->end())
483
		_lFiles->erase(findItr);
53 cycrow 484
	m_bCatChanged = true;
1 cycrow 485
 
486
	return true;
487
}
488
 
489
bool CCatFile::WriteCatFile ()
490
{
124 cycrow 491
	if ( (m_bCreate) && (_lFiles->empty()) ) return false;
1 cycrow 492
 
85 cycrow 493
	Utils::String cat = m_fDatFile.filename() + "\n";
124 cycrow 494
	for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr)
495
	{
496
		SInCatFile *c = *itr;
497
		if ( !c ) continue;
498
		if ( c->sFile.empty() ) continue;
499
		Utils::String str = c->sFile;
500
		cat += str.findReplace("/", "\\").findReplace("\\\\", "\\") + " " + (long)c->lSize + "\n";
1 cycrow 501
	}
502
 
53 cycrow 503
	if ( !cat.length() ) return false;
1 cycrow 504
 
53 cycrow 505
	// make sure the len is in multiples of 5, otherwise decryptData could cause heap problems
506
	size_t len = cat.length() + ((cat.length() % 5) ? 5 - (cat.length() % 5) : 0);
1 cycrow 507
 
53 cycrow 508
	bool ret = false;
509
	try {
510
		unsigned char *data = new unsigned char[len + 1];
511
		memcpy(data, cat.c_str(), cat.length() * sizeof(unsigned char));
512
		for ( size_t i = len; i >= cat.length(); i-- ) data[i] = '\0';
513
		this->DecryptData(data, len);
1 cycrow 514
 
53 cycrow 515
		bool ret = m_fCatFile.write(data, cat.length());
516
		delete []data;
517
	}
518
	catch(std::exception &e) {
519
		CLog::logf(CLog::Log_IO, 2, "CCatFile::WriteCatFile() unable to malloc, %d (%s)", len + 1, e.what());
520
		return false;
521
	}
1 cycrow 522
 
53 cycrow 523
	m_fCatFile.close();
524
	m_bCatChanged = false;
525
	return ret;
1 cycrow 526
}
527
 
124 cycrow 528
std::vector<SInCatFile *> *CCatFile::GetFiles() const
1 cycrow 529
{
124 cycrow 530
	return _lFiles;
531
}
1 cycrow 532
 
124 cycrow 533
bool CCatFile::checkExtensionPck(const Utils::String &filename) const
534
{	
535
	Utils::String ext = CFileIO(filename).extension().lower();
1 cycrow 536
	if ( ext == "xml" )
537
		return true;
538
	else if ( ext == "txt" )
539
		return true;
540
	else if ( ext == "bob" )
541
		return true;
542
	else if ( ext == "bod" )
543
		return true;
544
 
545
	return false;
546
}
547
 
58 cycrow 548
bool CCatFile::CheckPackedExtension(const Utils::String &sFilename)
1 cycrow 549
{
58 cycrow 550
	Utils::String ext = CFileIO(sFilename).extension().lower();
1 cycrow 551
 
552
	if ( ext == "pck" )
553
		return true;
554
	else if ( ext == "pbb" )
555
		return true;
556
	else if ( ext == "pbd" )
557
		return true;
558
 
559
	return false;
560
}
561
 
124 cycrow 562
Utils::String CCatFile::PckChangeExtension(const Utils::String &f)
1 cycrow 563
{
564
	CFileIO fo ( f );
119 cycrow 565
	Utils::String ext = fo.extension ().lower();
1 cycrow 566
	if ( ext == "txt" )
124 cycrow 567
		return fo.changeFileExtension("pck");
1 cycrow 568
	else if ( ext == "xml" )
124 cycrow 569
		return fo.changeFileExtension("pck");
1 cycrow 570
	else if ( ext == "bob" )
124 cycrow 571
		return fo.changeFileExtension("pbb");
1 cycrow 572
	else if ( ext == "bod" )
124 cycrow 573
		return fo.changeFileExtension("pbd");
1 cycrow 574
 
575
	return f;
576
}
577
 
181 cycrow 578
bool CCatFile::appendFile(const Utils::String &filename, const Utils::String &sTo, bool pck, bool bXor, Utils::String *sChangeTo)
1 cycrow 579
{
111 cycrow 580
	CLog::logf(CLog::Log_IO, 1, "CCatFile::AppendFile() Adding file, %s, into cat file, %s::%s [PCK:%s XOR:%s]", filename.c_str(), this->m_fCatFile.filename().c_str(), sTo.c_str(), (pck) ? "Yes" : "No", (bXor) ? "Yes" : "No");
52 cycrow 581
 
181 cycrow 582
	if ( filename.isin ( "::" ) ) return writeFromCat(filename.token("::", 1), filename.token("::", 2));
53 cycrow 583
	if ( (!m_bCreate) && (!m_fDatFile.exists ()) ) {
102 cycrow 584
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() Cat File: %s, doesn't exist, quitting...", m_fCatFile.fullFilename().c_str());
1 cycrow 585
		return false;
52 cycrow 586
	}
124 cycrow 587
	Utils::String to = sTo;
588
	if ( !_sAddonDir.empty() && CCatFile::IsAddonDir(to) ) {
589
		CLog::logf(CLog::Log_IO, 3, "CCatFile::AppendFile() changing destination to included addon fir, %s => %s", to, _sAddonDir + "/" + to);
590
		to = _sAddonDir + "\\" + to;
1 cycrow 591
	}
592
 
42 cycrow 593
	// change the file extension and remove the file again
124 cycrow 594
	if ( pck && checkExtensionPck(filename) ) {
595
		CLog::logf(CLog::Log_IO, 3, "CCatFile::AppendFile() changing file extension for packed file, %s => %s", to.c_str(), PckChangeExtension(to).c_str());
52 cycrow 596
		to = PckChangeExtension(to);
1 cycrow 597
	}
124 cycrow 598
	if ( sChangeTo ) *sChangeTo = to;
1 cycrow 599
 
124 cycrow 600
	if ( !_lFiles->empty() ) {
181 cycrow 601
		SInCatFile *checkf = findData(to);
42 cycrow 602
		if ( checkf ) {
124 cycrow 603
			CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() removing existing filechanging file extension for packed file, %s => %s", to.c_str(), PckChangeExtension(to).c_str());
604
			if ( !removeFile(checkf) ) {
52 cycrow 605
				CLog::logf(CLog::Log_IO, 1, "CCatFile::AppendFile() unable to remove existing file, quitting...");
606
				return false;
607
			}
42 cycrow 608
		}
609
	}
610
 
1 cycrow 611
	bool append = false;
612
 
613
	SInCatFile *f = new SInCatFile;
614
	f->sData = 0;
615
	f->lOffset = this->GetEndOffset();
85 cycrow 616
 
1 cycrow 617
	bool dofile = true;
618
 
124 cycrow 619
	if ( _lFiles->empty() )	{
52 cycrow 620
		CLog::logf(CLog::Log_IO, 3, "CCatFile::AppendFile() no existing files found, wipeing the existing dat file");
1 cycrow 621
		m_fDatFile.WipeFile();
52 cycrow 622
	}
1 cycrow 623
 
52 cycrow 624
	CFileIO File(filename);
625
	if ( !File.startRead() ) {
626
		CLog::logf(CLog::Log_IO, 3, "CCatFile::AppendFile() unable to open file, %s, for reading", filename.c_str());
627
		return false;
628
	}
629
 
630
	CLog::logf(CLog::Log_IO, 3, "CCatFile::AppendFile() reading file data, %s:%d", filename.c_str(), File.fileSize());
631
	unsigned char *data = File.readAll();
632
	File.close();
1 cycrow 633
 
52 cycrow 634
	// check if we need to pack the file
635
	int iFileType = this->_checkFiletype(data, 3);
636
	CLog::logf(CLog::Log_IO, 3, "CCatFile::AppendFile() preparing to append file data, Type=%d", iFileType);
124 cycrow 637
	if ( iFileType == FILETYPE_PLAIN && CheckPackedExtension(to) ) {
52 cycrow 638
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() plain text file needs to packed");
639
		size_t newsize = 0;
640
		unsigned char *newdata = PCKData(data, File.fileSize(), &newsize, bXor);
641
		CLog::logf(CLog::Log_IO, 1, "CCatFile::AppendFile() file has been packed, %d => %d", File.fileSize(), newsize);
1 cycrow 642
 
52 cycrow 643
		f->lSize = newsize;
644
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() Decrypting data");
645
		this->DecryptDAT(newdata, f->lSize);
646
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() appending data to Dat file, Offset:%d", f->lOffset);
647
		append = m_fDatFile.AppendDataToPos ( (const char *)newdata, newsize, f->lOffset );
1 cycrow 648
 
52 cycrow 649
		delete [] newdata;
1 cycrow 650
	}
52 cycrow 651
	else  {
652
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() Decrypting data");
653
		this->DecryptDAT(data, File.fileSize());
654
		f->lSize = File.fileSize();
655
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() appending data to Dat file, Offset:%d", f->lOffset);
656
		append = m_fDatFile.AppendDataToPos ( (const char *)data, f->lSize, f->lOffset );
657
	}
1 cycrow 658
 
52 cycrow 659
	CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() cleaning up memory");
660
	delete [] data;
661
 
53 cycrow 662
	m_fDatFile.close();
663
 
52 cycrow 664
	if ( append ) {
665
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() append complete, adding file into cat list");
1 cycrow 666
		m_bCreate = false;
667
		f->sFile = to;
124 cycrow 668
		_lFiles->push_back(f);
52 cycrow 669
		CLog::logf(CLog::Log_IO, 3, "CCatFile::AppendFile() writing the new cat file");
53 cycrow 670
		m_bCatChanged = true;
1 cycrow 671
	}
52 cycrow 672
	else {
673
		CLog::logf(CLog::Log_IO, 2, "CCatFile::AppendFile() appending failed, cleaning up file data");
1 cycrow 674
		delete f;
52 cycrow 675
	}
1 cycrow 676
 
53 cycrow 677
	CLog::logf(CLog::Log_IO, 4, "CCatFile::AppendFile() function complete");
678
 
679
	return append;
1 cycrow 680
}
681
 
181 cycrow 682
bool CCatFile::addData(const Utils::String &catfile, unsigned char *data, size_t size, const Utils::String &to, bool pck, bool create)
1 cycrow 683
{
181 cycrow 684
	int err = open(catfile, "", CATREAD_CATDECRYPT, create);
1 cycrow 685
	if ( (err != CATERR_NONE) && (err != CATERR_CREATED) )
686
		return false;
687
 
181 cycrow 688
	return appendData(data, size, to, pck);
1 cycrow 689
}
690
 
691
int CCatFile::GetEndOffset()
692
{
124 cycrow 693
	if ( _lFiles->empty() )
1 cycrow 694
		return 0;
84 cycrow 695
	else {
124 cycrow 696
		return _lFiles->back()->lOffset + _lFiles->back()->lSize;
84 cycrow 697
	}
1 cycrow 698
}
699
 
124 cycrow 700
size_t CCatFile::GetNumFiles() const 
701
{ 
702
	return _lFiles->size(); 
703
}
1 cycrow 704
 
124 cycrow 705
SInCatFile *CCatFile::GetFile(unsigned int num) const 
706
{ 
707
	return (num >= 0 && num < _lFiles->size()) ? _lFiles->at(num) : NULL; 
708
}
709
 
181 cycrow 710
bool CCatFile::appendData(unsigned char *data, size_t size, const Utils::String &aTo, bool pck, bool bXor)
1 cycrow 711
{
52 cycrow 712
	if ( (!m_bCreate) && (!m_fCatFile.exists ()) )
1 cycrow 713
		return false;
714
 
715
	if ( (size <= 0) || (!data) )
716
		return false;
717
 
181 cycrow 718
	Utils::String to = aTo;
124 cycrow 719
 
1 cycrow 720
	// then check if the file already exists
124 cycrow 721
	if ( !_lFiles->empty() )
1 cycrow 722
	{
181 cycrow 723
		SInCatFile *f = findData(to);
1 cycrow 724
		if ( f )
725
		{
124 cycrow 726
			if (!removeFile ( f ))
1 cycrow 727
				return false;
728
		}
729
	}
730
 
731
	bool append = false;
732
 
124 cycrow 733
	if (_lFiles->empty())
1 cycrow 734
		m_fDatFile.WipeFile();
735
 
736
	SInCatFile *f = new SInCatFile;
737
	f->sData = 0;
124 cycrow 738
	if (_lFiles->empty())
1 cycrow 739
		f->lOffset = 0;
740
	else
741
		f->lOffset = m_fDatFile.GetFilesize();
742
 
743
	// if file extension is packed but not the file, then pack it, "pck" forces it to be packed unless it already is
744
 
745
	f->lSize = size;
124 cycrow 746
	if ( (((pck) && (checkExtensionPck (to))) || ((CheckPackedExtension (to)))) && (!IsDataPCK ( data, size )) )
1 cycrow 747
	{
748
		to = PckChangeExtension ( to );
749
 
124 cycrow 750
		if (!_lFiles->empty())
1 cycrow 751
		{
181 cycrow 752
			SInCatFile *f = findData(to);
1 cycrow 753
			if ( f )
754
			{
124 cycrow 755
				if (!removeFile(f))
1 cycrow 756
					return false;
757
			}
758
		}
759
		size_t newsize = 0;
760
		unsigned char *d = PCKData ( data, size, &newsize, bXor );
761
 
762
		f->lSize = newsize;
763
		this->DecryptDAT(d, newsize);
764
		append = m_fDatFile.AppendDataToPos ( (const char *)d, newsize, f->lOffset );
765
 
766
		delete [] d;
767
	}
768
	else {
769
		this->DecryptDAT(data, size);
770
		append = m_fDatFile.AppendDataToPos ( (const char *)data, size, f->lOffset );
771
	}
772
 
58 cycrow 773
	m_fDatFile.close();
774
	if ( append ) {
1 cycrow 775
		m_bCreate = false;
776
		f->sFile = to;
124 cycrow 777
		_lFiles->push_back(f);
53 cycrow 778
		m_bCatChanged = true;
1 cycrow 779
	}
780
	else
781
		delete f;
782
 
783
	return true;
784
}
785
 
124 cycrow 786
Utils::String CCatFile::RenameFileExtension(SInCatFile *f)
1 cycrow 787
{
124 cycrow 788
	CFileIO fo(f->sFile);
125 cycrow 789
	Utils::String ext = fo.extension().lower();
1 cycrow 790
	if ( ext == "pck" )
791
	{
124 cycrow 792
		Utils::String firstDir = f->sFile.findReplace("/", "\\").token("\\", 1).lower();
1 cycrow 793
 
794
		if ( firstDir == "t" )
124 cycrow 795
			return fo.changeFileExtension ( "xml" );
1 cycrow 796
		else if ( firstDir == "director" )
124 cycrow 797
			return fo.changeFileExtension ( "xml" );
798
		return fo.changeFileExtension ( "txt" );
1 cycrow 799
	}
800
	else if ( ext == "pbb" )
124 cycrow 801
		return fo.changeFileExtension ( "bob" );
1 cycrow 802
	else if ( ext == "pbd" )
124 cycrow 803
		return fo.changeFileExtension ( "bod" );
1 cycrow 804
	return f->sFile;
805
}
806
 
181 cycrow 807
void CCatFile::findFiles(Utils::CStringList &files, const Utils::String &filemask) const
1 cycrow 808
{
124 cycrow 809
	if (_lFiles->empty())
1 cycrow 810
		return;
811
 
124 cycrow 812
	for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr)
1 cycrow 813
	{
181 cycrow 814
		if (filemask.match((*itr)->sFile))
815
			files.pushBack((*itr)->sFile);
1 cycrow 816
	}
817
}
818
 
181 cycrow 819
bool CCatFile::extractAll(const Utils::String &dir)
1 cycrow 820
{
124 cycrow 821
	if (_lFiles->empty())
1 cycrow 822
		return false;
823
 
124 cycrow 824
	for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr)
1 cycrow 825
	{
181 cycrow 826
		if ( !extractFile(*itr, dir, true) )
1 cycrow 827
			return false;
828
	}
829
 
830
	return true;
831
}
181 cycrow 832
bool CCatFile::extractFile(const Utils::String &filename, const Utils::String &to, bool preserve)
1 cycrow 833
{
124 cycrow 834
	if (_lFiles->empty())
1 cycrow 835
		return false;
836
 
837
	// check if file exists
124 cycrow 838
	if ( !_sAddonDir.empty() ) {
181 cycrow 839
		SInCatFile *f = findData(_sAddonDir + "\\" + filename);
1 cycrow 840
		if ( f )
181 cycrow 841
			return extractFile(f, to, preserve);
1 cycrow 842
	}
843
	{
181 cycrow 844
		SInCatFile *f = findData("addon\\" + filename);
1 cycrow 845
		if ( f )
181 cycrow 846
			return extractFile(f, to, preserve);
1 cycrow 847
	}
848
 
181 cycrow 849
	SInCatFile *f = findData(filename);
1 cycrow 850
	if ( !f )
851
	{
852
		m_iError = CATERR_NOFILE;
853
		return false;
854
	}
855
 
181 cycrow 856
	return extractFile(f, to, preserve);
1 cycrow 857
}
858
 
41 cycrow 859
int CCatFile::_checkFiletype(const unsigned char *pBuffer, int iSize)
860
{
861
	if(iSize >= 3) {
862
		unsigned char magic = pBuffer[0] ^ 0xC8;
863
		if( (pBuffer[1] ^ magic) == 0x1F && (pBuffer[2] ^ magic) == 0x8B) {
864
			return FILETYPE_PCK;
865
		}
866
	}
867
 
868
	if ( iSize >= 2 && (pBuffer[0] == 0x1F && pBuffer[1] == 0x8B) ) {
869
		return FILETYPE_DEFLATE;
870
	}	
871
 
872
	return FILETYPE_PLAIN;
873
}
874
 
181 cycrow 875
bool CCatFile::extractFile(SInCatFile* f, const Utils::String &to, bool preserve)
1 cycrow 876
{
877
	unsigned char *data = 0;
878
	size_t size = 0;
879
 
880
	// load the data from file
181 cycrow 881
	readFileToData(f);
1 cycrow 882
 
41 cycrow 883
	data = this->UnpackFile(f, &size);
52 cycrow 884
	if ( !data ) {
1 cycrow 885
		m_iError = CATERR_CANTREAD;
886
		return false;
887
	}
888
 
889
	CFileIO fo(CCatFile::RenameFileExtension(f));
890
	// check for a file name
181 cycrow 891
	Utils::String checkFile = to;
892
	Utils::String todir, tofile = to;
893
	if ( checkFile.containsAny("\\/") )
1 cycrow 894
	{
181 cycrow 895
		checkFile = checkFile.findReplace ( "\\", "/" );
896
		checkFile = checkFile.findReplace ( "//", "/" );
897
		tofile = checkFile.token("/", checkFile.countToken("/"));
1 cycrow 898
 
181 cycrow 899
		if ( !checkFile.contains(".") || preserve )
1 cycrow 900
		{
111 cycrow 901
			tofile = fo.filename();
1 cycrow 902
			todir = checkFile;
903
		}
904
		else
905
		{
102 cycrow 906
			todir = CFileIO(checkFile).dir();
907
			tofile = CFileIO(checkFile).filename();
1 cycrow 908
		}
909
	}
910
 
181 cycrow 911
	if ( tofile.empty() )
1 cycrow 912
	{
181 cycrow 913
		if ( !tofile.empty() )
1 cycrow 914
			tofile += "/";
111 cycrow 915
		tofile += fo.filename();
102 cycrow 916
		todir = CFileIO(tofile).dir();
917
		tofile = CFileIO(tofile).filename();
1 cycrow 918
	}
919
 
920
	if ( preserve )
921
	{
181 cycrow 922
		if ( !fo.dir().Compare(todir.right(- (int)fo.dir().length())) )
1 cycrow 923
		{
181 cycrow 924
			if ( !todir.empty() && todir.right(1) != "/" )
1 cycrow 925
				todir += "/";
102 cycrow 926
			todir += fo.dir();
1 cycrow 927
		}
928
	}
929
 
181 cycrow 930
	if ( tofile.empty() )
111 cycrow 931
		tofile = fo.filename();
1 cycrow 932
 
52 cycrow 933
	bool bWritten = false;
934
 
1 cycrow 935
	// create the directory to extract to
181 cycrow 936
	if ( !todir.empty() && !CDirIO(todir).create() )
1 cycrow 937
		m_iError = CATERR_CANTCREATEDIR;
938
	else
939
	{
181 cycrow 940
		Utils::String file = todir;
941
		if ( !file.empty() )
1 cycrow 942
			file += "/";
943
		file += tofile;
181 cycrow 944
		file = file.findReplace("/", "\\");
945
		file = file.findReplace("\\\\", "\\");
1 cycrow 946
 
52 cycrow 947
		CFileIO File(file.c_str());
948
		if ( !File.startWrite() ) m_iError = CATERR_INVALIDDEST;
949
		else bWritten = File.write(data, size);
1 cycrow 950
	}
951
 
952
	delete data;
953
	f->sData = 0;
954
 
124 cycrow 955
	if ( bWritten ) this->clearError();
52 cycrow 956
 
957
	return bWritten;
1 cycrow 958
}
959
 
85 cycrow 960
const Utils::String &CCatFile::internalDatFilename() const
961
{
962
	return _sReadFilename;
963
}
964
 
124 cycrow 965
Utils::String CCatFile::getErrorString () const
1 cycrow 966
{
967
	switch ( m_iError )
968
	{
969
		case CATERR_NONE:
124 cycrow 970
			return Utils::String::Null();
1 cycrow 971
		case CATERR_NODATFILE:
972
			return "Unable to open Dat file";
973
		case CATERR_NOCATFILE:
974
			return "Unable to open Cat file";
975
		case CATERR_FILEEMPTY:
976
			return "Cat file is empty";
977
		case CATERR_READCAT:
978
			return "Unable to read from cat file";
979
		case CATERR_DECRYPT:
980
			return "Unable to decrypt cat file";
981
		case CATERR_MISMATCH:
982
			return "File size mismatch with Dat file";
983
		case CATERR_NOFILE:
984
			return "Unable to find file in archive";
985
		case CATERR_CANTREAD:
986
			return "Unable to read file in archive";
987
		case CATERR_CANTCREATEDIR:
988
			return "Unable to create destiantion directory";
989
		case CATERR_INVALIDDEST:
990
			return "Unable to write to destiantion file";
991
	}
992
 
993
	return "Invalid";
994
}
995
 
996
 
997
unsigned char *CompressPCKData ( unsigned char *buffer, size_t size, size_t *retsize, time_t mtime )
998
{
999
	size_t newsize = (size * 2) + 20;
1000
	unsigned char *data = (unsigned char *)malloc ( sizeof(unsigned char) * newsize );
1001
 
1002
	z_stream zs;
1003
	char flags=0;
1004
 
1005
//	error(0);
1006
 
1007
	unsigned char *d = data;
1008
//	if(m_pszComment && strlen(m_pszComment) > 0) flags|=GZ_F_COMMENT;
1009
//	if(m_pszFileName && strlen(m_pszFileName) > 0) flags|=GZ_F_FILENAME;
1010
 
1011
	int pos = PCKHEADERSIZE;
1012
	*d = 0x1F; 		d++;
1013
	*d = 0x8B; 		d++;
1014
	*d = 8;			d++;
1015
	*d = flags; 	d++;
1016
	memcpy(d, &mtime, sizeof(mtime));
1017
	d += 4;
1018
	*d = 0; 		d++;
1019
	*d = 11; 		d++;
1020
//	if(flags & GZ_F_FILENAME) put((const char *)m_pszFileName);
1021
//	if(flags & GZ_F_COMMENT) put((const char *)m_pszComment);
1022
 
1023
	memset(&zs, 0, sizeof(zs));
1024
	zs.next_in=buffer;
1025
	zs.avail_in=(long)size;
1026
 
1027
	int ret;
1028
	unsigned long ubound;
1029
	ret=deflateInit2(&zs, 9, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY);
1030
	if(ret!=Z_OK)
1031
		return false;
1032
 
1033
	ubound=deflateBound(&zs, (unsigned long)size);
1034
	if ( newsize < ubound)
1035
	{
1036
		newsize += ubound;
1037
		data = (unsigned char *)realloc ( data, sizeof(unsigned char) * newsize );
1038
	}
1039
 
1040
 
1041
	zs.next_out=d;
1042
	zs.avail_out=(unsigned int)newsize - pos;
1043
 
1044
	while((ret=deflate(&zs, Z_FINISH))==Z_OK)
1045
	{
1046
		newsize += 1024;
1047
		data = (unsigned char *)realloc ( data, sizeof(unsigned char) * newsize );
1048
		zs.next_out=data + zs.total_out;
1049
		zs.avail_out=(unsigned int)newsize - zs.total_out;
1050
	}
1051
	pos += zs.total_out;
1052
 
1053
	deflateEnd(&zs);
1054
 
1055
	unsigned long crc=crc32(0, NULL, 0);
1056
	crc=crc32(crc, buffer, (unsigned int)size);
1057
 
1058
	int s = sizeof(crc) + sizeof(size);
1059
	if ( newsize < (size_t)(s + pos) )
1060
	{
1061
		newsize += (s + pos) - newsize;
1062
		data = (unsigned char *)realloc ( data, sizeof(unsigned char) * newsize );
1063
	}
1064
 
1065
	memcpy(&data[pos], &crc, sizeof(crc));
1066
	pos += sizeof(crc);
1067
	memcpy(&data[pos], &size, sizeof(size));
1068
	pos += sizeof(size);
1069
 
1070
	newsize = pos;
1071
 
1072
	unsigned char *retdata = NULL;
1073
	if ( ret == Z_STREAM_END )
1074
	{
1075
		*retsize = newsize;
1076
		retdata = new unsigned char[newsize];
1077
		memcpy ( retdata, data, newsize );
1078
	}
1079
	free ( data );
1080
 
1081
	return retdata;
1082
}
1083
 
1084
unsigned char *PCKData ( unsigned char *data, size_t oldsize, size_t *newsize, bool bXor )
1085
{
1086
	unsigned char *newdata = CompressPCKData ( data, oldsize, newsize, time(NULL) );
1087
	if ( !bXor )
1088
		return newdata;
1089
 
1090
	if ( newdata )
1091
	{
1092
		char magic = (char)clock(), m;
1093
		m=magic ^ 0xC8;
1094
 
1095
		unsigned char *ptr = newdata, *end = newdata + *newsize;
1096
		// XOR encryption
1097
		if ( bXor )
1098
		{
1099
			for ( ; ptr < end; ptr++ )
1100
				(*ptr)^=magic;
1101
		}
1102
 
1103
		unsigned char *finalData = new unsigned char[*newsize + 1];
1104
		finalData[0] = m;
1105
		memcpy ( finalData + 1, newdata, *newsize );
1106
		delete [] newdata;
1107
		(*newsize)++;
1108
		return finalData;
1109
	}
1110
 
1111
	return NULL;
1112
}
1113
 
181 cycrow 1114
bool CCatFile::writeFromCat(CCatFile *fcat, const Utils::String &file)
1 cycrow 1115
{
1116
	// now find the file in the cat file
181 cycrow 1117
	SInCatFile *getfile = fcat->findData(file);
1 cycrow 1118
	if ( !getfile )
1119
		return false;
1120
 
1121
	// read the dat from the cat file
1122
	size_t size = 0;
53 cycrow 1123
	unsigned char *data = fcat->readData ( getfile, &size );
1 cycrow 1124
	if ( !data )
1125
		return false;
1126
 
1127
	// now check if it exists in this file
181 cycrow 1128
	removeFile(file);
1 cycrow 1129
 
124 cycrow 1130
	int offset = (_lFiles->empty()) ? 0 : (_lFiles->back()->lOffset + _lFiles->back()->lSize);
1 cycrow 1131
	// now write to the new file
58 cycrow 1132
	if ( getfile->bDecrypted ) this->DecryptDAT(getfile->sData, getfile->lSize);
1133
	getfile->bDecrypted = false;
1134
	if ( !m_fDatFile.AppendDataToPos((const char *)getfile->sData, getfile->lSize, offset) ) return false;
1135
    m_fDatFile.close();
1 cycrow 1136
 
1137
	// finally add to the list
1138
	SInCatFile *f = new SInCatFile;
1139
	f->sData = 0;
124 cycrow 1140
	if (_lFiles->empty())
1 cycrow 1141
		f->lOffset = 0;
1142
	else
124 cycrow 1143
		f->lOffset = _lFiles->back()->lOffset + _lFiles->back()->lSize;
181 cycrow 1144
	f->sFile = file;
1 cycrow 1145
	f->lSize = size;
124 cycrow 1146
	_lFiles->push_back(f);
53 cycrow 1147
	m_bCatChanged = true;
1 cycrow 1148
 
1149
	return true;
1150
}
1151
 
181 cycrow 1152
bool CCatFile::writeFromCat(const Utils::String &catfile, const Utils::String &file)
1 cycrow 1153
{
1154
	CCatFile fcat;
181 cycrow 1155
	if ( fcat.open(catfile, "", CATREAD_CATDECRYPT, false) )
1 cycrow 1156
		return false;
1157
 
181 cycrow 1158
	return this->writeFromCat(&fcat, file);
1 cycrow 1159
}
124 cycrow 1160
SInCatFile *CCatFile::findData(const Utils::String &filename) const
1161
{
1162
	if (_lFiles->empty())
1 cycrow 1163
		return NULL;
1164
 
124 cycrow 1165
	Utils::String check = filename;
1166
	check = check.findReplace("\\", "/");
1167
	for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr)
1 cycrow 1168
	{
124 cycrow 1169
		Utils::String f = (*itr)->sFile;
1170
		f = f.findReplace("\\", "/");
1171
		if (f.Compare(check))
1172
			return *itr;
1 cycrow 1173
	}
1174
	return NULL;
1175
}
1176
 
181 cycrow 1177
bool CCatFile::markRemoveFile(const Utils::String &file)
1 cycrow 1178
{
181 cycrow 1179
	SInCatFile *f = findData(file);
1 cycrow 1180
	if ( !f )
1181
	{
1182
		m_iError = CATERR_NOFILE;
1183
		return false;
1184
	}
1185
 
181 cycrow 1186
	return markRemoveFile(f);
1 cycrow 1187
}
181 cycrow 1188
bool CCatFile::markRemoveFile ( SInCatFile *f )
1 cycrow 1189
{
1190
	f->bDelete = true;
1191
	return true;
1192
}