1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #define _CFILE_INTERNAL
13 
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdio.h>
17 
18 #ifdef _WIN32
19 #include <io.h>
20 #include <direct.h>
21 #include <windows.h>
22 #include <winbase.h>		/* needed for memory mapping of file functions */
23 #endif
24 
25 #include "cfile/cfile.h"
26 #include "cfile/cfilearchive.h"
27 #include "luaconf.h"
28 
29 #include <sstream>
30 
31 
32 #define CHECK_POSITION
33 
34 // Called once to setup the low-level reading code.
35 
cf_init_lowlevel_read_code(CFILE * cfile,int lib_offset,int size,int pos)36 void cf_init_lowlevel_read_code( CFILE * cfile, int lib_offset, int size, int pos )
37 {
38 	Assert(cfile != NULL);
39 
40 	Cfile_block *cb;
41 	Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
42 	cb = &Cfile_block_list[cfile->id];
43 
44 	cb->lib_offset = lib_offset;
45 	cb->raw_position = pos;
46 	cb->size = size;
47 
48 	if ( cb->fp )	{
49 		if ( cb->lib_offset )	{
50 			fseek( cb->fp, cb->lib_offset, SEEK_SET );
51 		}
52 
53 		#if defined(CHECK_POSITION) && !defined(NDEBUG)
54 			int raw_position;
55 			raw_position = ftell(cb->fp) - cb->lib_offset;
56 			Assert(raw_position == cb->raw_position);
57 		#endif
58 	}
59 }
60 
61 
62 
63 // cfeof() Tests for end-of-file on a stream
64 //
65 // returns a nonzero value after the first read operation that attempts to read
66 // past the end of the file. It returns 0 if the current position is not end of file.
67 // There is no error return.
68 
cfeof(CFILE * cfile)69 int cfeof(CFILE *cfile)
70 {
71 	Assert(cfile != NULL);
72 
73 	Cfile_block *cb;
74 	Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
75 	cb = &Cfile_block_list[cfile->id];
76 
77 	int result;
78 
79 	result = 0;
80 
81 	// cfeof() not supported for memory-mapped files
82 	Assert( !cb->data );
83 
84 	Assert(cb->fp != NULL);
85 
86 	#if defined(CHECK_POSITION) && !defined(NDEBUG)
87 		int raw_position;
88 		raw_position = ftell(cb->fp) - cb->lib_offset;
89 		Assert(raw_position == cb->raw_position);
90 	#endif
91 
92 	if (cb->raw_position >= cb->size ) {
93 		result = 1;
94 	} else {
95 		result = 0;
96 	}
97 
98 	return result;
99 }
100 
101 // cftell() returns offset into file
102 //
103 // returns:  success ==> offset into the file
104 //           error   ==> -1
105 //
cftell(CFILE * cfile)106 int cftell( CFILE * cfile )
107 {
108 	Assert(cfile != NULL);
109 	Cfile_block *cb;
110 	Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
111 	cb = &Cfile_block_list[cfile->id];
112 
113 	// Doesn't work for memory mapped files
114 	Assert( !cb->data );
115 
116 	Assert(cb->fp != NULL);
117 
118 	#if defined(CHECK_POSITION) && !defined(NDEBUG)
119 		int raw_position;
120 		raw_position = ftell(cb->fp) - cb->lib_offset;
121 		Assert(raw_position == cb->raw_position);
122 	#endif
123 
124 	return cb->raw_position;
125 }
126 
127 
128 // cfseek() moves the file pointer
129 //
130 // returns:   success ==> 0
131 //            error   ==> non-zero
132 //
cfseek(CFILE * cfile,int offset,int where)133 int cfseek( CFILE *cfile, int offset, int where )
134 {
135 
136 	Assert(cfile != NULL);
137 	Cfile_block *cb;
138 	Assert(cfile->id >= 0 && cfile->id < MAX_CFILE_BLOCKS);
139 	cb = &Cfile_block_list[cfile->id];
140 
141 
142 	// TODO: seek to offset in memory mapped file
143 	Assert( !cb->data );
144 	Assert( cb->fp != NULL );
145 
146 	int goal_position;
147 
148 	switch( where )	{
149 	case CF_SEEK_SET:
150 		goal_position = offset+cb->lib_offset;
151 		break;
152 	case CF_SEEK_CUR:
153 		{
154 			goal_position = cb->raw_position+offset+cb->lib_offset;
155 		}
156 		break;
157 	case CF_SEEK_END:
158 		goal_position = cb->size+offset+cb->lib_offset;
159 		break;
160 	default:
161 		Int3();
162 		return 1;
163 	}
164 
165 	int result = fseek(cb->fp, goal_position, SEEK_SET );
166 	cb->raw_position = goal_position - cb->lib_offset;
167 
168 	#if defined(CHECK_POSITION) && !defined(NDEBUG)
169 		int tmp_offset;
170 		tmp_offset = (int)ftell(cb->fp) - cb->lib_offset;
171 		Assert(tmp_offset==cb->raw_position);
172 	#endif
173 
174 	return result;
175 }
176 
177 
178 // cfread() reads from a file
179 //
180 // returns:   returns the number of full elements read
181 //
182 //
cfread(void * buf,int elsize,int nelem,CFILE * cfile)183 int cfread(void *buf, int elsize, int nelem, CFILE *cfile)
184 {
185 	if(!cf_is_valid(cfile))
186 		return 0;
187 
188 	int size = elsize*nelem;
189 
190 	if(buf == NULL || size <= 0)
191 		return 0;
192 
193 	Cfile_block *cb = &Cfile_block_list[cfile->id];
194 
195 	// cfread() not supported for memory-mapped files
196 	if(cb->data != NULL)
197 	{
198 		Warning(LOCATION, "Writing is not supported for mem-mapped files");
199 		return 0;
200 	}
201 
202 	if ( (cb->raw_position+size) > cb->size ) {
203 		size = cb->size - cb->raw_position;
204 		if ( size < 1 ) {
205 			return 0;
206 		}
207 		//mprintf(( "CFILE: EOF encountered in file\n" ));
208 	}
209 
210 	if (cb->max_read_len) {
211 		if ( (size_t)(cb->raw_position+size) > cb->max_read_len ) {
212 			std::ostringstream s_buf;
213 			s_buf << "Attempted to read " << size << "-byte(s) beyond length limit";
214 
215 			throw cfile::max_read_length(s_buf.str());
216 		}
217 	}
218 
219 	int bytes_read = fread( buf, 1, size, cb->fp );
220 	if ( bytes_read > 0 )	{
221 		cb->raw_position += bytes_read;
222 	}
223 
224 	#if defined(CHECK_POSITION) && !defined(NDEBUG)
225 		int tmp_offset;
226 		tmp_offset = ftell(cb->fp) - cb->lib_offset;
227 		Assert(tmp_offset==cb->raw_position);
228 	#endif
229 
230 	return bytes_read / elsize;
231 
232 }
233 
cfread_lua_number(double * buf,CFILE * cfile)234 int cfread_lua_number(double *buf, CFILE *cfile)
235 {
236 	if(!cf_is_valid(cfile))
237 		return 0;
238 
239 	if(buf == NULL)
240 		return 0;
241 
242 	Cfile_block *cb = &Cfile_block_list[cfile->id];
243 
244 	// cfread() not supported for memory-mapped files
245 	if(cb->data != NULL)
246 	{
247 		Warning(LOCATION, "Writing is not supported for mem-mapped files");
248 		return 0;
249 	}
250 
251 	long orig_pos = ftell(cb->fp);
252 	int items_read = fscanf(cb->fp, LUA_NUMBER_SCAN, buf);
253 	cb->raw_position += ftell(cb->fp)-orig_pos;
254 
255 	#if defined(CHECK_POSITION) && !defined(NDEBUG)
256 		int tmp_offset;
257 		tmp_offset = ftell(cb->fp) - cb->lib_offset;
258 		Assert(tmp_offset==cb->raw_position);
259 	#endif
260 
261 	return items_read;
262 
263 }
264 
265