Subversion Repositories spk

Rev

Rev 41 | Rev 45 | 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
975
	if ( (!m_sData) || (!m_lDataSize) )
976
		return false;
977
 
978
	if ( m_bCompressedToFile )
979
		return false;
980
 
981
	// if comopression is set to none, dont bother
982
	if ( m_iDataCompression == SPKCOMPRESS_NONE )
983
		return true;
984
 
985
	if ( m_iDataCompression == SPKCOMPRESS_ZLIB )
986
	{
987
		unsigned long uncomprLen = m_lUncomprDataSize;
988
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
989
		int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );
990
		if ( err == Z_OK )
991
		{
992
			DeleteData ();
993
			m_iDataCompression = SPKCOMPRESS_NONE;
994
			m_lDataSize = uncomprLen;
995
			m_sData = uncompr;
996
			return true;
997
		}
998
 
999
		if ( uncompr )
1000
			delete [] uncompr;
1001
	}
1002
	else if ( m_iDataCompression == SPKCOMPRESS_LZMA )
1003
	{
1004
		size_t uncomprLen = m_lUncomprDataSize;
1005
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1006
		SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);
1007
		if ( res == SZ_OK )
1008
		{
1009
			DeleteData ();
1010
			m_iDataCompression = SPKCOMPRESS_NONE;
1011
			m_lDataSize = (long)uncomprLen;
1012
			m_sData = new unsigned char[m_lDataSize];
1013
			memcpy(m_sData, uncompr, m_lDataSize);
1014
			delete uncompr;
1015
			return true;
1016
		}
1017
 
1018
		if ( uncompr )
1019
			delete [] uncompr;
1020
	}
1021
	else if ( m_iDataCompression == SPKCOMPRESS_7ZIP )
1022
	{
1023
		long len = m_lUncomprDataSize;
1024
		unsigned char *compr = LZMADecode_C ( (unsigned char *)m_sData, m_lDataSize, (size_t*)&len, NULL );
1025
		if ( compr )
1026
		{
1027
			DeleteData ();
1028
			m_sData = compr;
1029
			m_lDataSize = len;
1030
			m_iDataCompression = SPKCOMPRESS_NONE;
1031
			return true;
1032
		}
1033
	}
1034
 
1035
	return false;
1036
}
1037
 
1038
unsigned char *C_File::UncompressData ( long *size, CProgressInfo *progress )
1039
{
1040
	// no data to try to uncompress
1041
	if ( (!m_sData) || (!m_lDataSize) )
1042
		return NULL;
1043
 
1044
	//if ( m_bCompressedToFile )
1045
	//	return NULL;
1046
 
1047
	// if comopression is set to none, dont bother
1048
	if ( m_iDataCompression == SPKCOMPRESS_NONE )
1049
	{
1050
		*size = m_lDataSize;
1051
		return m_sData;
1052
	}
1053
 
1054
	if ( m_iDataCompression == SPKCOMPRESS_ZLIB )
1055
	{
1056
		unsigned long uncomprLen = m_lUncomprDataSize;
1057
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1058
		int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );
1059
		if ( err == Z_OK )
1060
		{
1061
			*size = uncomprLen;
1062
			return uncompr;
1063
		}
1064
		if ( uncompr )
1065
			delete [] uncompr;
1066
	}
1067
	if ( m_iDataCompression == SPKCOMPRESS_7ZIP )
1068
	{
1069
		long len = m_lUncomprDataSize;
1070
		unsigned char *compr = LZMADecode_C ( m_sData, m_lDataSize, (size_t *)&len, NULL );
1071
		if ( compr )
1072
		{
1073
			*size = len;
1074
			return compr;
1075
		}
1076
		if ( compr )
1077
			delete [] compr;
1078
	}
1079
	else if ( m_iDataCompression == SPKCOMPRESS_LZMA )
1080
	{
1081
		size_t uncomprLen = m_lUncomprDataSize;
1082
		unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];
1083
		SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);
1084
		if ( res == SZ_OK )
1085
		{
1086
			*size = (long)uncomprLen;
1087
			return uncompr;
1088
		}
1089
		if ( uncompr )
1090
			delete [] uncompr;
1091
	}
1092
 
1093
	return NULL;
1094
}
1095
 
