Subversion Repositories spk

Rev

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

Rev Author Line No. Line
1 cycrow 1
// File.cpp: implementation of the C_File class.
2
//
3
//////////////////////////////////////////////////////////////////////
4
 
5
#include "File.h"
6
 
7
#include <time.h>
8
#include <sys/types.h>
9
#include <sys/stat.h>
10
 
11
#ifndef _WIN32
12
#include <unistd.h>
13
#endif
14
 
15
#include <iostream>
16
#include <fstream>
17
 
18
#include "spk.h"
19
 
6 cycrow 20
#include "BaseFile.h"
1 cycrow 21
#include "CatFile.h"
22
#include "DirIO.h"
23
 
24
#include "secure.h"
25
 
26
// LZMA compression
27
#include "lzma/Lzma86Enc.h"
28
#include "lzma/Lzma86Dec.h"
29
 
30
//////////////////////////////////////////////////////////////////////
31
// Construction/Destruction
32
//////////////////////////////////////////////////////////////////////
33
 
34
void CProgressInfoDone::DoingFile ( C_File *file )
35
{
36
	m_iDone = 0;
37
 
38
	if ( !m_bDontDoMax )
39
	{
40
		if ( file->GetData() && file->GetDataSize() )
41
			m_lMaxSize = file->GetDataSize();
42
		else
43
			m_lMaxSize = file->GetSize();
44
	}
45
 
46
	m_pOnFile = file;
47
}
48
 
49
void CProgressInfoDone::DoingPackage ( SMultiSpkFile *file )
50
{
51
	m_iDone = 0;
52
 
53
	if ( !m_bDontDoMax )
54
		m_lMaxSize = file->lSize;
55
 
56
	m_pOnPackage = file;
57
}
58
 
59
int C_File::m_iTempNum = 0;
60
 
61
C_File::C_File()
62
{
63
	m_bDontDeleteData = false;
64
	m_bUsedMalloc = false;
65
	m_sData = NULL;
66
	Reset();
67
}
68
 
69
C_File::C_File ( CyString filename )
70
{
71
	m_bDontDeleteData = false;
72
	m_bUsedMalloc = false;
73
	m_sData = NULL;
74
	Reset ();
75
	SetFilename ( filename );
76
}
77
 
78
C_File::C_File ( const char *filename )
79
{
80
	m_bDontDeleteData = false;
81
	m_bUsedMalloc = false;
82
	m_sData = NULL;
83
	Reset ();
84
	SetFilename ( CyString(filename) );
85
}
86
 
87
C_File::~C_File()
88
{
89
	DeleteData ();
90
	if ( !m_sTmpFile.Empty() )
91
		remove ( m_sTmpFile.c_str() );
92
}
93
 
94
 
95
/*
96
	Func:	GetDirectory()
97
	Return: Directory String
98
	Desc:	Returns the directory the file goes into, based on m_sDir and Filetype
99
*/
100
CyString C_File::GetDirectory ( CBaseFile *file )
101
{
102
	if ( IsFakePatch() )
103
		return "";
104
 
105
	if ( (m_iFileType == FILETYPE_MOD) && (m_sDir == "Patch") )
106
		return "PluginManager/Patch";
107
 
108
	if ( (!m_sDir.Empty()) && (m_iFileType != FILETYPE_README) && m_sDir != "." )
109
	{
110
		CyString dir = m_sDir.FindReplace ( "\\", "/" );
111
		if ( file )
112
		{
113
			dir = dir.FindReplace ( "$scriptname", file->GetNameValidFile() );
114
			dir = dir.FindReplace ( "$scriptauthor", file->GetAuthor() );
115
		}
116
		return dir;
117
	}
118
 
119
	switch ( m_iFileType )
120
	{
121
		case FILETYPE_SCRIPT:
122
			return "Scripts";
123
		case FILETYPE_TEXT:
124
			return "T";
125
		case FILETYPE_README:
126
		{
127
			if ( file )
128
				return CyString("PluginManager/Readme/") + file->GetNameValidFile();
129
			return "PluginManager/Readme";
130
		}
131
		case FILETYPE_MAP:
132
			return "Maps";
133
		case FILETYPE_MOD:
134
//			if ( (file) && (file->IsPatch()) )
135
//				return "Mods/Patch";
136
			return "Mods";
137
		case FILETYPE_UNINSTALL:
138
			return "PluginManager/Uninstall";
139
		case FILETYPE_SOUND:
140
			if ( CFileIO(m_sName).CheckFileExtension("wav") )
141
				return "s";
142
			return "Soundtrack";
143
		case FILETYPE_EXTRA:
144
			return "PluginManager/Extras";
145
		case FILETYPE_SCREEN:
146
			return "loadscr";
147
		case FILETYPE_ADVERT:
148
			return "PluginManager/Graphics";
149
		case FILETYPE_MISSION:
150
			return "Director";
151
	}
152
	return NullString;
153
}
154
 
155
CyString C_File::GetNameDirectory ( CBaseFile *file )
156
{
157
	CyString dir = GetDirectory( file );
158
	if ( !dir.Empty() )
159
		dir += "/";
160
	return CyString(dir + m_sName).FindReplace ( "\\", "/" ).FindReplace( "//", "/");
161
}
162
 
163
/*
164
	Func:	Reset()
165
	Desc:	Resets the file data, clears all data inside
166
			Clears the Data stream
167
*/
168
void C_File::Reset ()
169
{
170
	m_iLastError = SPKERR_NONE;
171
	m_bLoaded = false;
172
	m_iFileType = -1;
173
	m_lSize = 0;
174
	m_iVersion = 0;
175
	m_bSigned = false;
176
	m_iUsed = 0;
177
	m_tTime = 0;
178
	m_lDataSize = m_lUncomprDataSize = 0;
179
	DeleteData ();
180
	m_iDataCompression = 0;
181
	m_bSkip = false;
182
	m_bShared = false;
183
	m_bCompressedToFile = false;
184
	m_bDisabled = false;
185
	m_bUpdatedSignature = false;
186
	m_iPos = -1;
187
	m_iGame = 0;
188
}
189
 
190
bool C_File::UpdateSigned()
191
{
192
	switch ( m_iFileType )
193
	{
194
		// text files, readmes, screenshots can be always considered to be signed
195
		case FILETYPE_TEXT:
196
		case FILETYPE_README:
197
		case FILETYPE_SCREEN:
198
		case FILETYPE_ADVERT:
199
		case FILETYPE_SOUND:
200
		case FILETYPE_BACKUP:
201
			m_bSigned = true;
202
			break;
203
 
204
		// mods, maps are always not signed
205
		case FILETYPE_MOD:
206
		case FILETYPE_MAP:
207
		case FILETYPE_SHIPOTHER:
208
		case FILETYPE_SHIPMODEL:
209
		case FILETYPE_SHIPSCENE:
210
		case FILETYPE_COCKPITSCENE:
211
			m_bSigned = false;
212
			break;
213
 
214
		// extra files are a special case
215
		case FILETYPE_EXTRA:
216
			if ( this->GetDir().Left(6).Compare("extras") )
217
				m_bSigned = true;
218
			else
219
				m_bSigned = false;
220
			break;
221
 
222
		// script files need to check
223
		case FILETYPE_SCRIPT:
224
		case FILETYPE_UNINSTALL:
225
			m_bSigned = this->ReadSignedFile();
226
			break;
227
 
228
		// mission files
229
		case FILETYPE_MISSION:
230
			m_bSigned = false;
231
			break;
232
	}
233
 
234
	return m_bSigned;
235
}
236
 
237
/*
238
	Func:	DeleteData()
239
	Desc:	Clears the data stream, uses free() if created by malloc, otherwise use delete.
240
*/
241
void C_File::DeleteData ()
242
{
243
	if ( m_sData )
244
	{
245
		if ( m_bUsedMalloc )
246
			free ( m_sData );
247
		else
248
			delete [] m_sData;
249
		m_bDontDeleteData = false;
250
		m_sData = NULL;
251
		m_bLoaded = false;
252
		m_lDataSize = 0;
253
	}
254
	m_bUsedMalloc = false;
255
	m_iDataCompression = SPKCOMPRESS_NONE;
256
}
257
 
