int32 OsclFileCache::Open(uint32 mode, uint32 size) //Called to open the cache for a newly opened file. //The NativeOpen was just called prior to this and was successful. { //should not be called with zero-size cache. OSCL_ASSERT(size > 0); //Save the mode _mode = mode; //open logger object only if logging is enabled on this //file if (iContainer.iLogger) iLogger = PVLogger::GetLoggerObject("OsclFileCache"); else iLogger = NULL; PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Open mode %d size %d", this, mode, size)); // Create the movable cache. // Re-allocate it if the size has changed. if (_movableCache.pBuffer && size != _movableCache.capacity) { OSCL_FREE(_movableCache.pBuffer); _movableCache.pBuffer = NULL; } if (!_movableCache.pBuffer && size > 0) { _movableCache.pBuffer = (uint8*)OSCL_MALLOC(size); } if (!_movableCache.pBuffer) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Open ERROR no memory %d", this)); return (-1);//error } _movableCache.capacity = _movableCache.usableSize = size; _movableCache.filePosition = 0; _movableCache.updateStart = _movableCache.updateEnd = 0; _movableCache.currentPos = _movableCache.endPos = 0; //Position the cache at zero. SetCachePosition(0); //get initial file size & native position PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Open CallingNativeSize", this)); _fileSize = iContainer.CallNativeSize(); PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Open CallingNativeTell", this)); _nativePosition = iContainer.CallNativeTell(); return 0; }
void OsclFileCache::Close() { //flush any cache updates SetCachePosition(0); //free the memory for cache buffer if (_pCacheBufferStart) { OSCL_FREE(_pCacheBufferStart); _pCacheBufferStart = NULL; } }
/** * Seek * * @param [in] offset from origin * @param [in] origin: either SEEKSET, SEEKCUR, or SEEKEND * * @return 0 for success. */ int32 OsclFileCache::Seek(TOsclFileOffset offset, Oscl_File::seek_type origin) { //figure out the file position we're trying to seek to TOsclFileOffset pos; switch (origin) { case Oscl_File::SEEKCUR: pos = Tell() + offset; break; case Oscl_File::SEEKSET: pos = 0 + offset; break; case Oscl_File::SEEKEND: pos = FileSize() + offset; break; default: PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Seek ERROR invalid origin %d", this, origin)); return (-1);//error-- invalid origin! } //don't allow seeking outside valid file size if (pos < 0 || pos > FileSize()) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Seek ERROR invalid seek position %d", this, pos)); return -1;//error } if (_curCache->Contains(pos)) { //Seek in cur cache _curCache->currentPos = (uint32)(pos - _curCache->filePosition); } else { //Seek outside cache int32 retval = SetCachePosition(pos); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Seek ERROR SetPosition error %d", this, retval)); return retval;//error } } return 0; }
/** * FillCacheFromFile * * Fill cache from current virtual position. * Flush any updated data first. * This will return a full cache, or * if at EOF, a partial or empty cache. * * @param void * * @return 0 on success. */ int32 OsclFileCache::FillCacheFromFile() { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::FillCacheFromFile vpos %d", this, Tell())); //flush and relocate cache to current virtual //position if needed TOsclFileOffset newpos = Tell(); if (_cacheFilePosition != newpos || (_cacheUpdateEnd - _cacheUpdateStart) > 0) { int32 retval = SetCachePosition(newpos); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::FillCacheFromFile ERROR SetCachePosition failed", this)); return retval;//error! } } //Now seek to the read position if needed. if (_nativePosition != newpos) { int32 result = iContainer.CallNativeSeek(newpos, Oscl_File::SEEKSET); if (result != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::FillCacheFromFile ERROR CallNativeSeek failed", this)); return result;//error! } //keep track of the native file position _nativePosition = newpos; } //try to fill the cache. If we hit EOF we won't get a full cache. _endCachePos = iContainer.CallNativeRead((void*)_pCacheBufferStart, 1, _cacheSize); PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::FillCacheFromFile got %d bytes", this, _endCachePos)); //update native position _nativePosition += _endCachePos; return 0;//success }
int32 OsclFileCache::Open(uint32 mode, uint32 size) //Called to open the cache for a newly opened file. //The NativeOpen was just called prior to this and was successful. { //should not be called with zero-size cache. OSCL_ASSERT(size > 0); //Save the open parameters _cacheSize = size; _mode = mode; //open logger object only if logging is enabled on this //file if (iContainer.iLogger) iLogger = PVLogger::GetLoggerObject("OsclFileCache"); else iLogger = NULL; PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Open mode %d size %d", this, mode, size)); // allocate memory for cache // free any old buffer since its size may be different if (_pCacheBufferStart) { OSCL_FREE(_pCacheBufferStart); _pCacheBufferStart = NULL; } _pCacheBufferStart = (uint8*)OSCL_MALLOC(_cacheSize); if (!_pCacheBufferStart) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Open ERROR no memory %d", this)); return (-1);//error } //initialise the cache variables SetCachePosition(0); //get initial file size & native position _fileSize = iContainer.CallNativeSize(); _nativePosition = iContainer.CallNativeTell(); return 0; }
/** * Write * Writes data from the input buffer into * the buffer supplied (inputBuffer) * * @param inputBuffer pointer to buffer of type void * @param size element size in bytes * @param numelements * number of elements to write * * @return returns the number of elements written */ uint32 OsclFileCache::Write(const void* inputBuffer, uint32 size, uint32 numelements) { if (inputBuffer == NULL) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Write ERROR invalid arg ", this)); return 0; } //write the data only in the mode we are permitted to write if ((_mode & Oscl_File::MODE_READWRITE) || (_mode & Oscl_File::MODE_APPEND) || (_mode & Oscl_File::MODE_READ_PLUS)) { ;//ok to write } else { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Write ERROR invalid mode for writing ", this)); return 0;//invalid mode. } //In Append mode, write always happens at the end of file, //so relocate the cache now if needed. if ((_mode & Oscl_File::MODE_APPEND) && (Tell() != FileSize())) { int32 result = SetCachePosition(FileSize()); if (result != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Write ERROR SetCachePosition failed. ", this)); return 0; } } //prep current cache for writing int32 result = _curCache->PrepWrite(); if (result != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Write ERROR PrepWrite failed. ", this)); return 0; } uint8* srcBuf = (uint8*)(inputBuffer); uint32 bytesToWrite = size * numelements; //write into cache, flushing as needed when it fills up. while (bytesToWrite > 0) { OSCL_ASSERT(_curCache->usableSize >= _curCache->currentPos); uint32 spaceInCache = _curCache->usableSize - _curCache->currentPos; if (spaceInCache > 0) { //write to cache uint32 thisWrite = (spaceInCache > bytesToWrite) ? bytesToWrite : spaceInCache; oscl_memcpy((_curCache->pBuffer + _curCache->currentPos), srcBuf, thisWrite); bytesToWrite -= thisWrite; srcBuf += thisWrite; //keep track of the range of data in the cache that has been updated. if (_curCache->updateEnd == _curCache->updateStart) { //first update in this cache _curCache->updateStart = _curCache->currentPos; _curCache->updateEnd = _curCache->currentPos + thisWrite; } else { //cache has already been updated. Expand the updated range //to include this update. if (_curCache->currentPos < _curCache->updateStart) _curCache->updateStart = _curCache->currentPos; if ((_curCache->currentPos + thisWrite) > _curCache->updateEnd) _curCache->updateEnd = _curCache->currentPos + thisWrite; } //update the virtual position. _curCache->currentPos += thisWrite; //extend the end of cache data if needed if (_curCache->endPos < _curCache->currentPos) _curCache->endPos = _curCache->currentPos; //extend the virtual file size if needed. if (_fileSize < (TOsclFileOffset)(_curCache->filePosition + _curCache->endPos)) _fileSize = _curCache->filePosition + _curCache->endPos; //consistency checks. if these asserts fire, there is //a logic error. OSCL_ASSERT(_curCache->updateEnd >= _curCache->updateStart); OSCL_ASSERT(_curCache->endPos >= _curCache->currentPos); } else { //entire cache is full-- re-set cache to current vpos and prep //for write int32 retval = SetCachePosition(Tell()); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Write ERROR SetCachePosition failed ", this)); break;//error! } retval = _curCache->PrepWrite(); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Write ERROR PrepWrite failed ", this)); break;//error! } } } //return number of whole elements written. return (size) ? ((size*numelements - bytesToWrite) / size) : 0; }
/** * Read * Reads data from the file cache buffer and copies into * the buffer supplied (outputBuffer) * * @param outputBuffer pointer to buffer of type void * @param size element size in bytes * @param numelements * max number of elements to read * * @return returns the number of full elements actually read, which * may be less than count if an error occurs or if the end * of the file is encountered before reaching count. */ uint32 OsclFileCache::Read(void* outputBuffer, uint32 size, uint32 numelements) { if (!outputBuffer) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Read ERROR invalid arg ", this)); return 0; } //check for a valid read mode if ((_mode & Oscl_File::MODE_READWRITE) || (_mode & Oscl_File::MODE_READ) || (_mode & Oscl_File::MODE_APPEND) || (_mode & Oscl_File::MODE_READ_PLUS)) { ;//ok to write } else { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Read ERROR invalid mode for reading ", this)); return 0;//invalid mode. } uint8* destBuf = (uint8*)(outputBuffer); uint32 bytesToRead = numelements * size; // If file is smaller than requested data amount, reduce bytesToRead to the lowest multiple // of size that we can read uint32 bytesLeftInFile = (uint32)(FileSize() - Tell()); if (bytesToRead > bytesLeftInFile) { numelements = bytesLeftInFile / size; bytesToRead = numelements * size; } if (bytesToRead) { //prep current cache for reading int32 retval = _curCache->PrepRead(); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Read ERROR PrepRead failed ", this)); return 0; } } //pull data out of the cache until we run out, then re-fill the cache //as needed until we get the desired amount. while (bytesToRead > 0) { OSCL_ASSERT(_curCache->endPos >= _curCache->currentPos); uint32 bytesInCache = (uint32)(_curCache->endPos - _curCache->currentPos); if (bytesInCache > 0) { //pull out either all data in cache, or number of bytes required, //whichever is less uint32 thisRead = (bytesInCache > bytesToRead) ? bytesToRead : bytesInCache; oscl_memcpy(destBuf, _curCache->pBuffer + _curCache->currentPos, thisRead); bytesToRead -= thisRead; destBuf += thisRead; //update virtual position _curCache->currentPos += thisRead; } else { //no more data-- reposition & refill the cache int32 retval = SetCachePosition(Tell()); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Read ERROR SetCachePosition failed ", this)); break;//error! } retval = _curCache->PrepRead(); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Read ERROR PrepRead failed ", this)); break;//error! } //When at EOF, cache will be empty after fillcache, //so break out of loop. if (_curCache->endPos - _curCache->currentPos == 0) break; } } //return number of whole elements read. return (size) ? ((size*numelements - bytesToRead) / size) : 0; }
/** * WriteCacheToFile * * Writes any updated data in the cache to disk, but does not * otherwise alter cache position or contents. Existing cache * data is still available for read. * * Has a side effect of adjusting the native file position. * * @param void * * @return 0 if successful and a non-zero value otherwise */ int32 OsclFileCache::WriteCacheToFile() { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::WriteCacheToFile vpos %d", this, Tell())); if (_cacheUpdateEnd > _cacheUpdateStart) { uint32 bytesToWrite = (_cacheUpdateEnd - _cacheUpdateStart); PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::WriteCacheToFile nbytes %d filepos %d start %d end %d " , this, bytesToWrite, _cacheFilePosition, _cacheUpdateStart, _cacheUpdateEnd)); //Seek to the correct write location in the file if needed TOsclFileOffset pos = _cacheFilePosition + _cacheUpdateStart; if (_nativePosition != pos) { if (_mode & Oscl_File::MODE_APPEND) { //In Append mode, writes automatically happen at the end of file so there is no //need to seek. ; } else { //seek to the write location int32 retval = iContainer.CallNativeSeek(pos, Oscl_File::SEEKSET); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::WriteCacheToFile ERROR CallNativeSeek failed", this)); return retval;//error! } } _nativePosition = pos; } //write the updated data range. int32 retval = iContainer.CallNativeWrite(_pCacheBufferStart + _cacheUpdateStart, 1, bytesToWrite); //keep track of the native file position. _nativePosition += retval; //clear the updated data range. _cacheUpdateStart = _cacheUpdateEnd = 0; if ((uint32)retval == bytesToWrite) return 0;//success! PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::WriteCacheToFile ERROR CallNativeWrite only wrote %d of %d", this, retval, bytesToWrite)); //At this point, the cache is corrupt, since we lost data. //Recover by checking actual native file values, emptying the cache, //and locating it as close as possible to the desired position. _fileSize = iContainer.CallNativeSize(); _nativePosition = iContainer.CallNativeTell(); TOsclFileOffset newpos = Tell(); if (newpos > _fileSize) newpos = _fileSize; SetCachePosition(newpos); return (-1); //error } return 0;//success-- nothing to do }
/** * Seek * * @param [in] offset from origin * @param [in] origin: either SEEKSET, SEEKCUR, or SEEKEND * * @return 0 for success. */ int32 OsclFileCache::Seek(TOsclFileOffset offset, Oscl_File::seek_type origin) { //figure out the file position we're trying to seek to TOsclFileOffset pos; switch (origin) { case Oscl_File::SEEKCUR: pos = Tell() + offset; break; case Oscl_File::SEEKSET: pos = 0 + offset; break; case Oscl_File::SEEKEND: pos = FileSize() + offset; break; default: PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Seek ERROR invalid origin %d", this, origin)); return (-1);//error-- invalid origin! } //don't allow seeking outside valid file size if ((uint32)pos < 0 || (uint32)pos > (uint32)FileSize()) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Seek ERROR invalid seek position %d", this, pos)); return -1;//error } //when seek is in current cache range, just update the //virtual position. if ((uint32)_cacheFilePosition <= (uint32)pos && (uint32)pos <= (uint32)(_cacheFilePosition + _endCachePos)) { _currentCachePos = (uint32)(pos - _cacheFilePosition); return 0;//success } //else seeking outside cache //Seek to the real target location. //Always use SEEKSET because the actual file end or current //position may not be accurate at this point. int32 retval; retval = iContainer.CallNativeSeek(pos, Oscl_File::SEEKSET); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Seek ERROR CallNativeSeek failed", this)); return retval;//error } //update native position _nativePosition = pos; //Relocate the cache & virtual position retval = SetCachePosition(pos); if (retval != 0) { PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG, (0, "OsclFileCache(0x%x)::Seek ERROR SetCachePosition failed", this)); } return retval; }