1096
bool C_File::UncompressToFile ( CyString toFile, CBaseFile *spkfile, bool includedir, CProgressInfo *progress )
1097
{
1098
#ifdef _INCLUDE7ZIP
1099
	if ( (!m_sData) || (!m_lDataSize) )
1100
		return false;
1101
	// if theres a tmp file, open it and check it still exists
1102
	if ( !m_sTmpFile.Empty() )
1103
	{
1104
		FILE *id = fopen ( m_sTmpFile.c_str(), "rb" );
1105
		if ( id )
1106
		{
1107
			fclose ( id );
1108
			return true;
1109
		}
1110
		m_sTmpFile = "";
1111
	}
1112
 
1113
	// now uncompress to the file
1114
	CyString file = toFile;
1115
	if ( file.Empty() )
1116
	{
1117
		m_iTempNum++;
1118
		file = CyString("uncompr") + (long)m_iTempNum + ".tmp";
1119
	}
1120
	else
1121
		file = GetFullFileToDir ( file, includedir, spkfile );
1122
 
1123
	FILE *id = fopen ( "compr.tmp", "wb" );
1124
	if ( !id )
1125
		return false;
1126
 
1127
	fwrite ( m_sData, sizeof(unsigned char), m_lDataSize, id );
1128
	bool ret = false;
1129
	int err = ferror(id);
1130
	fclose ( id );
1131
	if ( !err )
1132
	{
1133
		if ( LZMADecodeFile ( "compr.tmp", file.c_str(), (CProgressInfo7Zip *)progress ) )
1134
		{
1135
			ret = true;
1136
			if ( toFile.Empty() )
1137
				m_sTmpFile = file;
1138
		}
1139
	}
1140
 
1141
	remove ( "compr.tmp" );
1142
 
1143
	return ret;
1144
#else
1145
	return false;
1146
#endif
1147
}
1148
 
1149
 
1150
bool C_File::WriteFilePointer ( unsigned char *cData, long len )
1151
{
1152
	return WriteToFile ( GetFilePointer(), cData, len );
1153
}
1154
 
1155
bool C_File::WriteToFile ( CyString filename, unsigned char *cData, long len )
1156
{
1157
	unsigned char *data = cData;
1158
	if ( (!len) || (!data) )
1159
	{
1160
		len = m_lDataSize;
1161
		data = m_sData;
1162
	}
1163
 
1164
	if ( (!len) || (!data) )
1165
		return false;
1166
 
1167
	// check for cat file
1168
	if ( filename.IsIn ( "::" ) )
1169
	{
1170
		CyString catfile = filename.GetToken ( "::", 1, 1 );
1171
		CyString file = filename.GetToken ( "::", 2, 2 );
1172
 
1173
		CCatFile newcat;
1174
		return newcat.AddData ( catfile, data, len, file, true, true );
1175
	}
1176
	else
1177
	{
1178
		CyString filen = filename.FindReplace ( "/", "\\" );
1179
		filen = filen.FindReplace ( "\\\\", "\\" );
1180
 
1181
		FILE *id = fopen ( filen.c_str(), "wb" );
1182
		if ( !id )
1183
			return false;
1184
 
1185
		fwrite ( data, sizeof(unsigned char), len, id );
1186
 
1187
		bool ret = true;
1188
		if ( ferror(id) )
1189
			ret = false;
1190
 
1191
		fclose ( id );
1192
 
1193
		return ret;
1194
	}
1195
 
1196
	return false;
1197
}
1198
 
1199
CyString C_File::GetFullFileToDir ( CyString dir, bool includedir, CBaseFile *file )
1200
{
1201
	CyString fullfile = dir;
1202
	if ( includedir )
1203
	{
1204
		CyString d = GetDirectory ( file );
1205
		if ( !d.Empty() )
1206
		{
1207
			if ( !fullfile.Empty() )
1208
				fullfile += "/";
1209
			fullfile += d;
1210
		}
1211
	}
1212
	if ( !m_sName.Empty() )
1213
	{
1214
		if ( !fullfile.Empty() )
1215
			fullfile += "/";
1216
		fullfile += m_sName;
1217
	}
1218
 
1219
	fullfile = fullfile.FindReplace ( "\\", "/" );
1220
	return fullfile;
1221
}
1222
 
1223
bool C_File::WriteToDir ( CyString &dir, CBaseFile *spkfile, bool includedir, CyString appendDir, unsigned char *data, long len )
1224
{
1225
	CyString fullfile = GetFullFileToDir ( dir, includedir, spkfile );
1226
 
1227
	if ( !appendDir.Empty() )
1228
	{
1229
		if ( !fullfile.Empty() )
1230
			fullfile += "/";
1231
		fullfile += appendDir;
1232
	}
1233
 
1234
	CyString fulldir = fullfile.GetToken ( 1, fullfile.NumToken('/') - 2, '/' );
1235
	if ( !fulldir.Empty() )
1236
	{
1237
		if ( !CDirIO(fulldir).Create() )
1238
			return false;
1239
	}
1240
 
1241
	return WriteToFile ( fullfile, data, len );
1242
}
1243
 
