1 /*
2 * Copyright (c) 2009, The MilkyTracker Team.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * - Neither the name of the <ORGANIZATION> nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 //////////////////////////////////////////////////////////////////////////
31 // System dependent file loading routines //
32 // to make future porting easier //
33 //////////////////////////////////////////////////////////////////////////
34 #include "XMFile.h"
35
XMFileBase()36 XMFileBase::XMFileBase() :
37 baseOffset(0)
38 {
39 }
40
~XMFileBase()41 XMFileBase::~XMFileBase()
42 {
43 }
44
seekWithBaseOffset(mp_dword pos)45 void XMFileBase::seekWithBaseOffset(mp_dword pos)
46 {
47 seek(pos+baseOffset);
48 }
49
sizeWithBaseOffset()50 mp_uint32 XMFileBase::sizeWithBaseOffset()
51 {
52 return size()-baseOffset;
53 }
54
posWithBaseOffset()55 mp_uint32 XMFileBase::posWithBaseOffset()
56 {
57 return pos()-baseOffset;
58 }
59
60 //////////////////////////////////////////////////////////////////////////
61 // Reading/writing of little endian stuff //
62 //////////////////////////////////////////////////////////////////////////
readByte()63 mp_ubyte XMFileBase::readByte()
64 {
65 mp_ubyte c;
66 mp_sint32 bytesRead = read(&c,1,1);
67 //ASSERT(bytesRead == 1);
68
69 if (!(bytesRead == 1))
70 c = 0;
71
72 return (mp_ubyte)c;
73 }
74
readWord()75 mp_uword XMFileBase::readWord()
76 {
77 mp_ubyte c[2];
78 mp_sint32 bytesRead = read(&c,1,2);
79 //ASSERT(bytesRead == 2);
80
81 if (!(bytesRead == 2))
82 c[0] = c[1] = 0;
83
84 return (mp_uword)((mp_uword)c[0]+((mp_uword)c[1]<<8));
85 }
86
readDword()87 mp_dword XMFileBase::readDword()
88 {
89 mp_ubyte c[4];
90 mp_sint32 bytesRead = read(&c,1,4);
91 //ASSERT(bytesRead == 4);
92
93 if (!(bytesRead == 4))
94 c[0] = c[1] = c[2] = c[3] = 0;
95
96 return (mp_dword)((mp_uint32)c[0]+
97 ((mp_uint32)c[1]<<8)+
98 ((mp_uint32)c[2]<<16)+
99 ((mp_uint32)c[3]<<24));
100 }
101
readWords(mp_uword * buffer,mp_sint32 count)102 void XMFileBase::readWords(mp_uword* buffer,mp_sint32 count)
103 {
104 for (mp_sint32 i = 0; i < count; i++)
105 *buffer++ = readWord();
106 }
107
readDwords(mp_dword * buffer,mp_sint32 count)108 void XMFileBase::readDwords(mp_dword* buffer,mp_sint32 count)
109 {
110 for (mp_sint32 i = 0; i < count; i++)
111 *buffer++ = readDword();
112 }
113
writeByte(mp_ubyte b)114 void XMFileBase::writeByte(mp_ubyte b)
115 {
116 mp_sint32 bytesWritten = write(&b, 1, 1);
117 ASSERT(bytesWritten == 1);
118 }
119
writeWord(mp_uword w)120 void XMFileBase::writeWord(mp_uword w)
121 {
122 mp_ubyte c[2];
123 c[0] = (mp_ubyte)w;
124 c[1] = (mp_ubyte)(w>>8);
125 mp_sint32 bytesWritten = write(&c, 1, 2);
126 ASSERT(bytesWritten == 2);
127 }
128
writeDword(mp_dword dw)129 void XMFileBase::writeDword(mp_dword dw)
130 {
131 mp_ubyte c[4];
132 c[0] = (mp_ubyte)dw;
133 c[1] = (mp_ubyte)(dw>>8);
134 c[2] = (mp_ubyte)(dw>>16);
135 c[3] = (mp_ubyte)(dw>>24);
136 mp_sint32 bytesWritten = write(&c, 1, 4);
137 ASSERT(bytesWritten == 4);
138 }
139
writeWords(const mp_uword * buffer,mp_sint32 count)140 void XMFileBase::writeWords(const mp_uword* buffer,mp_sint32 count)
141 {
142 for (mp_sint32 i = 0; i < count; i++)
143 {
144 writeWord(*buffer);
145 buffer++;
146 }
147 }
148
writeDwords(const mp_dword * buffer,mp_sint32 count)149 void XMFileBase::writeDwords(const mp_dword* buffer,mp_sint32 count)
150 {
151 for (mp_sint32 i = 0; i < count; i++)
152 {
153 writeDword(*buffer);
154 buffer++;
155 }
156 }
157
writeString(const char * string)158 void XMFileBase::writeString(const char* string)
159 {
160 write(string, 1, static_cast<mp_uint32> (strlen(string)));
161 }
162
163 #define BUFFERSIZE 16384
164
165 //////////////////////////////////////////////////////////////////////////
166 // WIN32 implentation //
167 //////////////////////////////////////////////////////////////////////////
168 #ifdef WIN32
169
170 #include <tchar.h>
171
XMFile(const SYSCHAR * fileName,bool writeAccess)172 XMFile::XMFile(const SYSCHAR* fileName, bool writeAccess /* = false*/) :
173 XMFileBase(),
174 fileName(fileName),
175 cacheBuffer(NULL)
176 {
177 this->writeAccess = writeAccess;
178
179 bytesRead = 0;
180
181 handle = CreateFile(fileName,
182 writeAccess ? GENERIC_WRITE : GENERIC_READ,
183 writeAccess ? FILE_SHARE_WRITE : FILE_SHARE_READ,
184 NULL,
185 writeAccess ? CREATE_ALWAYS : OPEN_EXISTING,
186 FILE_ATTRIBUTE_NORMAL,
187 NULL);
188
189 //ASSERT(handle != INVALID_HANDLE_VALUE);
190
191 if (writeAccess)
192 {
193 cacheBuffer = new mp_ubyte[BUFFERSIZE+16];
194 currentCacheBufferPtr = cacheBuffer;
195 }
196 }
197
isOpen()198 bool XMFile::isOpen()
199 {
200 return handle != INVALID_HANDLE_VALUE;
201 }
202
~XMFile()203 XMFile::~XMFile()
204 {
205 if (writeAccess && handle != INVALID_HANDLE_VALUE)
206 flush();
207
208 if (cacheBuffer)
209 delete[] cacheBuffer;
210
211 CloseHandle(handle);
212 }
213
read(void * ptr,mp_sint32 size,mp_sint32 count)214 mp_sint32 XMFile::read(void* ptr,mp_sint32 size,mp_sint32 count)
215 {
216 unsigned long NumberOfBytesRead;
217 bool bResult = (bool)ReadFile(handle,ptr,size*count,&NumberOfBytesRead,NULL);
218 bytesRead+=(mp_uint32)NumberOfBytesRead;
219 if (!bResult) return -1;
220 return (mp_sint32)NumberOfBytesRead;
221 }
222
flush()223 void XMFile::flush()
224 {
225 unsigned long NumberOfBytesWritten;
226 bool bResult = (bool)WriteFile(handle,cacheBuffer,
227 currentCacheBufferPtr-cacheBuffer,
228 &NumberOfBytesWritten,
229 NULL);
230 bytesRead+=(mp_uint32)NumberOfBytesWritten;
231 currentCacheBufferPtr = cacheBuffer;
232 }
233
write(const void * ptr,mp_sint32 size,mp_sint32 count)234 mp_sint32 XMFile::write(const void* ptr,mp_sint32 size,mp_sint32 count)
235 {
236 #ifdef DEBUG
237 unsigned long NumberOfBytesWritten;
238 bool bResult = (bool)WriteFile(handle,ptr,size*count,&NumberOfBytesWritten,NULL);
239 bytesRead+=(mp_uint32)NumberOfBytesWritten;
240 if (!bResult) return -1;
241 return (mp_sint32)NumberOfBytesWritten;
242 FlushFileBuffers(handle);
243 #else
244 // Buffer to be written is bigger than our internal cache
245 // => Write through
246 if (size*count > BUFFERSIZE)
247 {
248 // Flush first
249 flush();
250 unsigned long NumberOfBytesWritten;
251 bool bResult = (bool)WriteFile(handle,ptr,size*count,&NumberOfBytesWritten,NULL);
252 bytesRead+=(mp_uint32)NumberOfBytesWritten;
253 if (!bResult) return -1;
254 return (mp_sint32)NumberOfBytesWritten;
255 }
256
257 // Buffer to be written still fits into our cache buffer
258 if (size*count + currentCacheBufferPtr <= cacheBuffer+BUFFERSIZE)
259 {
260 // Copy into cache
261 memcpy(currentCacheBufferPtr, ptr, size*count);
262 // Advance current cache ptr
263 currentCacheBufferPtr += size*count;
264 }
265 else
266 {
267 // Buffer doesn't fit, flush buffer first
268 flush();
269 // Copy into cache
270 memcpy(currentCacheBufferPtr, ptr, size*count);
271 // Advance
272 currentCacheBufferPtr += size*count;
273 }
274
275 if (currentCacheBufferPtr == cacheBuffer + BUFFERSIZE)
276 flush();
277
278 bytesRead+=size*count;
279 return size*count;
280 #endif
281 }
282
seek(mp_uint32 pos,SeekOffsetTypes seekOffsetType)283 void XMFile::seek(mp_uint32 pos, SeekOffsetTypes seekOffsetType/* = SeekOffsetTypeStart*/)
284 {
285 if (writeAccess)
286 {
287 flush();
288 }
289
290 DWORD moveMethod = FILE_BEGIN;
291
292 if (seekOffsetType == XMFile::SeekOffsetTypeCurrent)
293 moveMethod = FILE_CURRENT;
294 else if (seekOffsetType == XMFile::SeekOffsetTypeEnd)
295 moveMethod = FILE_END;
296
297 SetFilePointer(handle, pos, NULL, moveMethod);
298 }
299
pos()300 mp_uint32 XMFile::pos()
301 {
302 return SetFilePointer(handle, 0, NULL, FILE_CURRENT);
303 }
304
size()305 mp_uint32 XMFile::size()
306 {
307 mp_uint32 size = 0;
308 mp_uint32 curPos = pos();
309 SetFilePointer(handle, 0, NULL, FILE_END);
310 size = pos();
311 seek(curPos);
312 return size;
313 }
314
remove(const SYSCHAR * file)315 bool XMFile::remove(const SYSCHAR* file)
316 {
317 return DeleteFile(file);
318 }
319
exists(const SYSCHAR * file)320 bool XMFile::exists(const SYSCHAR* file)
321 {
322 HANDLE handle = CreateFile(file,
323 GENERIC_READ,
324 FILE_SHARE_READ,
325 NULL,
326 OPEN_EXISTING,
327 FILE_ATTRIBUTE_NORMAL,
328 NULL);
329
330 bool res = handle != INVALID_HANDLE_VALUE;
331 if (res)
332 CloseHandle(handle);
333 return res;
334 }
335
getFileNameASCII()336 const char* XMFile::getFileNameASCII()
337 {
338 const SYSCHAR* ptr = fileName+_tcslen(fileName);
339
340 while (*ptr != '\\' && ptr > fileName)
341 ptr--;
342
343 if (*ptr == '\\') ptr++;
344
345 fileNameASCII = new char[_tcslen(ptr)+1];
346
347 for (mp_uint32 i = 0; i <= _tcslen(ptr); i++)
348 fileNameASCII[i] = (char)ptr[i];
349
350 //strcpy(fileNameASCII, ptr);
351
352 return fileNameASCII;
353 }
354
355 //////////////////////////////////////////////////////////////////////////
356 // C compatible implentation //
357 //////////////////////////////////////////////////////////////////////////
358 #else
359
360 #include <unistd.h>
361
XMFile(const SYSCHAR * fileName,bool writeAccess)362 XMFile::XMFile(const SYSCHAR* fileName, bool writeAccess /* = false*/) :
363 XMFileBase(),
364 fileName(fileName),
365 fileNameASCII(NULL),
366 cacheBuffer(NULL)
367 {
368 this->writeAccess = writeAccess;
369
370 bytesRead = 0;
371 handle = fopen(fileName,writeAccess?"wb":"rb");
372
373 //ASSERT(handle != NULL);
374
375 if (writeAccess)
376 {
377 cacheBuffer = new mp_ubyte[BUFFERSIZE];
378 currentCacheBufferPtr = cacheBuffer;
379 }
380 }
381
~XMFile()382 XMFile::~XMFile()
383 {
384 if (writeAccess && handle != NULL)
385 flush();
386
387 if (handle != NULL)
388 fclose(handle);
389
390 if (fileNameASCII)
391 delete[] fileNameASCII;
392
393 if (cacheBuffer)
394 delete[] cacheBuffer;
395 }
396
isOpen()397 bool XMFile::isOpen()
398 {
399 return handle != NULL;
400 }
401
read(void * ptr,mp_sint32 size,mp_sint32 count)402 mp_sint32 XMFile::read(void* ptr, mp_sint32 size, mp_sint32 count)
403 {
404 unsigned long NumberOfBytesRead = fread(ptr,size,count,handle)*size;
405 bytesRead += NumberOfBytesRead;
406 return (mp_sint32)NumberOfBytesRead;
407 }
408
flush()409 void XMFile::flush()
410 {
411 fwrite(cacheBuffer, 1, currentCacheBufferPtr-cacheBuffer, handle);
412 currentCacheBufferPtr = cacheBuffer;
413 }
414
write(const void * ptr,mp_sint32 size,mp_sint32 count)415 mp_sint32 XMFile::write(const void* ptr, mp_sint32 size, mp_sint32 count)
416 {
417 // Buffer to be written is bigger than our internal cache
418 // => Write through
419 if (size*count > BUFFERSIZE)
420 {
421 // Flush first
422 flush();
423 unsigned long NumberOfBytesWritten = fwrite(ptr,size,count,handle)*size;
424 bytesRead += NumberOfBytesWritten;
425 return (mp_sint32)NumberOfBytesWritten;
426 }
427
428 // Buffer to be written still fits into our cache buffer
429 if (size*count + currentCacheBufferPtr <= cacheBuffer+BUFFERSIZE)
430 {
431 // Copy into cache
432 memcpy(currentCacheBufferPtr, ptr, size*count);
433 // Advance current cache ptr
434 currentCacheBufferPtr += size*count;
435 }
436 else
437 {
438 // Buffer doesn't fit, flush buffer first
439 flush();
440 // Copy into cache
441 memcpy(currentCacheBufferPtr, ptr, size*count);
442 // Advance
443 currentCacheBufferPtr += size*count;
444 }
445
446 if (currentCacheBufferPtr == cacheBuffer + BUFFERSIZE)
447 flush();
448
449 bytesRead+=size*count;
450 return size*count;
451 }
452
seek(mp_uint32 pos,SeekOffsetTypes seekOffsetType)453 void XMFile::seek(mp_uint32 pos, SeekOffsetTypes seekOffsetType/* = SeekOffsetTypeStart*/)
454 {
455 if (writeAccess)
456 {
457 flush();
458 fflush(handle);
459 }
460
461 int moveMethod = SEEK_SET;
462
463 if (seekOffsetType == XMFile::SeekOffsetTypeCurrent)
464 moveMethod = SEEK_CUR;
465 else if (seekOffsetType == XMFile::SeekOffsetTypeEnd)
466 moveMethod = SEEK_END;
467
468 fseek(handle,pos,moveMethod);
469 }
470
pos()471 mp_uint32 XMFile::pos()
472 {
473 return static_cast<mp_uint32>(ftell(handle));
474 }
475
size()476 mp_uint32 XMFile::size()
477 {
478 mp_uint32 size = 0;
479 mp_uint32 curPos = pos();
480 fseek(handle,0,SEEK_END);
481 size = pos();
482 seek(curPos);
483 return size;
484 }
485
exists(const SYSCHAR * file)486 bool XMFile::exists(const SYSCHAR* file)
487 {
488 FHANDLE handle = fopen(file,"rb");
489 bool res = handle != NULL;
490 if (res)
491 fclose(handle);
492 return res;
493 }
494
remove(const SYSCHAR * file)495 bool XMFile::remove(const SYSCHAR* file)
496 {
497 return unlink(file) == 0;
498 }
499
getFileNameASCII()500 const char* XMFile::getFileNameASCII()
501 {
502 const SYSCHAR* ptr = fileName+strlen(fileName);
503
504 while (*ptr != '/' && ptr > fileName)
505 ptr--;
506
507 if (*ptr == '/') ptr++;
508
509 fileNameASCII = new char[strlen(ptr)+1];
510
511 strcpy(fileNameASCII, ptr);
512
513 return fileNameASCII;
514 }
515
516 #endif
517