diff options
| author | Alejandro Marzini | 2010-06-08 03:31:27 +0000 | 
|---|---|---|
| committer | Alejandro Marzini | 2010-06-08 03:31:27 +0000 | 
| commit | 7ea78b10364d34ae607a9a1da00e4d42ad691aa1 (patch) | |
| tree | c16c3d224b2ad1179dbf3e7c54b5c0212b0581a4 /backends/fs/psp/psp-stream.cpp | |
| parent | 7e9d54a69a3444f5335b8cf6ecabdeffe2830644 (diff) | |
| parent | ea2e2053f25c216342c74bb7a74dabc682766720 (diff) | |
| download | scummvm-rg350-7ea78b10364d34ae607a9a1da00e4d42ad691aa1.tar.gz scummvm-rg350-7ea78b10364d34ae607a9a1da00e4d42ad691aa1.tar.bz2 scummvm-rg350-7ea78b10364d34ae607a9a1da00e4d42ad691aa1.zip  | |
Merged from trunk.
svn-id: r49499
Diffstat (limited to 'backends/fs/psp/psp-stream.cpp')
| -rw-r--r-- | backends/fs/psp/psp-stream.cpp | 294 | 
1 files changed, 214 insertions, 80 deletions
diff --git a/backends/fs/psp/psp-stream.cpp b/backends/fs/psp/psp-stream.cpp index 8cb7dfea17..83ff095aa8 100644 --- a/backends/fs/psp/psp-stream.cpp +++ b/backends/fs/psp/psp-stream.cpp @@ -24,6 +24,8 @@   */  #ifdef __PSP__ +#include <pspiofilemgr_stat.h> +#include <pspiofilemgr.h>  #include <SDL/SDL_thread.h>  #include <SDL/SDL_mutex.h> @@ -32,28 +34,48 @@  #include <errno.h> -//#define __PSP_PRINT_TO_FILE__ -//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */ +#define MIN2(a,b) ((a < b) ? a : b) +#define MIN3(a,b,c) ( (a < b) ? (a < c ? a : c) : (b < c ? b : c) ) + +//#define __PSP_PRINT_TO_FILE__ /* For debugging suspend stuff, we have no screen output */ +//#define __PSP_DEBUG_FUNCS__ 	/* For debugging function calls */  //#define __PSP_DEBUG_PRINT__	/* For debug printouts */ +  #include "backends/platform/psp/trace.h" +//#define DEBUG_BUFFERS					/* to see the contents of the buffers being read */ + +#ifdef DEBUG_BUFFERS +void printBuffer(byte *ptr, uint32 len) { +	uint32 printLen = len <= 10 ? len : 10; +	 +	for (int i = 0; i < printLen; i++) { +		PSP_INFO_PRINT("%x ", ptr[i]);		 +	} +	 +	if (len > 10) { +		PSP_INFO_PRINT("... "); +		for (int i = len - 10; i < len; i++) +			PSP_INFO_PRINT("%x ", ptr[i]); +	} +	 +	PSP_INFO_PRINT("\n"); +} +#endif + +  PSPIoStream::PSPIoStream(const Common::String &path, bool writeMode) -		: StdioStream((void *)1), _path(path), _writeMode(writeMode) { +		: StdioStream((void *)1), _path(path), _writeMode(writeMode), +		  _ferror(false), _pos(0), +		  _physicalPos(0), _fileSize(0), _inCache(false), _eos(false), +		  _cacheStartOffset(-1), _cache(0), +		  _errorSuspend(0), _errorSource(0), +		  _errorPos(0), _errorHandle(0), _suspendCount(0) {  	DEBUG_ENTER_FUNC(); -	assert(!path.empty()); +	// assert(!path.empty());	// do we need this?  	_handle = (void *)0;		// Need to do this since base class asserts not 0. -	_ferror = false; -	_feof = false; -	_pos = 0; - -	/* for error checking */ -	_errorSuspend = 0; -	_errorSource = 0; -	_errorPos = 0; -	_errorHandle = 0; -	_suspendCount = 0;  }  PSPIoStream::~PSPIoStream() { @@ -63,9 +85,12 @@ PSPIoStream::~PSPIoStream() {  		PSP_DEBUG_PRINT_FUNC("Suspended\n");  	PowerMan.unregisterSuspend(this); // Unregister with powermanager to be suspended -	// Must do this before fclose() or resume() will reopen. +									  // Must do this before fclose() or resume() will reopen. -	fclose((FILE *)_handle);	// We don't need a critical section(?). Worst case, the handle gets closed on its own +	fclose((FILE *)_handle);		  // We don't need a critical section. Worst case, the handle gets closed on its own +	 +	if (_cache) +		free(_cache);  	PowerMan.endCriticalSection();  } @@ -82,6 +107,17 @@ void *PSPIoStream::open() {  	_handle = fopen(_path.c_str(), _writeMode ? "wb" : "rb"); 	// open +	if (_handle) { +		// Get the file size. This way is much faster than going to the end of the file and back +		SceIoStat stat; +		sceIoGetstat(_path.c_str(), &stat); +		_fileSize = *((uint32 *)(void *)&stat.st_size);	// 4GB file is big enough for us +		PSP_DEBUG_PRINT("%s filesize = %d\n", _path.c_str(), _fileSize); +	 +		// Allocate the cache +		_cache = (char *)memalign(64, CACHE_SIZE); +	} +  	PowerMan.registerSuspend(this);	 // Register with the powermanager to be suspended  	PowerMan.endCriticalSection(); @@ -91,100 +127,183 @@ void *PSPIoStream::open() {  bool PSPIoStream::err() const {  	DEBUG_ENTER_FUNC(); -	if (_ferror) -		PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], _errorPos[%d], _errorHandle[%p], suspendCount[%d]\n", -		          _ferror, _errorSource, _errorSuspend, _pos, _errorPos, _errorHandle, _suspendCount); +	 +	if (_ferror)	// We dump since no printing to screen with suspend +		PSP_ERROR("mem_ferror[%d], source[%d], suspend error[%d], pos[%d], \ +		_errorPos[%d], _errorHandle[%p], suspendCount[%d]\n", +		          _ferror, _errorSource, _errorSuspend, _pos, +				  _errorPos, _errorHandle, _suspendCount);  	return _ferror;  }  void PSPIoStream::clearErr() { -	_ferror = false;	// Remove regular error bit +	_ferror = false;  }  bool PSPIoStream::eos() const { -	return _feof; +	return _eos;  }  int32 PSPIoStream::pos() const {  	return _pos;  } -  int32 PSPIoStream::size() const { -	DEBUG_ENTER_FUNC(); -	if (PowerMan.beginCriticalSection() == PowerManager::Blocked) -		PSP_DEBUG_PRINT_FUNC("Suspended\n"); - -	fseek((FILE *)_handle, 0, SEEK_END); -	int32 length = ftell((FILE *)_handle); -	fseek((FILE *)_handle, _pos, SEEK_SET); - -	if (_pos < 0 || length < 0) {	// Check for errors -		_errorSource = 2; -		PSP_ERROR("pos[%d] or length[%d] < 0!\n", _pos, length); -		_ferror = true; -		length = -1;				// If our oldPos is bad, we want length to be bad too to signal -		clearerr((FILE *)_handle); -	} - -	PowerMan.endCriticalSection(); - -	return length; +	return _fileSize;  }  bool PSPIoStream::seek(int32 offs, int whence) {  	DEBUG_ENTER_FUNC(); - -	// Check if we can access the file -	if (PowerMan.beginCriticalSection() == PowerManager::Blocked) -		PSP_DEBUG_PRINT_FUNC("Suspended\n"); - -	int ret = fseek((FILE *)_handle, offs, whence); - -	if (ret != 0) { +	PSP_DEBUG_PRINT_FUNC("offset[0x%x], whence[%d], _pos[0x%x], _physPos[0x%x]\n", offs, whence, _pos, _physicalPos); +	_eos = false; +	 +	int32 posToSearchFor = 0; +	switch (whence) { +	case SEEK_CUR: +		posToSearchFor = _pos; +		break; +	case SEEK_END: +		posToSearchFor = _fileSize;	// unsure. Does it take us here or to EOS - 1? +		break; +	} +	posToSearchFor += offs; +	 +	// Check for bad values +	if (posToSearchFor < 0) {  		_ferror = true; -		PSP_ERROR("fseek returned with [%d], non-zero\n", ret); -		clearerr((FILE *)_handle); -		_feof = feof((FILE *)_handle); -		_errorSource = 3; -	} else {					// everything ok -		_feof = false;		// Reset eof flag since we know it was ok +		return false;  	} - -	_pos = ftell((FILE *)_handle);	// update pos - -	PowerMan.endCriticalSection(); - -	return (ret == 0); +	 +	if (posToSearchFor > _fileSize) { +		_ferror = true; +		_eos = true; +		return false; +	} +	 +	// See if we can find it in cache +	if (isOffsetInCache(posToSearchFor)) { +		PSP_DEBUG_PRINT("seek offset[0x%x] found in cache. Cache starts[0x%x]\n", posToSearchFor, _cacheStartOffset); +		_inCache = true;		 +	} else {	// not in cache +		_inCache = false;		 +	}	 +	_pos = posToSearchFor;		 +	return true;  }  uint32 PSPIoStream::read(void *ptr, uint32 len) {  	DEBUG_ENTER_FUNC(); -	// Check if we can access the file +	PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x], ptr[%p]\n", _path.c_str(), len, ptr); + +	if (_ferror || _eos) +		return 0; +		 +	byte *destPtr = (byte *)ptr; +	uint32 lenFromFile = len;		// how much we read from the actual file +	uint32 lenFromCache = 0;		// how much we read from cache +	uint32 lenRemainingInFile = _fileSize - _pos; +	 +	if (lenFromFile > lenRemainingInFile) { +		lenFromFile = lenRemainingInFile; +		_eos = true; +	}	 +	 +	// Are we in cache? +	if (_inCache && isCacheValid()) { +		uint32 offsetInCache = _pos - _cacheStartOffset; +		// We can read at most what's in the cache or the remaining size of the file +		lenFromCache = MIN2(lenFromFile, CACHE_SIZE - offsetInCache); // unsure +		 +		PSP_DEBUG_PRINT("reading 0x%x bytes from cache to %p. pos[0x%x] physPos[0x%x] cacheStart[0x%x]\n", lenFromCache, destPtr, _pos, _physicalPos, _cacheStartOffset); +		 +		memcpy(destPtr, &_cache[offsetInCache], lenFromCache); +		_pos += lenFromCache;		 +		 +		if (lenFromCache < lenFromFile) {	// there's more to copy from the file +			lenFromFile -= lenFromCache; +			lenRemainingInFile -= lenFromCache;	// since we moved pos +			destPtr += lenFromCache; +		} else {							// we're done +#ifdef DEBUG_BUFFERS +			printBuffer((byte *)ptr, len); +#endif			 +			 +			return lenFromCache;			// how much we actually read +		}		 +	} +  	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)  		PSP_DEBUG_PRINT_FUNC("Suspended\n"); - -	PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len); - -	size_t ret = fread((byte *)ptr, 1, len, (FILE *)_handle); - -	_pos += ret;	// Update pos - -	if (ret != len) {	// Check for eof -		_feof = feof((FILE *)_handle); -		if (!_feof) {	// It wasn't an eof. Must be an error +	 +	 +	synchronizePhysicalPos();	// we need to update our physical position +	 +	if (lenFromFile <= MIN_READ_SIZE) {	// We load the cache in case the read is small enough +		// This optimization is based on the principle that reading 1 byte is as expensive as 1000 bytes +		uint32 lenToCopyToCache = MIN2((uint32)MIN_READ_SIZE, lenRemainingInFile); // at most remaining file size +		 +		PSP_DEBUG_PRINT("filling cache with 0x%x bytes from physicalPos[0x%x]. cacheStart[0x%x], pos[0x%x], fileSize[0x%x]\n", lenToCopyToCache, _physicalPos, _cacheStartOffset, _pos, _fileSize); +		 +		size_t ret = fread(_cache, 1, lenToCopyToCache, (FILE *)_handle); +		if (ret != lenToCopyToCache) { +			PSP_ERROR("in filling cache, failed to get 0x%x bytes. Only got 0x%x\n", lenToCopyToCache, ret); +			_ferror = true; +			clearerr((FILE *)_handle); +		} +		_cacheStartOffset = _physicalPos; +		_inCache = true; +		 +		_physicalPos += ret; +		 +		PSP_DEBUG_PRINT("copying 0x%x bytes from cache to %p\n", lenFromFile, destPtr); +		 +		// Copy to the destination buffer from cache +		memcpy(destPtr, _cache, lenFromFile); +		_pos += lenFromFile; +		 +	} else {	// Too big for cache. No caching +		PSP_DEBUG_PRINT("reading 0x%x bytes from file to %p. Pos[0x%x], physPos[0x%x]\n", lenFromFile, destPtr, _pos, _physicalPos); +		size_t ret = fread(destPtr, 1, lenFromFile, (FILE *)_handle); + +		_physicalPos += ret;	// Update pos +		_pos = _physicalPos; + +		if (ret != lenFromFile) {	// error +			PSP_ERROR("fread returned [0x%x] instead of len[0x%x]\n", ret, lenFromFile);  			_ferror = true;  			clearerr((FILE *)_handle); -			_pos = ftell((FILE *)_handle);	// Update our position -			_errorSource = 4; -			PSP_ERROR("fread returned ret[%d] instead of len[%d]\n", ret, len); +			_errorSource = 4;			  		} +		_inCache = false;  	}  	PowerMan.endCriticalSection(); -	return ret; +#ifdef DEBUG_BUFFERS +	printBuffer((byte *)ptr, len); +#endif	 +		 +	return lenFromCache + lenFromFile;		// total of what was copied +} + +// TODO: Test if seeking backwards/forwards has any effect on performance +inline bool PSPIoStream::synchronizePhysicalPos() { +	if (_pos != _physicalPos) { +		if (fseek((FILE *)_handle, _pos - _physicalPos, SEEK_CUR) != 0) +			return false; +		_physicalPos = _pos;	 +	} +	 +	return true; +} + +inline bool PSPIoStream::isOffsetInCache(uint32 offset) { +	if (_cacheStartOffset != -1 &&  +		offset >= (uint32)_cacheStartOffset &&  +		offset < (uint32)(_cacheStartOffset + CACHE_SIZE)) +		return true; +	return false;  }  uint32 PSPIoStream::write(const void *ptr, uint32 len) { @@ -193,18 +312,30 @@ uint32 PSPIoStream::write(const void *ptr, uint32 len) {  	if (PowerMan.beginCriticalSection() == PowerManager::Blocked)  		PSP_DEBUG_PRINT_FUNC("Suspended\n"); -	PSP_DEBUG_PRINT_FUNC("filename[%s], len[%d]\n", _path.c_str(), len); +	PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x]\n", _path.c_str(), len); +	if (_ferror) +		return 0; +		 +	_eos = false;	// we can't have eos with write +	synchronizePhysicalPos(); +	  	size_t ret = fwrite(ptr, 1, len, (FILE *)_handle); -	_pos += ret; +	// If we're making the file bigger, adjust the size +	if (_physicalPos + (int)ret > _fileSize) +		_fileSize = _physicalPos + ret; +	_physicalPos += ret; +	_pos = _physicalPos; +	_inCache = false; +	_cacheStartOffset = -1;	// invalidate cache  	if (ret != len) {	// Set error  		_ferror = true;  		clearerr((FILE *)_handle);  		_pos = ftell((FILE *)_handle);	// Update pos  		_errorSource = 5; -		PSP_ERROR("fwrite returned[%d] instead of len[%d]\n", ret, len); +		PSP_ERROR("fwrite returned[0x%x] instead of len[0x%x]\n", ret, len);  	}  	PowerMan.endCriticalSection(); @@ -224,7 +355,7 @@ bool PSPIoStream::flush() {  		_ferror = true;  		clearerr((FILE *)_handle);  		_errorSource = 6; -		PSP_ERROR("fflush returned ret[%u]\n", ret); +		PSP_ERROR("fflush returned ret[%d]\n", ret);  	}  	PowerMan.endCriticalSection(); @@ -286,6 +417,9 @@ int PSPIoStream::resume() {  	// Resume our previous position  	if (_handle > 0 && _pos > 0) {  		ret = fseek((FILE *)_handle, _pos, SEEK_SET); +		 +		_physicalPos = _pos; +		_inCache = false;  		if (ret != 0) {		// Check for problem  			_errorSuspend = ResumeError;  | 