1244
CyString C_File::GetDataSizeString ()
1245
{
1246
	return SPK::GetSizeString ( m_lDataSize );
1247
}
1248
CyString C_File::GetUncompressedSizeString ()
1249
{
1250
	return SPK::GetSizeString ( GetUncompressedDataSize() );
1251
}
1252
 
1253
CyString C_File::GetCreationTimeString ()
1254
{
1255
	if ( !m_tTime )
1256
		return NullString;
1257
 
1258
	struct tm   *currDate;
1259
	char    dateString[100];
1260
 
1261
	time_t n = m_tTime;
1262
 
1263
	currDate = localtime(&n);
1264
 
1265
	strftime(dateString, sizeof dateString, "(%d/%m/%Y) %H:%M", currDate);
1266
 
1267
 
1268
	return CyString(dateString);
1269
}
1270
 
1271
bool C_File::CompareNew ( C_File *file )
1272
{
1273
	if ( !m_iVersion )
1274
		ReadScriptVersion ();
1275
 
1276
	// if version, check if its later version
1277
	if ( (m_iVersion) && (file->GetVersion()) )
1278
	{
1279
		if ( m_iVersion > file->GetVersion() )
1280
			return false;
1281
	}
1282
 
1283
	// now check for last modified time
1284
	if ( (m_tTime) && (file->GetLastModified()) )
1285
	{
1286
		if ( m_tTime > file->GetLastModified() )
1287
			return false;
1288
	}
1289
 
1290
	// assume same or newer
1291
	return true;
1292
}
1293
 
1294
CyString GetFileTypeString ( int type )
1295
{
1296
	switch ( type )
1297
	{
1298
		case FILETYPE_SCRIPT:
1299
			return "Script";
1300
		case FILETYPE_TEXT:
1301
			return "Text";
1302
		case FILETYPE_README:
1303
			return "Readme";
1304
		case FILETYPE_MAP:
1305
			return "Map";
1306
		case FILETYPE_MOD:
1307
			return "Mod";
1308
		case FILETYPE_UNINSTALL:
1309
			return "Uninstall";
1310
		case FILETYPE_SOUND:
1311
			return "Sound";
1312
		case FILETYPE_EXTRA:
1313
			return "Extra";
1314
		case FILETYPE_SCREEN:
1315
			return "Screen";
1316
		case FILETYPE_ADVERT:
1317
			return "Advert";
1318
		case FILETYPE_MISSION:
1319
			return "Mission";
1320
		case FILETYPE_BACKUP:
1321
			return "Backup";
1322
		case FILETYPE_SHIPOTHER:
1323
			return "ShipOther";
1324
		case FILETYPE_SHIPMODEL:
1325
			return "ShipModel";
1326
		case FILETYPE_SHIPSCENE:
1327
			return "ShipScene";
1328
		case FILETYPE_COCKPITSCENE:
1329
			return "CockpitScene";
1330
	}
1331
 
1332
	return NullString;
1333
}
1334
 
1335
int GetFileTypeFromString ( CyString type )
1336
{
1337
	CyString ltype = type.ToLower();
1338
	if ( ltype == "script" )
1339
		return FILETYPE_SCRIPT;
1340
	else if ( ltype == "text" )
1341
		return FILETYPE_TEXT;
1342
	else if ( ltype == "readme" )
1343
		return FILETYPE_README;
1344
	else if ( ltype == "map" )
1345
		return FILETYPE_MAP;
1346
	else if ( ltype == "mod" )
1347
		return FILETYPE_MOD;
1348
	else if ( ltype == "uninstall" )
1349
		return FILETYPE_UNINSTALL;
1350
	else if ( ltype == "sound" )
1351
		return FILETYPE_SOUND;
1352
	else if ( ltype == "extra" )
1353
		return FILETYPE_EXTRA;
1354
	else if ( ltype == "screen" )
1355
		return FILETYPE_SCREEN;
1356
	else if ( ltype == "advert" )
1357
		return FILETYPE_ADVERT;
1358
	else if ( ltype == "mission" )
1359
		return FILETYPE_MISSION;
1360
	else if ( ltype == "backup" )
1361
		return FILETYPE_BACKUP;
1362
	else if ( ltype == "shipother" )
1363
		return FILETYPE_SHIPOTHER;
1364
	else if ( ltype == "shipmodel" )
1365
		return FILETYPE_SHIPMODEL;
1366
	else if ( ltype == "shipscene" )
1367
		return FILETYPE_SHIPSCENE;
1368
	else if ( ltype == "cockpitscene" )
1369
		return FILETYPE_COCKPITSCENE;
1370
 
1371
	return -1;
1372
}
1373
 