258
int C_File::GetTextFileID(CyString filename)
259
{
260
	if ( m_iFileType != FILETYPE_TEXT )
261
		return -1;
262
 
263
	if ( filename.Empty() )
264
		filename = m_sName;
265
 
266
	CyString textid;
267
	if ( filename.IsIn("-L") || filename.IsIn("-l") )
268
		textid = filename.GetToken("-", 1, 1);
269
	else
270
		textid = filename.GetToken(".", -1).Right(4);
271
 
43 cycrow 272
	if ( textid.IsNumber() ) return textid.ToInt();
273
	return -1;
1 cycrow 274
}
275
bool C_File::IsAutoTextFile ()
276
{
277
	int textid = GetTextFileID();
278
	if ( textid == -1 ) return false;
279
 
280
	if ( textid <= 3 )
281
		return true;
282
 
283
	// check for original name
284
	if ( !m_sOriginalName.Empty() )
285
	{
286
		textid = GetTextFileID(m_sOriginalName);
287
		if ( textid >= 0 && textid <= 3 )
288
			return true;
289
	}
290
 
291
	return false;
292
}
293
 
294
bool C_File::IsFakePatch ()
295
{
296
	if ( m_iFileType != FILETYPE_MOD )
297
		return false;
298
 
299
	if ( m_sName.GetToken ( 1, '.' ).ToInt() )
300
		return true;
301
 
302
	if ( m_sName.Left (10) == "FakePatch_" )
303
		return true;
304
 
305
	return false;
306
}
307
 
308
/*
309
########################################################################################################################
310
####################################             File Pointer Functions             ####################################
311
########################################################################################################################
312
*/
313
 
314
/*
315
	Func:	SetFilename
316
	Accept:	filename - String for the filename of disk
317
	Desc:	Sets the file pointer
318
			Reads the file size and last modifed time to store in the class
319
			Splits up the filename and dir path
320
*/
321
void C_File::SetFilename ( CyString filename )
322
{
323
	CyString file = filename.FindReplace ( "\\", "/" ).FindReplace ( "//", "/" );
324
	int tok = file.NumToken ( '/' );
325
 
326
	m_sFullDir = file.GetToken ( "/", 1, -1 );
327
	m_sName = file.GetToken ( "/", -1 );
328
	if ( m_sFullDir.Right(2) == "/." )
329
		m_sFullDir = m_sFullDir.Left(-2);
330
 
331
	ReadFileSize ();
332
 
333
	ReadLastModified ();
334
}
335
 
336
 
337
/*
338
	Func:	ReadFromFile
339
	Return:	Boolean - Returns true if read was successfull
340
	Desc:	Reads data from file pointer into data stream
341
			As its read from a file, there will be no compression, so its set to None
342
*/
343
bool C_File::ReadFromFile ()
344
{
345
	return this->ReadFromFile(GetFilePointer().c_str());
346
}
347
 
348
bool C_File::ReadFromFile (CyString filename)
349
{
350
	FILE *id = fopen ( filename.c_str(), "rb" );
351
	if ( !id )
352
	{
353
		m_iLastError = SPKERR_FILEOPEN;
354
		return false;
355
	}
356
 
357
	if ( !m_lSize )
358
	{
359
		fseek ( id, 0, SEEK_END );
360
		m_lSize = ftell ( id );
361
		rewind ( id );
362
	}
363
 
364
	m_iDataCompression = SPKCOMPRESS_NONE;
365
	m_lDataSize = m_lUncomprDataSize = m_lSize;
366
 
367
	DeleteData ();
368
 
369
	m_sData = new unsigned char[m_lSize];
370
	if ( !m_sData ) { fclose ( id ); m_iLastError = SPKERR_MALLOC; return false; }
371
 
372
	fread ( m_sData, sizeof(unsigned char), m_lSize, id );
373
	if ( ferror(id) )
374
	{
375
		m_iLastError = SPKERR_FILEREAD;
376
		DeleteData ();
377
		m_lDataSize = 0;
378
		fclose ( id );
379
		return false;
380
	}
381
 
382
	m_iLastError = SPKERR_NONE;
383
 
384
	struct stat fileStat;
385
	if ( !stat(GetFilePointer().c_str(), &fileStat) )
386
		m_tTime = fileStat.st_atime;
387
 
388
	m_bLoaded = true;
389
 
390
	fclose ( id );
391
 
392
	return true;
393
}
394
 
395
/*
396
	Func:	ReadFromData
397
	Accept:	data - The data stream to read
398
			size - The length of the data stream
399
	Return: Boolean - Return true if successfull
400
	Desc:	Copys data to the data stream in the file
401
			Used when data is already loaded into memory
402
*/
403
bool C_File::ReadFromData ( char *data, long size )
404
{
405
	DeleteData ();
406
 
407
	m_lDataSize = size ;
408
	m_sData = new unsigned char[m_lDataSize];
409
 
410
	memcpy ( m_sData, data, size );
411
 
412
	return true;
413
}
414
 
415
 
416
/*
417
	Func:	ReadFromFile
418
	Accept:	id		- File Pointer Stream of open file
419
			size	- amount of data to read from file
420
			dosize	- Read the 4 character size
421
	Func:	Reads a data stream from a currently open file
422
			Can be used to read directly from a SPK Package
423
			dosize will read the initial 4 character uncompressed size if needed
424
*/
425
bool C_File::ReadFromFile ( FILE *id, long size, bool dosize )
426
{
427
	// remove data
428
 
429
	m_lDataSize = size ;
430
	m_sData = new unsigned char[m_lDataSize];
431
	if ( dosize )
432
	{
433
		unsigned char s[4];
434
		fread ( s, sizeof(unsigned char), 4, id );
435
	}
436
 
437
	fread ( m_sData, sizeof(unsigned char), m_lDataSize, id );
438
 
439
	if ( ferror (id) )
440
	{
441
		DeleteData ();
442
		m_lDataSize = 0;
443
		return false;
444
	}
445
 
446
	return true;
447
}
448
 
449
 
43 cycrow 450
void C_File::copyData(const unsigned char *data, size_t size)
451
{
452
	m_lDataSize = (long)size;
453
	delete m_sData;
454
	m_sData = new unsigned char[size];
455
	memcpy(m_sData, data, size);
456
}
1 cycrow 457
 
43 cycrow 458
 
1 cycrow 459
/*
460
	Func:	GetFilePointer
461
	Desc:	Returns the file pointer name
462
			Joins dir and name together
463
			Works for relative paths as well
464
*/
465
CyString C_File::GetFilePointer ()
466
{
467
	CyString fullfile = m_sFullDir;
468
	if ( !fullfile.Empty() )
469
		fullfile += "/";
470
 
471
	if ( !m_sName.Empty() )
472
		fullfile += m_sName;
473
 
474
	return fullfile;
475
}
476
 
477
 
478
void C_File::UpdateSignature()
479
{
480
	m_sSignature = "";
481
 
482
	bool deleteData = false;
483
	if ( !m_sData )
484
	{
485
		if ( !ReadFromFile() )
486
			return;
487
		deleteData = true;
488
	}
489
 
490
	if ( CheckPCK() )
491
		UnPCKFile();
492
 
493
	m_bUpdatedSignature = true;
494
 
495
	if ( !m_sData )
496
		return;
497
 
498
	size_t fPos = m_lDataSize;
499
	if ( fPos > 700 )
500
		fPos = 700;
501
	unsigned char *data = m_sData + (m_lDataSize - fPos);
502
	data[fPos - 1] = '\0';
503
	CyString sData ((char *)data);
504
	int pos = sData.FindPos("</codearray>", 0);
505
	if ( pos != -1 )
506
	{
507
		sData = sData.Right(sData.Length() - pos);
508
		pos = sData.FindPos("<signature>", 0);
509
		int endpos = sData.FindPos("</signature>", 0);
510
		if ( pos != -1 && endpos != -1 )
511
		{
512
			m_sSignature = sData.Mid(pos + 12, endpos - (pos + 12) + 1);
513
			m_sSignature = m_sSignature.Remove('\n').Remove('\r');
514
		}
515
	}
516
 
517
	if ( deleteData )
518
		DeleteData();
519
}
520
 
521
 
522
/*
523
	Func:	ReadFileSize()
524
	Return:	Returns the file size read
525
	Desc:	Opens the file and seeks to the end
526
*/
527
long C_File::ReadFileSize ()
528
{
529
 
530
	FILE *id = fopen ( GetFilePointer().c_str(), "rb" );
531
	if ( id )
532
	{
533
		fseek ( id, 0, SEEK_END );
534
		m_lSize = ftell ( id );
535
		fclose ( id );
536
	}
537
 
538
	m_lUncomprDataSize = m_lSize;
539
 
540
	return m_lSize;
541
}
542
 
