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