1374
 
1375
CyString FormatErrorString(int error, CyString rest)
1376
{
1377
	int max = 0;
1378
	CyString *args = 0;
1379
 
1380
	if ( !rest.Empty() )
1381
		args = rest.SplitToken('~', &max);
1382
 
1383
	CyString errorStr;
1384
	switch ( error )
1385
	{
1386
		case SPKINSTALL_CREATEDIRECTORY:
1387
			errorStr = "Creating Directory: %1";
1388
			break;
1389
		case SPKINSTALL_CREATEDIRECTORY_FAIL:
1390
			errorStr = "Unable to Creating Directory: %1";
1391
			break;
1392
		case SPKINSTALL_WRITEFILE:
1393
			errorStr = "Writing File: %1";
1394
			break;
1395
		case SPKINSTALL_WRITEFILE_FAIL:
1396
			errorStr = "Unable to Write File: %1";
1397
			break;
1398
		case SPKINSTALL_DELETEFILE:
1399
			errorStr = "Deleting File: %1";
1400
			break;
1401
		case SPKINSTALL_DELETEFILE_FAIL:
1402
			errorStr = "Unable to delete File: %1";
1403
			break;
1404
		case SPKINSTALL_REMOVEDIR:
1405
			errorStr = "Removing Directory: %1";
1406
			break;
1407
		case SPKINSTALL_SKIPFILE:
1408
			errorStr = "Skipping File (older): %1";
1409
			break;
1410
		case SPKINSTALL_ENABLEFILE:
1411
			errorStr = "Enabled File: %1";
1412
			break;
1413
		case SPKINSTALL_DISABLEFILE:
1414
			errorStr = "Disabled File: %1";
1415
			break;
1416
		case SPKINSTALL_ENABLEFILE_FAIL:
1417
			errorStr = "Failed to enable File: %1";
1418
			break;
1419
		case SPKINSTALL_DISABLEFILE_FAIL:
1420
			errorStr = "Failed to disable File: %1";
1421
			break;
1422
		case SPKINSTALL_UNINSTALL_MOVE:
1423
			errorStr = "Moving uninstall file: %1";
1424
			break;
1425
		case SPKINSTALL_UNINSTALL_MOVE_FAIL:
1426
			errorStr = "Unable to Move uninstall file: %1";
1427
			break;
1428
		case SPKINSTALL_UNINSTALL_COPY:
1429
			errorStr = "Coping uninstall file: %1";
1430
			break;
1431
		case SPKINSTALL_UNINSTALL_COPY_FAIL:
1432
			errorStr = "Unable to Copy uninstall file: %1";
1433
			break;
1434
		case SPKINSTALL_UNINSTALL_REMOVE:
1435
			errorStr = "Removing Uninstall file: %1";
1436
			break;
1437
		case SPKINSTALL_UNINSTALL_REMOVE_FAIL:
1438
			errorStr = "Unable to remove Uninstall file: %1";
1439
			break;
1440
		case SPKINSTALL_SHARED:
1441
			errorStr = "Removing Unused Shared file: %1";
1442
			break;
1443
		case SPKINSTALL_SHARED_FAIL:
1444
			errorStr = "Unable to remove Unused Shared file: %1";
1445
			break;
1446
		case SPKINSTALL_ORIGINAL_BACKUP:
1447
			errorStr = "Backing up original file: %1";
1448
			break;
1449
		case SPKINSTALL_ORIGINAL_BACKUP_FAIL:
1450
			errorStr = "Unable to back up original file: %1";
1451
			break;
1452
		case SPKINSTALL_ORIGINAL_RESTORE:
1453
			errorStr = "Restoring original file: %1";
1454
			break;
1455
		case SPKINSTALL_ORIGINAL_RESTORE_FAIL:
1456
			errorStr = "Unable to restore original file: %1";
1457
			break;
1458
		case SPKINSTALL_FAKEPATCH:
1459
			errorStr = "Shifted fake patch: %1 to %2";
1460
			break;
1461
		case SPKINSTALL_FAKEPATCH_FAIL:
1462
			errorStr = "Unable to shift fake patch: %1 to %2";
1463
			break;
1464
		case SPKINSTALL_AUTOTEXT:
1465
			errorStr = "Shifted text file: %1 to %2";
1466
			break;
1467
		case SPKINSTALL_AUTOTEXT_FAIL:
1468
			errorStr = "Unable to shift text file: %1 to %2";
1469
			break;
1470
		case SPKINSTALL_MISSINGFILE:
1471
			errorStr = "File is missing: %1";
1472
			break;
1473
		case SPKINSTALL_ORPHANED:
1474
			errorStr = "Orphaned File removed: %1";
1475
			break;
1476
		case SPKINSTALL_ORPHANED_FAIL:
1477
			errorStr = "Unable to remove Orphaned File: %1";
1478
			break;
1479
	}
1480
 
1481
	CyString ret = errorStr.Args(args, max);
1482
	CLEANSPLIT(args, max)
1483
	return ret;
1484
}
1485
 