543
/*
544
	Func:	ReadLastModifed()
545
	Desc:	Reads the last modified time of the file and returns
546
			Uses seperate rountines for Windows and Linux
547
*/
548
time_t C_File::ReadLastModified ()
549
{
550
	CyString file = GetFilePointer();
551
	if ( file.Empty() )
552
		return m_tTime;
553
 
554
	#ifndef _WIN32
555
	struct stat attrib;			// create a file attribute structure
556
    stat ( file.c_str(), &attrib);
557
	m_tTime = attrib.st_mtime;
558
	#else
559
	#endif
560
 
561
	return m_tTime;
562
}
563
 
564
bool C_File::CheckValidFilePointer ()
565
{
566
	CyString filename = GetFilePointer();
567
	if ( filename.Empty() )
568
		return false;
569
 
570
	FILE *id = fopen ( filename.c_str(), "rb+" );
571
	if ( !id )
572
		return false;
573
 
574
	fclose ( id );
575
	return true;
576
}
577
 
578
bool C_File::ReadSignedFile()
579
{
580
	if ( (m_iFileType != FILETYPE_SCRIPT) && (m_iFileType != FILETYPE_UNINSTALL) )
581
		return false;
582
 
583
	// check file pointer
584
	CyString file = GetFilePointer();
585
	CyString ext = CFileIO(file).GetFileExtension();
586
	if ( !ext.Compare("xml") && !ext.Compare("pck") )
587
		return false;
588
 
589
	if ( m_iDataCompression != SPKCOMPRESS_NONE )
590
		return m_bSigned;
591
 
592
	// check file extenstion
593
	if ( (ext.Compare("pck")) || (CheckPCK()) )
594
	{
595
		size_t size = 0;
596
		unsigned char *data = UnPCKFile ( &size );
597
		if ( (data) && (size) )
598
			return ::ReadSignedFromData ( data, (long)size );
599
	}
600
	else if ( (m_sData) && (m_iDataCompression == SPKCOMPRESS_NONE) )
601
		return ::ReadSignedFromData ( m_sData, m_lDataSize );
602
	else
603
	{
604
		FILE *id = fopen(file.c_str(), "rb");
605
		if ( id )
606
		{
607
			CyString sRead;
608
			char read[21];
609
 
610
			fseek(id, 0, SEEK_END);
611
			int endPos = ftell(id);
612
 
613
			int pos = endPos;
43 cycrow 614
			int attempts = 100;
1 cycrow 615
			// move to end of the file
616
			while ( true )
617
			{
618
				// read blocks of 20 backwards
619
				pos -= 20;
620
				if ( pos < 0 )
621
					pos = 0;
622
 
623
				fseek(id, pos, SEEK_SET);
624
				fread(read, sizeof(char), 20, id);
625
				read[20] = '\0';
626
				sRead = CyString(read) + sRead;
627
				// find code array
628
				if ( sRead.FindPos("codearray") != -1 )
629
					break;
630
				if ( pos <= 2 )
631
					break;
43 cycrow 632
				--attempts;
633
				if ( attempts <= 0 ) break;
1 cycrow 634
			}
635
 
636
			fclose(id);
637
 
638
			// now check the find read
639
			if ( sRead.FindPos("signed") != -1 )
640
				return true;
641
		}
642
	}
643
 
644
	return false;
645
}
646
 
647
int C_File::ReadScriptVersion ()
648
{
649
	if ( (m_iFileType != FILETYPE_SCRIPT) && (m_iFileType != FILETYPE_UNINSTALL) )
650
		return 0;
651
 
652
	// check file pointer
653
	CyString file = GetFilePointer();
654
	// check file extenstion
655
	if ( (CFileIO(file).CheckFileExtension("pck")) || (CheckPCK()) )
656
	{
657
		size_t size = 0;
658
		unsigned char *data = UnPCKFile ( &size );
659
		if ( (data) && (size) )
660
			m_iVersion = ::ReadScriptVersionFromData ( data, (long)size );
661
	}
662
	else if ( (m_sData) && (m_iDataCompression == SPKCOMPRESS_NONE) )
663
		m_iVersion = ::ReadScriptVersionFromData ( m_sData, m_lDataSize );
664
	else
665
	{
666
		FILE *id = fopen ( file.c_str(), "rb+" );
667
		if ( id )
668
		{
669
			fclose ( id );
670
			std::string line;
671
			std::ifstream myfile ( file.c_str() );
672
			if ( myfile.is_open() )
673
			{
674
				bool inscript = false;
675
				while (! myfile.eof() )
676
				{
677
					std::getline ( myfile, line );
678
					while ( line[0] == ' ' )
679
						line.erase ( 0, 1 );
680
					CyString sLine = line;
681
					if ( !inscript )
682
					{
683
						if ( sLine.GetToken ( 1, '>' ) == "<script" )
684
							inscript = true;
685
					}
686
					else
687
					{
688
						if ( sLine.GetToken ( 1, '>' ) == "<version" )
689
						{
690
							m_iVersion = sLine.GetToken ( 2, '>' ).GetToken ( 1, '<' ).ToInt();
691
							break;
692
						}
693
					}
694
				}
695
				myfile.close();
696
			}
697
		}
698
	}
699
 
700
	return m_iVersion;
701
}
702
 
703
bool C_File::MatchFile ( C_File *file )
704
{
705
	if ( file->GetFileType() != m_iFileType )
706
		return false;
707
 
708
	if ( file->GetDir() != m_sDir )
709
		return false;
710
 
711
	if ( file->GetName() != m_sName )
712
		return false;
713
 
714
	return true;
715
}
716
 
717
/*
718
########################################################################################################################
719
####################################              Compression Functions             ####################################
720
########################################################################################################################
721
*/
722
 
723
bool C_File::CompressFile ( CProgressInfo *progress )
724
{
725
	CyString file = this->GetFilePointer();
726
	if ( !CFileIO(this->GetFilePointer()).Exists() )
727
	{
728
		if ( !this->WriteToFile("tempuncompr.dat", m_sData, m_lDataSize) )
729
			return false;
730
		file = "tempuncompr.dat";
731
	}
732
 
733
	bool ret = false;
734
 
735
	FILE *fIn = fopen(file.c_str(), "rb");
736
	if ( fIn )
737
	{
738
		FILE *fOut = fopen("tempcompr.dat", "wb");
739
		if ( fOut )
740
		{
741
			int err;
742
			if ( progress )
743
				err = zlib_def(fIn, fOut, progress->GetDonePointer());
744
			else
745
				err = zlib_def(fIn, fOut, 0);
746
 
747
			fclose(fOut);
748
			if ( err == Z_OK )
749
			{
750
				DeleteData ();
751
 
752
				FILE *id = fopen ( "tempcompr.dat", "rb" );
753
				if ( id )
754
				{
755
					fseek ( id, 0, SEEK_END );
756
					m_lDataSize = ftell ( id );
757
					rewind ( id );
758
					m_sData = new unsigned char[m_lDataSize];
759
					if ( !m_sData ) { fclose ( id ); m_iLastError = SPKERR_MALLOC; }
760
					else
761
					{
762
						fread ( m_sData, sizeof(unsigned char), m_lDataSize, id );
763
						if ( ferror(id) )
764
						{
765
							m_iLastError = SPKERR_FILEREAD;
766
							DeleteData ();
767
							m_lDataSize = 0;
768
						}
769
						else
770
						{
771
							ret = true;
772
							m_iLastError = SPKERR_NONE;
773
							m_iDataCompression = SPKCOMPRESS_ZLIB;
774
						}
775
					}
776
 
777
					fclose(id);
778
				}
779
			}
780
		}
781
		CFileIO("tempcompr.dat").Remove();
782
 
783
		fclose(fIn);
784
	}
785
 
786
	CFileIO("tempuncompr.dat").Remove();
787
 
788
	return ret;
789
}
790
 
791
bool C_File::ChangeCompression ( int compressionType, CProgressInfo *progress )
792
{
793
	// no data to try to compress
794
	if ( (!m_sData) || (!m_lDataSize) )
795
		return false;
796
 
797
	// laready compressed to correct type
798
	if ( compressionType == m_iDataCompression )
799
		return true;
800
 
801
	// otherwise, lets recompress the file
802
	// first we uncompress the data
803
	if ( !this->UncompressData(progress) )
804
		return false;
805
 
806
	// next we compress to new type
807
	if ( !this->CompressData(compressionType, progress) )
808
		return false;
809
	return true;
810
}
811
 
