/*---------------------------------------------------------------------------* Copyright 2010-2012 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ ////=========================================================================== /// demoFWB.c /// /// This is file write buffer code for the DEMO library. /// ////=========================================================================== #include #include s32 DEMOFWBOpenFile(const char* path, DEMOFWBFileInfo* fwbFileInfo, const char* mode, u32 writeBufferSize) { if((NULL == fwbFileInfo) || (NULL == mode) || (0 == writeBufferSize)) { return DEMO_FS_RESULT_FATAL_ERROR; } memset(fwbFileInfo, 0, sizeof(DEMOFWBFileInfo)); s32 openResult = DEMOFSOpenFileMode(path, &(fwbFileInfo->fileInfo), mode); if(openResult != DEMO_FS_RESULT_OK) { return openResult; } fwbFileInfo->writeBufferSize = writeBufferSize; fwbFileInfo->writeBuffer = DEMOAllocEx(writeBufferSize, PPC_IO_BUFFER_ALIGN); if(NULL == fwbFileInfo->writeBuffer) { return DEMO_FS_RESULT_FATAL_ERROR; } return DEMO_FS_RESULT_OK; } s32 DEMOFWBCloseFile(DEMOFWBFileInfo* fwbFileInfo) { if(fwbFileInfo == NULL) { return DEMO_FS_RESULT_FATAL_ERROR; } s32 result = DEMOFWBFlush(fwbFileInfo); if(fwbFileInfo->writeBuffer) { DEMOFree(fwbFileInfo->writeBuffer); fwbFileInfo->writeBuffer = 0; } if(result != DEMO_FS_RESULT_OK) { return result; } s32 result2 = DEMOFSCloseFile(&(fwbFileInfo->fileInfo)); fwbFileInfo->fileInfo = 0; return result2; } s32 DEMOFWBFlush(DEMOFWBFileInfo* fwbFileInfo) { s32 retVal = DEMO_FS_RESULT_OK; if(fwbFileInfo == NULL) { return DEMO_FS_RESULT_FATAL_ERROR; } if(fwbFileInfo->writeBufferWriteLocation > 0) { ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize); //We have data to be written. retVal = DEMOFSWrite(&(fwbFileInfo->fileInfo), fwbFileInfo->writeBuffer, fwbFileInfo->writeBufferWriteLocation); //Reset the writeBuffer to "empty" fwbFileInfo->writeBufferWriteLocation = 0; } return retVal; } s32 DEMOFWBWrite(DEMOFWBFileInfo* fwbFileInfo, void* bufferAddress, s32 length) { if((fwbFileInfo == NULL) || (bufferAddress == NULL)) { return DEMO_FS_RESULT_FATAL_ERROR; } ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize); //Is the write larger than writeBufferSize and cannot be buffered? This will not be efficient\fast. if(length > fwbFileInfo->writeBufferSize) { s32 retVal; DEMOPrintf("DEMOFWB Error: DEMOFWBWrite is taking a slow path since length > writeBufferSize!\n"); //The write will not fit in the buffer, so flush buffered writes first so the writes are correctly //ordered. DEMOFWBFlush(fwbFileInfo); ASSERT(fwbFileInfo->writeBufferWriteLocation == 0); //We can't buffer this write, but instead of failing, just write directly to FSA. void *tempPtr; if(((u32)bufferAddress % PPC_IO_BUFFER_ALIGN) == 0) { //address is already 64 byte alligned tempPtr = bufferAddress; } else { //Move the data so the buffer is 64 byte aligned. tempPtr = DEMOAllocEx(length+1, PPC_IO_BUFFER_ALIGN); memcpy(tempPtr, bufferAddress, length); } retVal = DEMOFSWrite(&(fwbFileInfo->fileInfo), tempPtr, length); if(tempPtr != bufferAddress) { DEMOFree(tempPtr); } return retVal; } //Can the write fit in the buffer space remaining? if((fwbFileInfo->writeBufferWriteLocation > 0) && (length > (fwbFileInfo->writeBufferSize - fwbFileInfo->writeBufferWriteLocation))) { //The write, will not fit in the buffer, so flush it first. DEMOFWBFlush(fwbFileInfo); ASSERT(fwbFileInfo->writeBufferWriteLocation == 0); } //There should be space in the buffer if we get here. if(length > (fwbFileInfo->writeBufferSize - fwbFileInfo->writeBufferWriteLocation)) { ASSERT(0); //Something is very broken; return DEMO_FS_RESULT_FATAL_ERROR; } void* writeAddr = (void*)((u32)fwbFileInfo->writeBuffer + fwbFileInfo->writeBufferWriteLocation); memcpy(writeAddr, bufferAddress, length); fwbFileInfo->writeBufferWriteLocation += length; ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize); return DEMO_FS_RESULT_OK; } inline void DEMOFWBvsnprintfHelper(s32 vsnprintfReturnVal, s32 maxPrintSize, s32* returnCode, u32* printedChars) { if(vsnprintfReturnVal < 0) { DEMOPrintf("DEMOFWB Error: DEMOFWBfprintf returned %d!\n", vsnprintfReturnVal); *returnCode = DEMO_FS_RESULT_FATAL_ERROR; } if(vsnprintfReturnVal > maxPrintSize) { //We must have been truncated! //Subtract off the NULL terminator. *printedChars = maxPrintSize - 1; } else { *printedChars = vsnprintfReturnVal; } } void copyChars(char* destination, char* source, u32 length) { for(u32 i = 0; i < length; i++) { destination[i] = source[i]; } } s32 DEMOFWBfprintf(DEMOFWBFileInfo* fwbFileInfo, const char * format, ...) { s32 retVal = DEMO_FS_RESULT_OK; va_list valist; if(fwbFileInfo == NULL) { return DEMO_FS_RESULT_FATAL_ERROR; } if(fwbFileInfo->writeBufferWriteLocation == fwbFileInfo->writeBufferSize) { //the buffer is full, so flush it to disk. DEMOFWBFlush(fwbFileInfo); } u32 printedChars = 0; void* writeAddr = (void*)((u32)fwbFileInfo->writeBuffer + fwbFileInfo->writeBufferWriteLocation); u32 freeSpace = fwbFileInfo->writeBufferSize - fwbFileInfo->writeBufferWriteLocation; ASSERT(freeSpace > 0); //We don't really know if the print will fit in the buffer. Try to print "freeSpace" characters of it. va_start(valist, format); s32 vsnprintfResult = vsnprintf(writeAddr, freeSpace, format, valist); va_end(valist); DEMOFWBvsnprintfHelper(vsnprintfResult, freeSpace, &retVal, &printedChars); fwbFileInfo->writeBufferWriteLocation += printedChars; if(vsnprintfResult > fwbFileInfo->writeBufferSize) { DEMOPrintf("DEMOFWB Error: DEMOFWBfprintf print length of %d was greater than writeBufferSize(%d) and data was truncated!", vsnprintfResult, fwbFileInfo->writeBufferSize); retVal = DEMO_FS_RESULT_AREA_FULL; } //Check if the full print fit in the free space or was truncated. if((DEMO_FS_RESULT_OK == retVal) && (vsnprintfResult > freeSpace)) { //The print was truncated, so we need to flush, retry, and pack that data. //The write buffer should be almost full now. Don't print the null terminator. ASSERT(fwbFileInfo->writeBufferWriteLocation + 1 == fwbFileInfo->writeBufferSize); //Flush the full buffer. DEMOFWBFlush(fwbFileInfo); ASSERT(fwbFileInfo->writeBufferWriteLocation == 0); //print again into the empy buffer u32 printedChars2 = 0; va_start(valist, format); s32 vsnprintfResult2 = vsnprintf(fwbFileInfo->writeBuffer, fwbFileInfo->writeBufferSize, format, valist); va_end(valist); DEMOFWBvsnprintfHelper(vsnprintfResult2, fwbFileInfo->writeBufferSize, &retVal, &printedChars2); if(DEMO_FS_RESULT_OK == retVal) { ASSERT(vsnprintfResult2 <= fwbFileInfo->writeBufferSize); //This shouldn't happen. ASSERT(vsnprintfResult == vsnprintfResult2); //I assume these should match. ASSERT(printedChars2 == vsnprintfResult2); char* newDataStart = (char*)((u32)fwbFileInfo->writeBuffer + printedChars); copyChars((char*)fwbFileInfo->writeBuffer, newDataStart, printedChars2 - printedChars); fwbFileInfo->writeBufferWriteLocation = printedChars2 - printedChars; } } ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize); if(fwbFileInfo->writeBufferWriteLocation == fwbFileInfo->writeBufferSize) { //the buffer is full, so flush it to disk. DEMOFWBFlush(fwbFileInfo); } return retVal; } // --------------------------------------------------------