1486
 
1487
bool C_File::CheckPCK ()
1488
{
1489
	if ( (m_sData) && (m_lDataSize) && (m_iDataCompression == SPKCOMPRESS_NONE) )
1490
		return IsDataPCK ( m_sData, m_lDataSize );
1491
 
1492
	CyString filename = GetFilePointer();
1493
	if ( !filename.Empty() )
1494
	{
1495
		FILE *id = fopen ( filename.c_str(), "rb+" );
1496
		if ( id )
1497
		{
1498
			unsigned char data[3];
1499
			fread ( data, sizeof(unsigned char), 3, id );
1500
			fclose ( id );
1501
 
1502
			return IsDataPCK ( data, 3 );
1503
		}
1504
	}
1505
 
1506
	if ( CheckFileExt("pck") || CheckFileExt("pbb") || CheckFileExt("pbd") )
1507
		return true;
1508
	return false;
1509
}
1510
 
1511
bool C_File::PCKFile()
1512
{
1513
	if ( !m_lDataSize || !m_sData )
1514
	{
1515
		if ( !this->ReadFromFile() )
1516
			return false;
1517
	}
1518
 
1519
	if ( m_lDataSize && m_sData )
1520
	{
1521
		if ( !this->UncompressData() )
1522
			return false;
1523
 
1524
		size_t size;
40 cycrow 1525
		unsigned char *data = PCKData(m_sData, m_lDataSize, &size, false);
1 cycrow 1526
		if ( data && size )
1527
		{
40 cycrow 1528
			m_lUncomprDataSize = m_lDataSize;
1 cycrow 1529
			this->DeleteData();
1530
			m_bUsedMalloc = false;
1531
			m_lDataSize = (long)size;
1532
			m_sData = new unsigned char[size];
1533
			memcpy(m_sData, data, size);
1534
			delete [] data;
1535
		}
1536
 
1537
		return true;
1538
	}
1539
 
1540
	return false;
1541
}
1542
 
1543
unsigned char *C_File::UnPCKFile ( size_t *len )
1544
{
1545
	unsigned char *data = NULL;
1546
	size_t datasize = 0;
1547
 
1548
	if ( CheckValidFilePointer() )
1549
	{
1550
		FILE *id = fopen ( GetFilePointer().c_str(), "rb+" );
1551
		if ( id )
1552
		{
1553
			fseek ( id, 0, SEEK_END );
1554
			datasize = ftell ( id );
1555
			rewind ( id );
1556
 
1557
			data = new unsigned char[datasize];
1558
			fread ( data, sizeof(unsigned char), datasize, id );
1559
			fclose ( id );
1560
		}
1561
	}
1562
 
1563
	if ( !data )
1564
	{
1565
		if ( !m_lDataSize )
1566
		{
1567
			if ( !this->ReadFromFile() )
1568
				return NULL;
1569
		}
1570
		datasize = m_lDataSize;
1571
		data = new unsigned char[datasize];
1572
		memcpy ( data, m_sData, datasize );
1573
	}
1574
 
1575
	if ( data )
1576
	{
1577
		unsigned char *newdata = UnPCKData ( data, datasize, len, CheckPCK() );
1578
		delete data;
1579
		return newdata;
1580
	}
1581
 
1582
	return NULL;
1583
}
1584
 
1585
bool C_File::UnPCKFile()
1586
{
1587
	if ( !m_lDataSize || !m_sData )
1588
	{
1589
		if ( !this->ReadFromFile() )
1590
			return false;
1591
	}
1592
	if ( m_lDataSize && m_sData )
1593
	{
1594
		if ( !this->UncompressData() )
1595
			return false;
1596
 
1597
		size_t size;
1598
		unsigned char *data = UnPCKData(m_sData, m_lDataSize, &size, CheckPCK());
1599
		if ( data && size )
1600
		{
1601
			this->DeleteData();
1602
			m_lUncomprDataSize = m_lDataSize;
1603
			m_bUsedMalloc = false;
1604
			m_sData = new unsigned char[size];
1605
			memcpy(m_sData, data, size);
1606
			m_lDataSize = (long)size;
1607
			delete []data;
1608
		}
1609
 
1610
		return true;
1611
	}
1612
 
1613
	return false;
1614
}
1615
 