812
unsigned char *C_File::CompressToData(int compressionType, unsigned long *outSize, CProgressInfo *progress, int level)
813
{
814
	unsigned long comprLen = m_lDataSize;
815
	if ( comprLen < 100 )		comprLen = 200;
816
	else if ( comprLen < 1000 )	comprLen *= 2;
817
	comprLen += 1000;
818
 
819
	switch(compressionType)
820
	{
821
		case SPKCOMPRESS_ZLIB:
822
			{
823
				unsigned char *compr = (unsigned char *)calloc(comprLen, 1);
824
				int err = Z_NOTENOUGH_BUF;
825
				while ( err == Z_NOTENOUGH_BUF )
826
				{
827
					err = compress2 ( compr, &comprLen, (const unsigned char *)m_sData, m_lDataSize, (progress) ? progress->GetDonePointer() : 0, level );
828
					if ( err == Z_NOTENOUGH_BUF )
829
					{
830
						comprLen += (CHUNK * 2);
831
						compr = (unsigned char *)realloc(compr, comprLen);
832
					}
833
					else
834
						break;
835
				}	
836
 
837
				// if its compressed ok, remove old data and use new one
838
				if ( err == Z_OK )
839
				{
840
					unsigned char *retData = new unsigned char[comprLen];
841
					(*outSize) = comprLen;
842
					memcpy(retData, compr, comprLen);
843
					free(compr);
844
					return retData;
845
				}
846
 
847
				free(compr);
848
				return NULL;
849
			}
850
			break;
851
 
852
		case SPKCOMPRESS_LZMA:
853
			{
854
				unsigned char *compr = (unsigned char *)malloc(comprLen);
855
				SRes res = Lzma86_Encode((Byte *)compr, (size_t *)&comprLen, (const Byte *)m_sData, (size_t)m_lDataSize, level, LZMA_DICT, SZ_FILTER_NO, (progress) ? progress->GetDonePointer() : NULL);
856
 
857
				if ( res == SZ_OK )
858
				{
859
					unsigned char *retData = new unsigned char[comprLen];
860
					(*outSize) = comprLen;
861
					memcpy(retData, compr, comprLen);
862
					free(compr);
863
					return retData;
864
				}
865
 
866
				free(compr);
867
				return NULL;
868
			}
869
			break;
870
	}
871
 
872
	return NULL;
873
}
874
 
875
bool C_File::CompressData ( int compressionType, CProgressInfo *progress, int level )
876
{
877
	// no data to try to compress
878
	if ( (!m_sData) || (!m_lDataSize) )
879
		return false;
880
 
881
	// if comopression is set to noe, dont bother
882
	if ( compressionType == SPKCOMPRESS_NONE )
883
		return true;
884
 
885
	if ( compressionType == SPKCOMPRESS_7ZIP )
886
		compressionType = SPKCOMPRESS_LZMA;
887
 
888
	// if its zlib, and we are trying to compress pcked files (ie already zlib compression) then switch to lzma instead
889
	if ( compressionType == SPKCOMPRESS_ZLIB && (this->CheckFileExt("pck") || this->CheckFileExt("cat") || this->CheckFileExt("dat") || this->CheckFileExt("pbb") || this->CheckFileExt("pbd")) )
890
		compressionType = SPKCOMPRESS_LZMA;
891
 
892
	// if its already compressed, no need to compress again
893
	if ( compressionType == m_iDataCompression )
894
		return true;
895
 
896
	// no need to change the compression
897
	if ( m_iDataCompression != SPKCOMPRESS_NONE )
898
		return true;
899
 
900
	m_lUncomprDataSize = m_lDataSize;
901
 
902
	unsigned long comprLen = m_lDataSize;
903
	if ( comprLen < 100 )
904
		comprLen = 200;
905
	else if ( comprLen < 1000 )
906
		comprLen *= 2;
907
	comprLen += 1000;
908
 
909
	// > 500mb (do file compression
910
	if ( comprLen > 500000000 )
911
		return this->CompressFile(progress);
912
 
913
	// best compression, attempt to compress the file multiple times until we get the best one
914
	if ( compressionType == SPKCOMPRESS_BEST )
915
	{
916
		int compress[] = { SPKCOMPRESS_ZLIB, SPKCOMPRESS_LZMA };
917
		int bestCompress = -1;
918
		unsigned int bestSize = 0;
919
		unsigned char *bestCompr = NULL;
920
		for ( int i = 0; i < 2; i++ )
921
		{
922
			unsigned long checkSize = 0;
923
			unsigned char *compr = this->CompressToData(compress[i], &checkSize, progress, level);
924
			if ( compr )
925
			{
926
				if ( checkSize < bestSize || bestCompress == -1 )
927
				{
928
					if ( bestCompr )
929
						delete bestCompr;
930
					bestCompr = compr;
931
					bestCompress = compress[i];
932
					bestSize = checkSize;
933
				}
934
				// not the best, no need to keep it
935
				else
936
					delete compr;
937
			}
938
		}
939
 
940
		if ( bestCompress != -1 && bestCompr )
941
		{
942
			DeleteData ();
943
			m_sData = bestCompr;
944
			m_bUsedMalloc = false;
945
			m_lDataSize = bestSize;
946
			m_iDataCompression = bestCompress;
947
			return true;
948
		}
949
 
950
		if ( bestCompr )
951
			delete bestCompr;
952
	}
953
 
954
	if ( compressionType == SPKCOMPRESS_ZLIB || compressionType == SPKCOMPRESS_LZMA )
955
	{
956
		unsigned char *compr = this->CompressToData(compressionType, &comprLen, progress, level);
957
		if ( compr )
958
		{
959
			DeleteData ();
960
			m_sData = compr;
961
			m_bUsedMalloc = false;
962
			m_lDataSize = comprLen;
963
			m_iDataCompression = compressionType;
964
		}
965
		// we shall always return true, files can be added in non compressed mode
966
		return true;
967
	}
968
 
969
	return false;
970
}
971
 
972
bool C_File::UncompressData ( CProgressInfo *progress )
973
{
974
	// no data to try to uncompress
45 cycrow 975
	if ( (!m_sData) || (!m_lDataSize) ) {
976
		return (m_lSize) ? false : true;
977
	}
1 cycrow 978
 
979
	if ( m_bCompressedToFile )
980
		return false;
981
 
982
	// if comopression is set to none, dont bother
983
	if ( m_iDataCompression == SPKCOMPRESS_NONE )
984
		return true;
985
 
986
	if ( m_iDataCompression == SPKCOMPRESS_ZLIB )
987
	{
988
		unsigned long uncomprLen = m_lUncomprDataSize;
989
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
990
		int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );
991
		if ( err == Z_OK )
992
		{
993
			DeleteData ();
994
			m_iDataCompression = SPKCOMPRESS_NONE;
995
			m_lDataSize = uncomprLen;
996
			m_sData = uncompr;
997
			return true;
998
		}
999
 
1000
		if ( uncompr )
1001
			delete [] uncompr;
1002
	}
1003
	else if ( m_iDataCompression == SPKCOMPRESS_LZMA )
1004
	{
1005
		size_t uncomprLen = m_lUncomprDataSize;
1006
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1007
		SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);
1008
		if ( res == SZ_OK )
1009
		{
1010
			DeleteData ();
1011
			m_iDataCompression = SPKCOMPRESS_NONE;
1012
			m_lDataSize = (long)uncomprLen;
1013
			m_sData = new unsigned char[m_lDataSize];
1014
			memcpy(m_sData, uncompr, m_lDataSize);
1015
			delete uncompr;
1016
			return true;
1017
		}
1018
 
1019
		if ( uncompr )
1020
			delete [] uncompr;
1021
	}
1022
	else if ( m_iDataCompression == SPKCOMPRESS_7ZIP )
1023
	{
1024
		long len = m_lUncomprDataSize;
1025
		unsigned char *compr = LZMADecode_C ( (unsigned char *)m_sData, m_lDataSize, (size_t*)&len, NULL );
1026
		if ( compr )
1027
		{
1028
			DeleteData ();
1029
			m_sData = compr;
1030
			m_lDataSize = len;
1031
			m_iDataCompression = SPKCOMPRESS_NONE;
1032
			return true;
1033
		}
1034
	}
1035
 
1036
	return false;
1037
}
1038
 
