1 /*
2 Unmass - unpacker for game archives.
3 Copyright (C) 2002-2007 Mirex
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <stdlib.h>
21
22 #include "ma.h"
23 #include "utools.h"
24
CMassArchive()25 CMassArchive::CMassArchive()
26 {
27 massf = NULL; pFileList = NULL; FileListSize = 0;
28 files_count = 0; FileRec.set = 0;
29 next_set = false; next_rec_num = 0;
30 }
31
32 //default extract for plain data
33 //return: bytes read
Extract(unsigned long offset,unsigned long size,unsigned char * output)34 unsigned long CMassArchive::Extract( unsigned long offset, unsigned long size, unsigned char *output )
35 {
36 if ( massf == NULL )
37 return 0;
38
39 if ( offset + size > FileRec.size ) {
40 SetErrorStr( "Out of file" );
41 return 0;
42 }
43
44 //no compression
45 if ( fseek( massf, FileRec.offset + offset, SEEK_SET ) != 0 ) {
46 SetErrorStr( "Error seeking" );
47 return 0;
48 }
49
50 return fread( output, 1, size, massf );
51 }
52
ExtractWholeFile(FILE * fout)53 int CMassArchive::ExtractWholeFile( FILE *fout )
54 {
55 /*
56 pos = 0; size = FF8bufferSize;
57 while ( pos < FileRec.size ) {
58
59 if ( pos + size > FileRec.size )
60 size = FileRec.size - pos;
61
62 if ( fread( buf, 1, size, fs ) != size )
63 return 0;
64
65 if ( fwrite( buf, 1, size, fout ) != size )
66 return 0;
67
68 pos += size;
69 }*/
70 return 0;
71 }
72
OpenFile(const char * filename)73 int CMassArchive::OpenFile( const char *filename )
74 {
75 if ( massf != NULL )
76 fclose( massf );
77
78 massf = fopen( filename, "rb" );
79
80 files_count = 0; FileRec.set = 0;
81 FileListItems = 0;
82 next_set = false; next_rec_num = 0;
83
84 strncpy( MassFileNameFull, filename, FileNameWithPathMaxLen - 1 );
85 // MassFileNameFull[ FileNameWithPathMaxLen-1 ] = 0;
86
87 int i, j;
88
89 //find last slash
90 i = strlen( MassFileNameFull );
91 while (( i > 0 ) && ( MassFileNameFull[ i ] != '\\' ) &&
92 ( MassFileNameFull[ i ] != '/' ))
93 i--;
94 if ( i != 0 )
95 i++;
96
97 // get path from result
98 strncpy( MassFilePath, MassFileNameFull, FileNameWithPathMaxLen-1 );
99 MassFilePath[ i ] = 0;
100
101 // find out filename and extension from the rest
102 strncpy( MassFileName, &MassFileNameFull[ i ], FileNameWithPathMaxLen-1 );
103
104 i = strlen( MassFileName );
105 while (( i > 0 ) && ( MassFileName[ i ] != '.' ))
106 i--;
107
108 if (( i == 0 ) && ( MassFileName[ i ] != '.' ))
109 MassFileExt[ 0 ] = 0;
110 else
111 strncpy( MassFileExt, &MassFileName[ i + 1 ], FileNameWithPathMaxLen-1 );
112 MassFileName[ i ] = 0;
113
114 UnmassTools::_strlwr( MassFileName );
115 UnmassTools::_strlwr( MassFileExt );
116
117 file_open_for_write = false;
118
119 return ( massf != NULL ) ? 1 : 0;
120 }
121
CloseFile()122 void CMassArchive::CloseFile()
123 {
124 if ( massf != NULL )
125 fclose( massf );
126 massf = NULL;
127
128 if ( pFileList != NULL )
129 free( pFileList );
130 pFileList = NULL;
131
132 FileListSize = 0;
133 files_count = 0;
134 }
135
ReadRecords(void)136 int CMassArchive::ReadRecords( void )
137 {
138 if ( massf == NULL ) {
139 SetErrorStr( "File not opened" );
140 return 0;
141 }
142
143 if ( FileListItems >= files_count ) {
144 SetErrorStr( "Already filled" );
145 return 0;
146 }
147
148 int res;
149
150 if ( FileListItems == 0 ) {
151
152 if ( GrowFileList() == 0 )
153 return 0;
154
155 res = ReadRec( 0 );
156 }
157 else
158 res = ReadRec( -1 );
159
160 if ( res == 1 ) {
161 FileRec.index = FileListItems;
162 pFileList[ FileListItems ] = FileRec;
163 } else
164 pFileList[ FileListItems ].Reset();
165
166 FileListItems++;
167
168 return res;
169
170 }
171
GetRec(long num)172 int CMassArchive::GetRec( long num )
173 {
174 if (( num < 0 ) || ( num >= files_count )) {
175 SetErrorStr( "Bad index" );
176 return 0;
177 }
178
179 FileRec = pFileList[ num ];
180 return 1;
181 }
182
AddFileData(unsigned long offset,unsigned long size,char * data)183 int CMassArchive::AddFileData( unsigned long offset, unsigned long size, char* data )
184 {
185 SetErrorStr( "AddFileData:" );
186
187 if ( ! file_open_for_write ) {
188 SetErrorStr( "Not open for writing" );
189 return 0;
190 }
191
192 if (( FileRec.index < 0 ) || ( FileRec.index >= files_count )) {
193 SetErrorStr( "Bad index" );
194 return 0;
195 }
196
197 s_FileRec *pFR;
198
199 pFR = &pFileList[ FileRec.index ];
200
201 if ( offset + size > pFR->size ) {
202 SetErrorStr( "Data out of file" );
203 return 0;
204 }
205
206 fseek( massf, pFR->offset + offset, SEEK_SET );
207 fwrite( data, size, 1, massf );
208
209 return 1;
210 }
211
GrowFileList(void)212 int CMassArchive::GrowFileList( void )
213 {
214 s_FileRec *pNewList;
215 unsigned long ul, oldlistsize;
216
217 if ( files_count <= FileListSize )
218 return 1;
219
220 oldlistsize = FileListSize;
221 if ( FileListSize == 0 )
222 FileListSize = 4;
223
224 while ( FileListSize < files_count )
225 FileListSize *= 2;
226
227 ul = sizeof( FileRec ) * FileListSize;
228 pNewList = (s_FileRec*) realloc( pFileList, ul );
229 if ( pNewList == NULL ) {
230 SetErrorStr( "Not enough memory for new list" );
231 FileListSize = oldlistsize;
232 return 0;
233 }
234 pFileList = pNewList;
235
236 return 1;
237 }
238
ReopenForWriting(void)239 int CMassArchive::ReopenForWriting( void )
240 {
241 SetErrorStr( "ReopenForWriting:" );
242
243 if ( massf == NULL ) {
244 SetErrorStr( "File not opened yet" );
245 return 0;
246 }
247
248 if ( file_open_for_write )
249 return 1;
250
251 fclose( massf );
252
253 massf = fopen( MassFileNameFull, "r+b" );
254
255 if ( massf == NULL ) {
256 SetErrorStr( "File could not be opened. It might be read-only." );
257
258 massf = fopen( MassFileNameFull, "rb" );
259 if ( massf == NULL )
260 SetErrorStr( "Could not open file, neither for reading" );
261 return 0;
262 }
263
264 file_open_for_write = true;
265
266 return 1;
267 }
268
269