1616
unsigned char *UnPCKFile ( const char *file, size_t *len, bool nocrypt )
1617
{
1618
	FILE *id = fopen ( file, "rb" );
1619
	if ( !id )
1620
		return NULL;
1621
 
1622
	fseek ( id, 0, SEEK_END );
1623
	size_t size = ftell ( id );
1624
	fseek ( id, 0, SEEK_SET );
1625
 
1626
	unsigned char *data = new unsigned char[size];
1627
	fread ( data, sizeof(unsigned char), size, id );
1628
 
1629
	if ( ferror(id) )
1630
	{
1631
		delete data;
1632
		data = NULL;
1633
	}
1634
 
1635
	fclose ( id );
1636
 
1637
	if ( data )
1638
	{
1639
		unsigned char *unData = UnPCKData ( data, size, len, nocrypt );
1640
		delete data;
1641
		return unData;
1642
	}
1643
 
1644
	return NULL;
1645
}
1646
 
1647
unsigned char *UnPCKData ( unsigned char *data, size_t datasize, size_t *len ) { return UnPCKData(data, datasize, len, IsDataPCK(data, datasize)); }
1648
unsigned char *UnPCKData ( unsigned char *data, size_t datasize, size_t *len, bool nocrypt )
1649
{
1650
	//IsDataPCK(data, datasize)
1651
	if ( nocrypt )
1652
	{
1653
		unsigned char magic = data[0] ^ 0xC8;
1654
 
1655
		for ( size_t i = 1; i < datasize; i++ )
1656
			data[i] ^= magic;
1657
		++data;
1658
		--datasize;
1659
	}
1660
 
1661
	// create data buffer
1662
	size_t *uncomprLenSize = (size_t*)(data + (datasize - 4));
1663
	unsigned long uncomprLen = (unsigned long)*uncomprLenSize;
1664
	if ( uncomprLen > (datasize * 100) )
1665
	{
1666
		*len = 0;
1667
		return NULL;
1668
	}
41 cycrow 1669
	unsigned char *uncompr = new unsigned char[uncomprLen + 1];
1 cycrow 1670
	if ( !uncompr ) 
1671
		return NULL;
1672
	memset ( uncompr, 0, sizeof(uncompr) );
1673
 
1674
 
1675
	// find header size
1676
	unsigned char *buf = data + PCKHEADERSIZE;
1677
 
1678
//	buf = data + (6 + sizeof(time_t));
1679
	char flag = data[3];
1680
 
1681
	if ( flag & GZ_FLAG_EXTRA )
1682
	{
1683
		size_t xlen = *((short int*)(buf));
1684
		buf += xlen;
1685
	}
1686
 
1687
	if ( flag & GZ_FLAG_FILENAME )
1688
	{
1689
		char *origname = (char*)(buf);
1690
		buf += strlen (origname) + 1;
1691
	}
1692
	if ( flag & GZ_FLAG_COMMENT )
1693
	{
1694
		char *comment = (char*)(buf);
1695
		buf += strlen(comment) + 1;
1696
	}
1697
	if ( flag & GZ_FLAG_HCRC )
1698
		buf += 2;
1699
	long bufSize = (long)(datasize - (buf-data) - 8);
1700
 
1701
	int err = uncompress2 ( uncompr, &uncomprLen, buf, bufSize );
1702
	if ( err != Z_OK )
1703
	{
1704
		delete uncompr;
1705
		*len = 0;
1706
		return NULL;
1707
	}
1708
 
1709
	*len = uncomprLen;
41 cycrow 1710
	uncompr[uncomprLen] = '\0';
1 cycrow 1711
	return uncompr;
1712
}
1713
 
1714
bool IsDataPCK ( const unsigned char *data, size_t size )
1715
{
1716
	if ( size >=3 )
1717
	{
1718
		unsigned char magic=data[0] ^ 0xC8;
1719
		return ((data[1] ^ magic)==0x1F && (data[2] ^ magic)==0x8B);
1720
	}
1721
	else
1722
		return false;
1723
 
1724
}
1725
 