1039
unsigned char *C_File::UncompressData ( long *size, CProgressInfo *progress )
1040
{
1041
	// no data to try to uncompress
1042
	if ( (!m_sData) || (!m_lDataSize) )
1043
		return NULL;
1044
 
1045
	//if ( m_bCompressedToFile )
1046
	//	return NULL;
1047
 
1048
	// if comopression is set to none, dont bother
1049
	if ( m_iDataCompression == SPKCOMPRESS_NONE )
1050
	{
1051
		*size = m_lDataSize;
1052
		return m_sData;
1053
	}
1054
 
1055
	if ( m_iDataCompression == SPKCOMPRESS_ZLIB )
1056
	{
1057
		unsigned long uncomprLen = m_lUncomprDataSize;
1058
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1059
		int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );
1060
		if ( err == Z_OK )
1061
		{
1062
			*size = uncomprLen;
1063
			return uncompr;
1064
		}
1065
		if ( uncompr )
1066
			delete [] uncompr;
1067
	}
1068
	if ( m_iDataCompression == SPKCOMPRESS_7ZIP )
1069
	{
1070
		long len = m_lUncomprDataSize;
1071
		unsigned char *compr = LZMADecode_C ( m_sData, m_lDataSize, (size_t *)&len, NULL );
1072
		if ( compr )
1073
		{
1074
			*size = len;
1075
			return compr;
1076
		}
1077
		if ( compr )
1078
			delete [] compr;
1079
	}
1080
	else if ( m_iDataCompression == SPKCOMPRESS_LZMA )
1081
	{
1082
		size_t uncomprLen = m_lUncomprDataSize;
1083
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1084
		SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);
1085
		if ( res == SZ_OK )
1086
		{
1087
			*size = (long)uncomprLen;
1088
			return uncompr;
1089
		}
1090
		if ( uncompr )
1091
			delete [] uncompr;
1092
	}
1093
 
1094
	return NULL;
1095
}
1096
 
1097
bool C_File::UncompressToFile ( CyString toFile, CBaseFile *spkfile, bool includedir, CProgressInfo *progress )
1098
{
1099
#ifdef _INCLUDE7ZIP
1100
	if ( (!m_sData) || (!m_lDataSize) )
1101
		return false;
1102
	// if theres a tmp file, open it and check it still exists
1103
	if ( !m_sTmpFile.Empty() )
1104
	{
1105
		FILE *id = fopen ( m_sTmpFile.c_str(), "rb" );
1106
		if ( id )
1107
		{
1108
			fclose ( id );
1109
			return true;
1110
		}
1111
		m_sTmpFile = "";
1112
	}
1113
 
1114
	// now uncompress to the file
1115
	CyString file = toFile;
1116
	if ( file.Empty() )
1117
	{
1118
		m_iTempNum++;
1119
		file = CyString("uncompr") + (long)m_iTempNum + ".tmp";
1120
	}
1121
	else
1122
		file = GetFullFileToDir ( file, includedir, spkfile );
1123
 
1124
	FILE *id = fopen ( "compr.tmp", "wb" );
1125
	if ( !id )
1126
		return false;
1127
 
1128
	fwrite ( m_sData, sizeof(unsigned char), m_lDataSize, id );
1129
	bool ret = false;
1130
	int err = ferror(id);
1131
	fclose ( id );
1132
	if ( !err )
1133
	{
1134
		if ( LZMADecodeFile ( "compr.tmp", file.c_str(), (CProgressInfo7Zip *)progress ) )
1135
		{
1136
			ret = true;
1137
			if ( toFile.Empty() )
1138
				m_sTmpFile = file;
1139
		}
1140
	}
1141
 
1142
	remove ( "compr.tmp" );
1143
 
1144
	return ret;
1145
#else
1146
	return false;
1147
#endif
1148
}
1149
 
1150
 
1151
bool C_File::WriteFilePointer ( unsigned char *cData, long len )
1152
{
1153
	return WriteToFile ( GetFilePointer(), cData, len );
1154
}
1155
 
1156
bool C_File::WriteToFile ( CyString filename, unsigned char *cData, long len )
1157
{
1158
	unsigned char *data = cData;
1159
	if ( (!len) || (!data) )
1160
	{
1161
		len = m_lDataSize;
1162
		data = m_sData;
1163
	}
1164
 
45 cycrow 1165
	if ( (!len) || (!data) ) {
1166
		if ( m_lSize ) return false;
1167
	}
1 cycrow 1168
 
1169
	// check for cat file
1170
	if ( filename.IsIn ( "::" ) )
1171
	{
1172
		CyString catfile = filename.GetToken ( "::", 1, 1 );
1173
		CyString file = filename.GetToken ( "::", 2, 2 );
1174
 
1175
		CCatFile newcat;
1176
		return newcat.AddData ( catfile, data, len, file, true, true );
1177
	}
1178
	else
1179
	{
1180
		CyString filen = filename.FindReplace ( "/", "\\" );
1181
		filen = filen.FindReplace ( "\\\\", "\\" );
1182
 
1183
		FILE *id = fopen ( filen.c_str(), "wb" );
1184
		if ( !id )
1185
			return false;
1186
 
1187
		bool ret = true;
45 cycrow 1188
		if ( len && data ) {
1189
			fwrite ( data, sizeof(unsigned char), len, id );
1 cycrow 1190
 
45 cycrow 1191
			if ( ferror(id) )
1192
				ret = false;
1 cycrow 1193
 
45 cycrow 1194
			fclose ( id );
1195
		}
1 cycrow 1196
		return ret;
1197
	}
1198
 
1199
	return false;
1200
}
1201
 
1202
CyString C_File::GetFullFileToDir ( CyString dir, bool includedir, CBaseFile *file )
1203
{
1204
	CyString fullfile = dir;
1205
	if ( includedir )
1206
	{
1207
		CyString d = GetDirectory ( file );
1208
		if ( !d.Empty() )
1209
		{
1210
			if ( !fullfile.Empty() )
1211
				fullfile += "/";
1212
			fullfile += d;
1213
		}
1214
	}
1215
	if ( !m_sName.Empty() )
1216
	{
1217
		if ( !fullfile.Empty() )
1218
			fullfile += "/";
1219
		fullfile += m_sName;
1220
	}
1221
 
1222
	fullfile = fullfile.FindReplace ( "\\", "/" );
1223
	return fullfile;
1224
}
1225
 
1226
bool C_File::WriteToDir ( CyString &dir, CBaseFile *spkfile, bool includedir, CyString appendDir, unsigned char *data, long len )
1227
{
1228
	CyString fullfile = GetFullFileToDir ( dir, includedir, spkfile );
1229
 
1230
	if ( !appendDir.Empty() )
1231
	{
1232
		if ( !fullfile.Empty() )
1233
			fullfile += "/";
1234
		fullfile += appendDir;
1235
	}
1236
 
1237
	CyString fulldir = fullfile.GetToken ( 1, fullfile.NumToken('/') - 2, '/' );
1238
	if ( !fulldir.Empty() )
1239
	{
1240
		if ( !CDirIO(fulldir).Create() )
1241
			return false;
1242
	}
1243
 
1244
	return WriteToFile ( fullfile, data, len );
1245
}
1246
 
1247
CyString C_File::GetDataSizeString ()
1248
{
1249
	return SPK::GetSizeString ( m_lDataSize );
1250
}
1251
CyString C_File::GetUncompressedSizeString ()
1252
{
1253
	return SPK::GetSizeString ( GetUncompressedDataSize() );
1254
}
1255
 
1256
CyString C_File::GetCreationTimeString ()
1257
{
1258
	if ( !m_tTime )
1259
		return NullString;
1260
 
1261
	struct tm   *currDate;
1262
	char    dateString[100];
1263
 
1264
	time_t n = m_tTime;
1265
 
1266
	currDate = localtime(&n);
1267
 
1268
	strftime(dateString, sizeof dateString, "(%d/%m/%Y) %H:%M", currDate);
1269
 
1270
 
1271
	return CyString(dateString);
1272
}
1273
 
1274
bool C_File::CompareNew ( C_File *file )
1275
{
1276
	if ( !m_iVersion )
1277
		ReadScriptVersion ();
1278
 
1279
	// if version, check if its later version
1280
	if ( (m_iVersion) && (file->GetVersion()) )
1281
	{
1282
		if ( m_iVersion > file->GetVersion() )
1283
			return false;
1284
	}
1285
 
1286
	// now check for last modified time
1287
	if ( (m_tTime) && (file->GetLastModified()) )
1288
	{
1289
		if ( m_tTime > file->GetLastModified() )
1290
			return false;
1291
	}
1292
 
1293
	// assume same or newer
1294
	return true;
1295
}
1296
 
