Subversion Repositories spk

Rev

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