1726
bool ReadSignedFromData ( unsigned char *data, long size )
1727
{
1728
	if ( IsDataPCK ( data, size ) )
1729
	{
1730
		size_t unpckSize = 0;
1731
		unsigned char *unpckData = UnPCKData ( data, size, &unpckSize, false );
1732
		if ( (unpckData) && (unpckSize) )
1733
			return ReadSignedFromData ( unpckData, (long)unpckSize );
1734
		return false;
1735
	}
1736
 
1737
	// work backwards
1738
	int pos = size - 1;
43 cycrow 1739
	int max = size - 5000;
1740
	if ( max < 0 ) max = 0;
1 cycrow 1741
	// find the first tage
43 cycrow 1742
	while ( pos > max )
1 cycrow 1743
	{
1744
		while ( data[pos] != '>' && pos > 0 )
1745
			pos--;
1746
 
43 cycrow 1747
		char tag[10000];
1 cycrow 1748
		bool checked = false;
1749
		if ( data[pos] == '>' )
1750
		{
1751
			int pos2 = pos - 1;
1752
			// now find the front
43 cycrow 1753
			while ( data[pos2] != '<' && pos2 > max )
1 cycrow 1754
				pos2--;
1755
 
1756
			// now get the tag
1757
			if ( data[pos2] == '<' )
1758
			{
1759
				checked = true;
1760
				memcpy(tag, data + pos2, pos - pos2);
1761
				tag[pos - pos2] = '\0';
1762
 
1763
				// check if tag is signed
1764
				CyString sTag(tag);
1765
 
1766
				if ( sTag.Compare("</signature") || sTag.Compare("<signature") )
1767
					return true;
1768
 
1769
				// check if tag is codearray
1770
				if ( sTag.Compare("</codearray") || sTag.Compare("<codearray") )
1771
					return false;
1772
 
1773
				pos = pos2;
1774
			}
1775
 
1776
			--pos;
1777
		}
1778
 
1779
		if ( !checked )
1780
			break;
1781
	}
1782
 
1783
	return false;
1784
}
1785
 
1786
int ReadScriptVersionFromData ( unsigned char *data, long size )
1787
{
1788
	if ( IsDataPCK ( data, size ) )
1789
	{
1790
		size_t unpckSize = 0;
1791
		unsigned char *unpckData = UnPCKData ( data, size, &unpckSize );
1792
		if ( (unpckData) && (unpckSize) )
1793
			return ReadScriptVersionFromData ( unpckData, (long)unpckSize );
1794
		return 0;
1795
	}
1796
 
1797
	int pos = 0;
1798
	bool found = false;
1799
	int iVersion = 0;
1800
 
1801
	// skip past initial space
1802
	while ( !found )
1803
	{
1804
		while ( (pos < size) && (data[pos] == ' ') )
1805
			++pos;
1806
 
1807
		if ( data[pos] == '<' )
1808
		{
1809
			CyString checktag;
1810
			while ( (pos < size) && (data[pos] != '>') )
1811
			{
1812
				checktag += (char)data[pos];
1813
				++pos;
1814
			}
1815
			++pos;
1816
 
1817
			if ( checktag == "<version" )
1818
			{
1819
				CyString version;
1820
				while ( (pos < size) && (data[pos] != '<') )
1821
				{
1822
					version += (char)data[pos];
1823
					++pos;
1824
				}
1825
				iVersion = version.ToInt();
1826
				found = true;
1827
				break;
1828
			}
1829
		}
1830
 
1831
		if ( found )
1832
			break;
1833
 
1834
		// skip to next line
1835
		while ( (pos < size) && (data[pos] != '\n') )
1836
			++pos;
1837
		++pos;
1838
 
1839
		if ( pos >= size )
1840
			break;
1841
	}
1842
 
1843
	return iVersion;
1844
}
1845
 
1846
CyString C_File::GetBaseName ()
1847
{
1848
	// remove any directory
1849
	CyString file = m_sName.GetToken ( "/", m_sName.NumToken ( '/' ) );
1850
 
1851
	// remove file extension
1852
	file = file.GetToken ( ".", 1, file.NumToken ( '.' ) - 1 );
1853
 
1854
	return file;
1855
}
1856
 
1857
void C_File::CopyData(C_File *oldFile, bool includeData)
1858
{
1859
	SetFilename(oldFile->GetFullFilename());
1860
	m_sDir = oldFile->GetDir();
1861
	m_tTime = oldFile->GetCreationTime();
1862
	m_bShared = oldFile->IsShared();
1863
	m_bSigned = oldFile->IsSigned();
1864
	m_iFileType = oldFile->GetFileType();
1865
	m_lSize = oldFile->GetSize();
1866
	if ( includeData )
1867
	{
1868
		m_lDataSize = oldFile->GetDataSize();
1869
		if ( m_sData )
1870
			this->DeleteData();
1871
		m_sData = NULL;
1872
		if ( oldFile->GetData() && m_lDataSize )
1873
		{
1874
			m_sData = new unsigned char[m_lDataSize];
1875
			m_bUsedMalloc = false;
1876
			memcpy((char *)m_sData, (char *)oldFile->GetData(), m_lDataSize);
1877
		}
1878
		m_lUncomprDataSize = oldFile->GetUncompressedDataSize();
1879
	}
1880
	m_iDataCompression = oldFile->GetCompressionType();
1881
}
1882
 