1297
CyString GetFileTypeString ( int type )
1298
{
1299
	switch ( type )
1300
	{
1301
		case FILETYPE_SCRIPT:
1302
			return "Script";
1303
		case FILETYPE_TEXT:
1304
			return "Text";
1305
		case FILETYPE_README:
1306
			return "Readme";
1307
		case FILETYPE_MAP:
1308
			return "Map";
1309
		case FILETYPE_MOD:
1310
			return "Mod";
1311
		case FILETYPE_UNINSTALL:
1312
			return "Uninstall";
1313
		case FILETYPE_SOUND:
1314
			return "Sound";
1315
		case FILETYPE_EXTRA:
1316
			return "Extra";
1317
		case FILETYPE_SCREEN:
1318
			return "Screen";
1319
		case FILETYPE_ADVERT:
1320
			return "Advert";
1321
		case FILETYPE_MISSION:
1322
			return "Mission";
1323
		case FILETYPE_BACKUP:
1324
			return "Backup";
1325
		case FILETYPE_SHIPOTHER:
1326
			return "ShipOther";
1327
		case FILETYPE_SHIPMODEL:
1328
			return "ShipModel";
1329
		case FILETYPE_SHIPSCENE:
1330
			return "ShipScene";
1331
		case FILETYPE_COCKPITSCENE:
1332
			return "CockpitScene";
1333
	}
1334
 
1335
	return NullString;
1336
}
1337
 
1338
int GetFileTypeFromString ( CyString type )
1339
{
1340
	CyString ltype = type.ToLower();
1341
	if ( ltype == "script" )
1342
		return FILETYPE_SCRIPT;
1343
	else if ( ltype == "text" )
1344
		return FILETYPE_TEXT;
1345
	else if ( ltype == "readme" )
1346
		return FILETYPE_README;
1347
	else if ( ltype == "map" )
1348
		return FILETYPE_MAP;
1349
	else if ( ltype == "mod" )
1350
		return FILETYPE_MOD;
1351
	else if ( ltype == "uninstall" )
1352
		return FILETYPE_UNINSTALL;
1353
	else if ( ltype == "sound" )
1354
		return FILETYPE_SOUND;
1355
	else if ( ltype == "extra" )
1356
		return FILETYPE_EXTRA;
1357
	else if ( ltype == "screen" )
1358
		return FILETYPE_SCREEN;
1359
	else if ( ltype == "advert" )
1360
		return FILETYPE_ADVERT;
1361
	else if ( ltype == "mission" )
1362
		return FILETYPE_MISSION;
1363
	else if ( ltype == "backup" )
1364
		return FILETYPE_BACKUP;
1365
	else if ( ltype == "shipother" )
1366
		return FILETYPE_SHIPOTHER;
1367
	else if ( ltype == "shipmodel" )
1368
		return FILETYPE_SHIPMODEL;
1369
	else if ( ltype == "shipscene" )
1370
		return FILETYPE_SHIPSCENE;
1371
	else if ( ltype == "cockpitscene" )
1372
		return FILETYPE_COCKPITSCENE;
1373
 
1374
	return -1;
1375
}
1376
 
1377
 
1378
CyString FormatErrorString(int error, CyString rest)
1379
{
1380
	int max = 0;
1381
	CyString *args = 0;
1382
 
1383
	if ( !rest.Empty() )
1384
		args = rest.SplitToken('~', &max);
1385
 
1386
	CyString errorStr;
1387
	switch ( error )
1388
	{
1389
		case SPKINSTALL_CREATEDIRECTORY:
1390
			errorStr = "Creating Directory: %1";
1391
			break;
1392
		case SPKINSTALL_CREATEDIRECTORY_FAIL:
1393
			errorStr = "Unable to Creating Directory: %1";
1394
			break;
1395
		case SPKINSTALL_WRITEFILE:
1396
			errorStr = "Writing File: %1";
1397
			break;
1398
		case SPKINSTALL_WRITEFILE_FAIL:
1399
			errorStr = "Unable to Write File: %1";
1400
			break;
1401
		case SPKINSTALL_DELETEFILE:
1402
			errorStr = "Deleting File: %1";
1403
			break;
1404
		case SPKINSTALL_DELETEFILE_FAIL:
1405
			errorStr = "Unable to delete File: %1";
1406
			break;
1407
		case SPKINSTALL_REMOVEDIR:
1408
			errorStr = "Removing Directory: %1";
1409
			break;
1410
		case SPKINSTALL_SKIPFILE:
1411
			errorStr = "Skipping File (older): %1";
1412
			break;
1413
		case SPKINSTALL_ENABLEFILE:
1414
			errorStr = "Enabled File: %1";
1415
			break;
1416
		case SPKINSTALL_DISABLEFILE:
1417
			errorStr = "Disabled File: %1";
1418
			break;
1419
		case SPKINSTALL_ENABLEFILE_FAIL:
1420
			errorStr = "Failed to enable File: %1";
1421
			break;
1422
		case SPKINSTALL_DISABLEFILE_FAIL:
1423
			errorStr = "Failed to disable File: %1";
1424
			break;
1425
		case SPKINSTALL_UNINSTALL_MOVE:
1426
			errorStr = "Moving uninstall file: %1";
1427
			break;
1428
		case SPKINSTALL_UNINSTALL_MOVE_FAIL:
1429
			errorStr = "Unable to Move uninstall file: %1";
1430
			break;
1431
		case SPKINSTALL_UNINSTALL_COPY:
1432
			errorStr = "Coping uninstall file: %1";
1433
			break;
1434
		case SPKINSTALL_UNINSTALL_COPY_FAIL:
1435
			errorStr = "Unable to Copy uninstall file: %1";
1436
			break;
1437
		case SPKINSTALL_UNINSTALL_REMOVE:
1438
			errorStr = "Removing Uninstall file: %1";
1439
			break;
1440
		case SPKINSTALL_UNINSTALL_REMOVE_FAIL:
1441
			errorStr = "Unable to remove Uninstall file: %1";
1442
			break;
1443
		case SPKINSTALL_SHARED:
1444
			errorStr = "Removing Unused Shared file: %1";
1445
			break;
1446
		case SPKINSTALL_SHARED_FAIL:
1447
			errorStr = "Unable to remove Unused Shared file: %1";
1448
			break;
1449
		case SPKINSTALL_ORIGINAL_BACKUP:
1450
			errorStr = "Backing up original file: %1";
1451
			break;
1452
		case SPKINSTALL_ORIGINAL_BACKUP_FAIL:
1453
			errorStr = "Unable to back up original file: %1";
1454
			break;
1455
		case SPKINSTALL_ORIGINAL_RESTORE:
1456
			errorStr = "Restoring original file: %1";
1457
			break;
1458
		case SPKINSTALL_ORIGINAL_RESTORE_FAIL:
1459
			errorStr = "Unable to restore original file: %1";
1460
			break;
1461
		case SPKINSTALL_FAKEPATCH:
1462
			errorStr = "Shifted fake patch: %1 to %2";
1463
			break;
1464
		case SPKINSTALL_FAKEPATCH_FAIL:
1465
			errorStr = "Unable to shift fake patch: %1 to %2";
1466
			break;
1467
		case SPKINSTALL_AUTOTEXT:
1468
			errorStr = "Shifted text file: %1 to %2";
1469
			break;
1470
		case SPKINSTALL_AUTOTEXT_FAIL:
1471
			errorStr = "Unable to shift text file: %1 to %2";
1472
			break;
1473
		case SPKINSTALL_MISSINGFILE:
1474
			errorStr = "File is missing: %1";
1475
			break;
1476
		case SPKINSTALL_ORPHANED:
1477
			errorStr = "Orphaned File removed: %1";
1478
			break;
1479
		case SPKINSTALL_ORPHANED_FAIL:
1480
			errorStr = "Unable to remove Orphaned File: %1";
1481
			break;
1482
	}
1483
 
1484
	CyString ret = errorStr.Args(args, max);
1485
	CLEANSPLIT(args, max)
1486
	return ret;
1487
}
1488
 
1489
 
1490
bool C_File::CheckPCK ()
1491
{
1492
	if ( (m_sData) && (m_lDataSize) && (m_iDataCompression == SPKCOMPRESS_NONE) )
1493
		return IsDataPCK ( m_sData, m_lDataSize );
1494
 
1495
	CyString filename = GetFilePointer();
1496
	if ( !filename.Empty() )
1497
	{
1498
		FILE *id = fopen ( filename.c_str(), "rb+" );
1499
		if ( id )
1500
		{
1501
			unsigned char data[3];
1502
			fread ( data, sizeof(unsigned char), 3, id );
1503
			fclose ( id );
1504
 
1505
			return IsDataPCK ( data, 3 );
1506
		}
1507
	}
1508
 
1509
	if ( CheckFileExt("pck") || CheckFileExt("pbb") || CheckFileExt("pbd") )
1510
		return true;
1511
	return false;
1512
}
1513
 
