FileStream: Fix potential segfault
[gemrb.git] / gemrb / core / System / FileStream.cpp
blob6129dfbd14f516dc7b303fed2912cc995925ac81
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "System/FileStream.h"
23 #include "win32def.h"
25 #include "Interface.h"
27 FileStream::FileStream(void)
29 opened = false;
30 created = false;
31 str = NULL;
32 autoFree = false;
35 FileStream::~FileStream(void)
37 if (autoFree && str) {
38 #ifdef _DEBUG
39 core->FileStreamPtrCount--;
40 #endif
41 _fclose( str );
43 str = NULL;
46 bool FileStream::Open(const char* fname, bool aF)
48 if (str && autoFree) {
49 #ifdef _DEBUG
50 core->FileStreamPtrCount--;
51 #endif
52 _fclose( str );
53 str = NULL;
55 autoFree = aF;
56 str = _fopen( fname, "rb" );
57 if (str == NULL) {
58 return false;
60 #ifdef _DEBUG
61 core->FileStreamPtrCount++;
62 #endif
63 startpos = 0;
64 opened = true;
65 created = false;
66 //FIXME: this is a very lame way to tell the file length
67 _fseek( str, 0, SEEK_END );
68 size = _ftell( str );
69 _fseek( str, 0, SEEK_SET );
70 ExtractFileFromPath( filename, fname );
71 strncpy( originalfile, fname, _MAX_PATH);
72 Pos = 0;
73 return true;
76 bool FileStream::Modify(const char* fname, bool aF)
78 if (str && autoFree) {
79 #ifdef _DEBUG
80 core->FileStreamPtrCount--;
81 #endif
82 _fclose( str );
84 autoFree = aF;
85 str = _fopen( fname, "r+b" );
86 if (str == NULL) {
87 return false;
89 #ifdef _DEBUG
90 core->FileStreamPtrCount++;
91 #endif
92 startpos = 0;
93 opened = true;
94 created = true;
95 //FIXME: this is a very lame way to tell the file length
96 _fseek( str, 0, SEEK_END );
97 size = _ftell( str );
98 _fseek( str, 0, SEEK_SET );
99 ExtractFileFromPath( filename, fname );
100 strncpy( originalfile, fname, _MAX_PATH);
101 Pos = 0;
102 return true;
105 bool FileStream::Open(_FILE* stream, int spos, int maxsize, bool aF)
107 if (str && autoFree) {
108 #ifdef _DEBUG
109 core->FileStreamPtrCount--;
110 #endif
111 _fclose( str );
113 autoFree = aF;
114 str = stream;
115 if (str == NULL) {
116 return false;
118 #ifdef _DEBUG
119 core->FileStreamPtrCount++;
120 #endif
121 startpos = spos;
122 opened = true;
123 created = false;
124 size = maxsize;
125 filename[0]=0;
126 originalfile[0]=0;
127 _fseek( str, spos, SEEK_SET );
128 Pos = 0;
129 return true;
132 //Creating file in the cache
133 //Create is ALWAYS autofree
134 bool FileStream::Create(const char* fname, SClass_ID ClassID)
136 return Create(core->CachePath, fname, ClassID);
139 //Creating file outside of the cache
140 bool FileStream::Create(const char *folder, const char* fname, SClass_ID ClassID)
142 if (str && autoFree) {
143 #ifdef _DEBUG
144 core->FileStreamPtrCount--;
145 #endif
146 _fclose( str );
148 autoFree = true;
149 ExtractFileFromPath( filename, fname );
150 strcpy( originalfile, folder );
151 strcat( originalfile, SPathDelimiter);
152 strcat( originalfile, filename );
153 strcat( originalfile, core->TypeExt( ClassID ) );
154 str = _fopen( originalfile, "wb" );
155 if (str == NULL) {
156 return false;
158 opened = true;
159 created = true;
160 Pos = 0;
161 size = 0;
162 startpos = 0;
163 return true;
166 int FileStream::Read(void* dest, unsigned int length)
168 if (!opened) {
169 return GEM_ERROR;
171 //we don't allow partial reads anyway, so it isn't a problem that
172 //i don't adjust length here (partial reads are evil)
173 if (Pos+length>size ) {
174 return GEM_ERROR;
176 size_t c = _fread( dest, 1, length, str );
177 if (c != length) {
178 return GEM_ERROR;
180 if (Encrypted) {
181 ReadDecrypted( dest, c );
183 Pos += c;
184 return c;
187 int FileStream::Write(const void* src, unsigned int length)
189 if (!created) {
190 return GEM_ERROR;
192 // do encryption here if needed
194 size_t c = _fwrite( src, 1, length, str );
195 if (c != length) {
196 return GEM_ERROR;
198 Pos += c;
199 if (Pos>size) {
200 size = Pos;
202 return c;
205 int FileStream::Seek(int newpos, int type)
207 if (!opened && !created) {
208 return GEM_ERROR;
210 switch (type) {
211 case GEM_STREAM_END:
212 _fseek( str, startpos + size - newpos, SEEK_SET);
213 Pos = size - newpos;
214 break;
215 case GEM_CURRENT_POS:
216 _fseek( str, newpos, SEEK_CUR );
217 Pos += newpos;
218 break;
220 case GEM_STREAM_START:
221 _fseek( str, startpos + newpos, SEEK_SET );
222 Pos = newpos;
223 break;
225 default:
226 return GEM_ERROR;
228 if (Pos>size) {
229 printf("[Streams]: Invalid seek position: %ld (limit: %ld)\n",Pos, size);
230 return GEM_ERROR;
232 return GEM_OK;
235 /** No descriptions */
236 int FileStream::ReadLine(void* buf, unsigned int maxlen)
238 if(!maxlen) {
239 return 0;
241 unsigned char * p = ( unsigned char * ) buf;
242 if (_feof( str )) {
243 p[0]=0;
244 return -1;
246 if (Pos >= size) {
247 p[0]=0;
248 return -1;
250 unsigned int i = 0;
251 while (i < ( maxlen - 1 )) {
252 int ch = _fgetc( str );
253 if (Pos == size)
254 break;
255 if (Encrypted) {
256 ch ^= GEM_ENCRYPTION_KEY[Pos & 63];
258 Pos++;
259 if (( ( char ) ch ) == '\n')
260 break;
261 if (( ( char ) ch ) == '\t')
262 ch = ' ';
263 if (( ( char ) ch ) != '\r')
264 p[i++] = ch;
265 //Warning:this feof implementation reads forward one byte
266 if (_feof( str ))
267 break;
269 p[i] = 0;
270 return i;
273 unsigned long FileStream::GetStartPos() const
275 return startpos;