1883
float GetLibraryVersion() { return (float)LIBRARYVERSION; }
1884
float GetFileFormatVersion() { return (float)FILEVERSION; }
1885
 
1886
CyString C_File::ChangeFileExt(CyString ext)
1887
{
1888
	m_sName = CFileIO(m_sName).ChangeFileExtension(ext);
1889
	return m_sName;
1890
}
1891
 
1892
bool C_File::CheckPackedExtension()
1893
{
1894
	CyString ext = this->GetFileExt();
1895
	if ( ext == "pck" )
1896
		return true;
1897
	else if ( ext == "pbb" )
1898
		return true;
1899
	else if ( ext == "pbd" )
1900
		return true;
1901
 
1902
	return false;
1903
}
1904
 
1905
bool C_File::BobDecompile()
1906
{
1907
	bool bRes=false;
1908
 
1909
 
1910
	CyStringList outData;
1911
	outData.PushBack("// Converted by SPK Libraries\n");
1912
	/*
1913
	bob_with_errors *e=0;
1914
	char *pszTime;
1915
	char *name="";
1916
 
1917
	time_t tm=time(0);
1918
	pszTime=ctime(&tm);
1919
	pszTime[strlen(pszTime)-1]=0;
1920
 
1921
	clearErrors();
1922
 
1923
	os << "// Converted with x2bc from \"" << is.name() << "\" at " << pszTime << endl;
1924
	if(settings->convert()==false)
1925
		os << "// Raw mode - values are not converted" << endl;
1926
	os << endl;
1927
	*/
1928
	/*
1929
	switch(m_sData[0]){
1930
		case bob_dom_bob::hdr_begin:
1931
			{
1932
				bob_dom_bob *bob = new bob_dom_bob(NULL);
1933
				//bRes=bob->load(is);
1934
				//if(bRes) bRes=bob->toFile(os);
1935
				delete bob;
1936
				break;
1937
			}
1938
		case bob_dom_cut::hdr_begin:
1939
			{
1940
				bob_dom_cut *cut = new bob_dom_cut(NULL);
1941
				//bRes=cut->convert(is, os);
1942
				delete cut;
1943
				break;
1944
			}
1945
		default:
1946
			return false;
1947
	}
1948
 
1949
	if(e){
1950
		for(bob_with_errors::ErrorIterator &it=e->errors.begin(); it!=e->errors.end(); ++it){
1951
			bob_error(it->severity, it->code, "%s->%s", name, it->text);
1952
		}
1953
	}
1954
	return bRes;
1955
 
1956
	bob_dom_ibufferstream<unsigned char> is((const unsigned char *)m_sData, m_lDataSize);
1957
	bob_dom_otextrealfile os;
1958
 
1959
	if(is.fail() || os.fail()) return false;
1960
 
1961
	bool bRes=doc.convert(is, os);*/
1962
 
1963
	return bRes;
1964
}
1965
 
1966
bool C_File::BodCompile()
1967
{
1968
	return true;
1969
}
1970
 
1971
bool C_File::RenameScript(CyString baseName)
1972
{
1973
	if ( !m_sData || !m_lDataSize )
1974
	{
1975
		if ( !this->ReadFromFile() )
1976
			return false;
1977
	}
1978
 
1979
	// uncompress the file
1980
	if ( !this->UncompressData() )
1981
		return false;
1982
 
1983
	// un pck the file
1984
	if ( this->CheckFileExt("pck") )
1985
	{
1986
		if ( !this->UnPCKFile() )
1987
			return false;
1988
	}
1989
 
1990
	// now we should have the raw data
1991
	CyString data((const char *)m_sData);
1992
	data.Truncate(m_lDataSize);
1993
	data = data.FindReplace(this->GetBaseName(), baseName);
1994
 
1995
	this->DeleteData();
1996
	m_sData = new unsigned char[data.Length()];
1997
	memcpy(m_sData, data.c_str(), data.Length());
1998
	m_lDataSize = (long)data.Length();
1999
 
2000
	// repck the file
2001
	if ( this->CheckFileExt("pck") )
2002
	{
2003
		if ( !this->PCKFile() )
2004
			return false;
2005
	}
2006
 
2007
 
2008
	return true;
2009
}