1514
bool C_File::PCKFile()
1515
{
1516
	if ( !m_lDataSize || !m_sData )
1517
	{
1518
		if ( !this->ReadFromFile() )
1519
			return false;
1520
	}
1521
 
1522
	if ( m_lDataSize && m_sData )
1523
	{
1524
		if ( !this->UncompressData() )
1525
			return false;
1526
 
1527
		size_t size;
40 cycrow 1528
		unsigned char *data = PCKData(m_sData, m_lDataSize, &size, false);
1 cycrow 1529
		if ( data && size )
1530
		{
40 cycrow 1531
			m_lUncomprDataSize = m_lDataSize;
1 cycrow 1532
			this->DeleteData();
1533
			m_bUsedMalloc = false;
1534
			m_lDataSize = (long)size;
1535
			m_sData = new unsigned char[size];
1536
			memcpy(m_sData, data, size);
1537
			delete [] data;
1538
		}
1539
 
1540
		return true;
1541
	}
1542
 
1543
	return false;
1544
}
1545
 
1546
unsigned char *C_File::UnPCKFile ( size_t *len )
1547
{
1548
	unsigned char *data = NULL;
1549
	size_t datasize = 0;
1550
 
1551
	if ( CheckValidFilePointer() )
1552
	{
1553
		FILE *id = fopen ( GetFilePointer().c_str(), "rb+" );
1554
		if ( id )
1555
		{
1556
			fseek ( id, 0, SEEK_END );
1557
			datasize = ftell ( id );
1558
			rewind ( id );
1559
 
1560
			data = new unsigned char[datasize];
1561
			fread ( data, sizeof(unsigned char), datasize, id );
1562
			fclose ( id );
1563
		}
1564
	}
1565
 
1566
	if ( !data )
1567
	{
1568
		if ( !m_lDataSize )
1569
		{
1570
			if ( !this->ReadFromFile() )
1571
				return NULL;
1572
		}
1573
		datasize = m_lDataSize;
1574
		data = new unsigned char[datasize];
1575
		memcpy ( data, m_sData, datasize );
1576
	}
1577
 
1578
	if ( data )
1579
	{
1580
		unsigned char *newdata = UnPCKData ( data, datasize, len, CheckPCK() );
1581
		delete data;
1582
		return newdata;
1583
	}
1584
 
1585
	return NULL;
1586
}
1587
 
1588
bool C_File::UnPCKFile()
1589
{
1590
	if ( !m_lDataSize || !m_sData )
1591
	{
1592
		if ( !this->ReadFromFile() )
1593
			return false;
1594
	}
1595
	if ( m_lDataSize && m_sData )
1596
	{
1597
		if ( !this->UncompressData() )
1598
			return false;
1599
 
1600
		size_t size;
1601
		unsigned char *data = UnPCKData(m_sData, m_lDataSize, &size, CheckPCK());
1602
		if ( data && size )
1603
		{
1604
			this->DeleteData();
1605
			m_lUncomprDataSize = m_lDataSize;
1606
			m_bUsedMalloc = false;
1607
			m_sData = new unsigned char[size];
1608
			memcpy(m_sData, data, size);
1609
			m_lDataSize = (long)size;
1610
			delete []data;
1611
		}
1612
 
1613
		return true;
1614
	}
1615
 
1616
	return false;
1617
}
1618
 
1619
unsigned char *UnPCKFile ( const char *file, size_t *len, bool nocrypt )
1620
{
1621
	FILE *id = fopen ( file, "rb" );
1622
	if ( !id )
1623
		return NULL;
1624
 
1625
	fseek ( id, 0, SEEK_END );
1626
	size_t size = ftell ( id );
1627
	fseek ( id, 0, SEEK_SET );
1628
 
1629
	unsigned char *data = new unsigned char[size];
1630
	fread ( data, sizeof(unsigned char), size, id );
1631
 
1632
	if ( ferror(id) )
1633
	{
1634
		delete data;
1635
		data = NULL;
1636
	}
1637
 
1638
	fclose ( id );
1639
 
1640
	if ( data )
1641
	{
1642
		unsigned char *unData = UnPCKData ( data, size, len, nocrypt );
1643
		delete data;
1644
		return unData;
1645
	}
1646
 
1647
	return NULL;
1648
}
1649
 
1650
unsigned char *UnPCKData ( unsigned char *data, size_t datasize, size_t *len ) { return UnPCKData(data, datasize, len, IsDataPCK(data, datasize)); }
1651
unsigned char *UnPCKData ( unsigned char *data, size_t datasize, size_t *len, bool nocrypt )
1652
{
1653
	//IsDataPCK(data, datasize)
1654
	if ( nocrypt )
1655
	{
1656
		unsigned char magic = data[0] ^ 0xC8;
1657
 
1658
		for ( size_t i = 1; i < datasize; i++ )
1659
			data[i] ^= magic;
1660
		++data;
1661
		--datasize;
1662
	}
1663
 
1664
	// create data buffer
1665
	size_t *uncomprLenSize = (size_t*)(data + (datasize - 4));
1666
	unsigned long uncomprLen = (unsigned long)*uncomprLenSize;
1667
	if ( uncomprLen > (datasize * 100) )
1668
	{
1669
		*len = 0;
1670
		return NULL;
1671
	}
41 cycrow 1672
	unsigned char *uncompr = new unsigned char[uncomprLen + 1];
1 cycrow 1673
	if ( !uncompr ) 
1674
		return NULL;
1675
	memset ( uncompr, 0, sizeof(uncompr) );
1676
 
1677
 
1678
	// find header size
1679
	unsigned char *buf = data + PCKHEADERSIZE;
1680
 
1681
//	buf = data + (6 + sizeof(time_t));
1682
	char flag = data[3];
1683
 
1684
	if ( flag & GZ_FLAG_EXTRA )
1685
	{
1686
		size_t xlen = *((short int*)(buf));
1687
		buf += xlen;
1688
	}
1689
 
1690
	if ( flag & GZ_FLAG_FILENAME )
1691
	{
1692
		char *origname = (char*)(buf);
1693
		buf += strlen (origname) + 1;
1694
	}
1695
	if ( flag & GZ_FLAG_COMMENT )
1696
	{
1697
		char *comment = (char*)(buf);
1698
		buf += strlen(comment) + 1;
1699
	}
1700
	if ( flag & GZ_FLAG_HCRC )
1701
		buf += 2;
1702
	long bufSize = (long)(datasize - (buf-data) - 8);
1703
 
1704
	int err = uncompress2 ( uncompr, &uncomprLen, buf, bufSize );
1705
	if ( err != Z_OK )
1706
	{
1707
		delete uncompr;
1708
		*len = 0;
1709
		return NULL;
1710
	}
1711
 
1712
	*len = uncomprLen;
41 cycrow 1713
	uncompr[uncomprLen] = '\0';
1 cycrow 1714
	return uncompr;
1715
}
1716
 
1717
bool IsDataPCK ( const unsigned char *data, size_t size )
1718
{
1719
	if ( size >=3 )
1720
	{
1721
		unsigned char magic=data[0] ^ 0xC8;
1722
		return ((data[1] ^ magic)==0x1F && (data[2] ^ magic)==0x8B);
1723
	}
1724
	else
1725
		return false;
1726
 
1727
}
1728
 
