Subversion Repositories spk

Rev

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