1729
bool ReadSignedFromData ( unsigned char *data, long size )
1730
{
1731
	if ( IsDataPCK ( data, size ) )
1732
	{
1733
		size_t unpckSize = 0;
1734
		unsigned char *unpckData = UnPCKData ( data, size, &unpckSize, false );
1735
		if ( (unpckData) && (unpckSize) )
1736
			return ReadSignedFromData ( unpckData, (long)unpckSize );
1737
		return false;
1738
	}
1739
 
1740
	// work backwards
1741
	int pos = size - 1;
43 cycrow 1742
	int max = size - 5000;
1743
	if ( max < 0 ) max = 0;
1 cycrow 1744
	// find the first tage
43 cycrow 1745
	while ( pos > max )
1 cycrow 1746
	{
1747
		while ( data[pos] != '>' && pos > 0 )
1748
			pos--;
1749
 
43 cycrow 1750
		char tag[10000];
1 cycrow 1751
		bool checked = false;
1752
		if ( data[pos] == '>' )
1753
		{
1754
			int pos2 = pos - 1;
1755
			// now find the front
43 cycrow 1756
			while ( data[pos2] != '<' && pos2 > max )
1 cycrow 1757
				pos2--;
1758
 
1759
			// now get the tag
1760
			if ( data[pos2] == '<' )
1761
			{
1762
				checked = true;
1763
				memcpy(tag, data + pos2, pos - pos2);
1764
				tag[pos - pos2] = '\0';
1765
 
1766
				// check if tag is signed
1767
				CyString sTag(tag);
1768
 
1769
				if ( sTag.Compare("</signature") || sTag.Compare("<signature") )
1770
					return true;
1771
 
1772
				// check if tag is codearray
1773
				if ( sTag.Compare("</codearray") || sTag.Compare("<codearray") )
1774
					return false;
1775
 
1776
				pos = pos2;
1777
			}
1778
 
1779
			--pos;
1780
		}
1781
 
1782
		if ( !checked )
1783
			break;
1784
	}
1785
 
1786
	return false;
1787
}
1788
 
1789
int ReadScriptVersionFromData ( unsigned char *data, long size )
1790
{
1791
	if ( IsDataPCK ( data, size ) )
1792
	{
1793
		size_t unpckSize = 0;
1794
		unsigned char *unpckData = UnPCKData ( data, size, &unpckSize );
1795
		if ( (unpckData) && (unpckSize) )
1796
			return ReadScriptVersionFromData ( unpckData, (long)unpckSize );
1797
		return 0;
1798
	}
1799
 
1800
	int pos = 0;
1801
	bool found = false;
1802
	int iVersion = 0;
1803
 
1804
	// skip past initial space
1805
	while ( !found )
1806
	{
1807
		while ( (pos < size) && (data[pos] == ' ') )
1808
			++pos;
1809
 
1810
		if ( data[pos] == '<' )
1811
		{
1812
			CyString checktag;
1813
			while ( (pos < size) && (data[pos] != '>') )
1814
			{
1815
				checktag += (char)data[pos];
1816
				++pos;
1817
			}
1818
			++pos;
1819
 
1820
			if ( checktag == "<version" )
1821
			{
1822
				CyString version;
1823
				while ( (pos < size) && (data[pos] != '<') )
1824
				{
1825
					version += (char)data[pos];
1826
					++pos;
1827
				}
1828
				iVersion = version.ToInt();
1829
				found = true;
1830
				break;
1831
			}
1832
		}
1833
 
1834
		if ( found )
1835
			break;
1836
 
1837
		// skip to next line
1838
		while ( (pos < size) && (data[pos] != '\n') )
1839
			++pos;
1840
		++pos;
1841
 
1842
		if ( pos >= size )
1843
			break;
1844
	}
1845
 
1846
	return iVersion;
1847
}
1848
 
1849
CyString C_File::GetBaseName ()
1850
{
1851
	// remove any directory
1852
	CyString file = m_sName.GetToken ( "/", m_sName.NumToken ( '/' ) );
1853
 
1854
	// remove file extension
1855
	file = file.GetToken ( ".", 1, file.NumToken ( '.' ) - 1 );
1856
 
1857
	return file;
1858
}
1859
 
1860
void C_File::CopyData(C_File *oldFile, bool includeData)
1861
{
1862
	SetFilename(oldFile->GetFullFilename());
1863
	m_sDir = oldFile->GetDir();
1864
	m_tTime = oldFile->GetCreationTime();
1865
	m_bShared = oldFile->IsShared();
1866
	m_bSigned = oldFile->IsSigned();
1867
	m_iFileType = oldFile->GetFileType();
1868
	m_lSize = oldFile->GetSize();
1869
	if ( includeData )
1870
	{
1871
		m_lDataSize = oldFile->GetDataSize();
1872
		if ( m_sData )
1873
			this->DeleteData();
1874
		m_sData = NULL;
1875
		if ( oldFile->GetData() && m_lDataSize )
1876
		{
1877
			m_sData = new unsigned char[m_lDataSize];
1878
			m_bUsedMalloc = false;
1879
			memcpy((char *)m_sData, (char *)oldFile->GetData(), m_lDataSize);
1880
		}
1881
		m_lUncomprDataSize = oldFile->GetUncompressedDataSize();
1882
	}
1883
	m_iDataCompression = oldFile->GetCompressionType();
1884
}
1885
 
1886
float GetLibraryVersion() { return (float)LIBRARYVERSION; }
1887
float GetFileFormatVersion() { return (float)FILEVERSION; }
1888
 
1889
CyString C_File::ChangeFileExt(CyString ext)
1890
{
1891
	m_sName = CFileIO(m_sName).ChangeFileExtension(ext);
1892
	return m_sName;
1893
}
1894
 
1895
bool C_File::CheckPackedExtension()
1896
{
1897
	CyString ext = this->GetFileExt();
1898
	if ( ext == "pck" )
1899
		return true;
1900
	else if ( ext == "pbb" )
1901
		return true;
1902
	else if ( ext == "pbd" )
1903
		return true;
1904
 
1905
	return false;
1906
}
1907
 
1908
bool C_File::BobDecompile()
1909
{
1910
	bool bRes=false;
1911
 
1912
 
1913
	CyStringList outData;
1914
	outData.PushBack("// Converted by SPK Libraries\n");
1915
	/*
1916
	bob_with_errors *e=0;
1917
	char *pszTime;
1918
	char *name="";
1919
 
1920
	time_t tm=time(0);
1921
	pszTime=ctime(&tm);
1922
	pszTime[strlen(pszTime)-1]=0;
1923
 
1924
	clearErrors();
1925
 
1926
	os << "// Converted with x2bc from \"" << is.name() << "\" at " << pszTime << endl;
1927
	if(settings->convert()==false)
1928
		os << "// Raw mode - values are not converted" << endl;
1929
	os << endl;
1930
	*/
1931
	/*
1932
	switch(m_sData[0]){
1933
		case bob_dom_bob::hdr_begin:
1934
			{
1935
				bob_dom_bob *bob = new bob_dom_bob(NULL);
1936
				//bRes=bob->load(is);
1937
				//if(bRes) bRes=bob->toFile(os);
1938
				delete bob;
1939
				break;
1940
			}
1941
		case bob_dom_cut::hdr_begin:
1942
			{
1943
				bob_dom_cut *cut = new bob_dom_cut(NULL);
1944
				//bRes=cut->convert(is, os);
1945
				delete cut;
1946
				break;
1947
			}
1948
		default:
1949
			return false;
1950
	}
1951
 
1952
	if(e){
1953
		for(bob_with_errors::ErrorIterator &it=e->errors.begin(); it!=e->errors.end(); ++it){
1954
			bob_error(it->severity, it->code, "%s->%s", name, it->text);
1955
		}
1956
	}
1957
	return bRes;
1958
 
1959
	bob_dom_ibufferstream<unsigned char> is((const unsigned char *)m_sData, m_lDataSize);
1960
	bob_dom_otextrealfile os;
1961
 
1962
	if(is.fail() || os.fail()) return false;
1963
 
1964
	bool bRes=doc.convert(is, os);*/
1965
 
1966
	return bRes;
1967
}
1968
 
1969
bool C_File::BodCompile()
1970
{
1971
	return true;
1972
}
1973
 
1974
bool C_File::RenameScript(CyString baseName)
1975
{
1976
	if ( !m_sData || !m_lDataSize )
1977
	{
1978
		if ( !this->ReadFromFile() )
1979
			return false;
1980
	}
1981
 
1982
	// uncompress the file
1983
	if ( !this->UncompressData() )
1984
		return false;
1985
 
1986
	// un pck the file
1987
	if ( this->CheckFileExt("pck") )
1988
	{
1989
		if ( !this->UnPCKFile() )
1990
			return false;
1991
	}
1992
 
1993
	// now we should have the raw data
1994
	CyString data((const char *)m_sData);
1995
	data.Truncate(m_lDataSize);
1996
	data = data.FindReplace(this->GetBaseName(), baseName);
1997
 
1998
	this->DeleteData();
1999
	m_sData = new unsigned char[data.Length()];
2000
	memcpy(m_sData, data.c_str(), data.Length());
2001
	m_lDataSize = (long)data.Length();
2002
 
2003
	// repck the file
2004
	if ( this->CheckFileExt("pck") )
2005
	{
2006
		if ( !this->PCKFile() )
2007
			return false;
2008
	}
2009
 
2010
 
2011
	return true;
2012
}