1 /*---------------------------------------------------------------------------*
2
3 Copyright (C) Nintendo. All rights reserved.
4
5 These coded instructions, statements, and computer programs contain
6 proprietary information of Nintendo of America Inc. and/or Nintendo
7 Company Ltd., and are protected by Federal copyright law. They may
8 not be disclosed to third parties or copied or duplicated in any form,
9 in whole or in part, without the prior written consent of Nintendo.
10
11 *---------------------------------------------------------------------------*/
12 ////===========================================================================
13 /// demoFWB.c
14 ///
15 /// This is file write buffer code for the DEMO library.
16 ///
17 ////===========================================================================
18
19 #include <cafe/demo.h>
20
21 #include <stdio.h>
22
DEMOFWBOpenFile(const char * path,DEMOFWBFileInfo * fwbFileInfo,const char * mode,u32 writeBufferSize)23 s32 DEMOFWBOpenFile(const char* path, DEMOFWBFileInfo* fwbFileInfo, const char* mode, u32 writeBufferSize)
24 {
25 if((NULL == fwbFileInfo) ||
26 (NULL == mode) ||
27 (0 == writeBufferSize))
28 {
29 return DEMO_FS_RESULT_FATAL_ERROR;
30 }
31
32 memset(fwbFileInfo, 0, sizeof(DEMOFWBFileInfo));
33
34 s32 openResult = DEMOFSOpenFileMode(path, &(fwbFileInfo->fileInfo), mode);
35 if(openResult != DEMO_FS_RESULT_OK)
36 {
37 return openResult;
38 }
39
40 fwbFileInfo->writeBufferSize = writeBufferSize;
41 fwbFileInfo->writeBuffer = DEMOAllocEx(writeBufferSize, PPC_IO_BUFFER_ALIGN);
42
43 if(NULL == fwbFileInfo->writeBuffer)
44 {
45 return DEMO_FS_RESULT_FATAL_ERROR;
46 }
47
48 return DEMO_FS_RESULT_OK;
49 }
50
DEMOFWBCloseFile(DEMOFWBFileInfo * fwbFileInfo)51 s32 DEMOFWBCloseFile(DEMOFWBFileInfo* fwbFileInfo)
52 {
53 if(fwbFileInfo == NULL)
54 {
55 return DEMO_FS_RESULT_FATAL_ERROR;
56 }
57
58 s32 result = DEMOFWBFlush(fwbFileInfo);
59
60 if(fwbFileInfo->writeBuffer)
61 {
62 DEMOFree(fwbFileInfo->writeBuffer);
63 fwbFileInfo->writeBuffer = 0;
64 }
65
66 if(result != DEMO_FS_RESULT_OK)
67 {
68 return result;
69 }
70
71 s32 result2 = DEMOFSCloseFile(&(fwbFileInfo->fileInfo));
72
73 fwbFileInfo->fileInfo = 0;
74
75 return result2;
76 }
77
78
79
DEMOFWBFlush(DEMOFWBFileInfo * fwbFileInfo)80 s32 DEMOFWBFlush(DEMOFWBFileInfo* fwbFileInfo)
81 {
82 s32 retVal = DEMO_FS_RESULT_OK;
83 if(fwbFileInfo == NULL)
84 {
85 return DEMO_FS_RESULT_FATAL_ERROR;
86 }
87
88
89 if(fwbFileInfo->writeBufferWriteLocation > 0)
90 {
91 ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize);
92
93 //We have data to be written.
94 retVal = DEMOFSWrite(&(fwbFileInfo->fileInfo),
95 fwbFileInfo->writeBuffer,
96 fwbFileInfo->writeBufferWriteLocation);
97
98 //Reset the writeBuffer to "empty"
99 fwbFileInfo->writeBufferWriteLocation = 0;
100 }
101
102 return retVal;
103 }
104
105
DEMOFWBWrite(DEMOFWBFileInfo * fwbFileInfo,void * bufferAddress,s32 length)106 s32 DEMOFWBWrite(DEMOFWBFileInfo* fwbFileInfo, void* bufferAddress, s32 length)
107 {
108 if((fwbFileInfo == NULL) ||
109 (bufferAddress == NULL))
110 {
111 return DEMO_FS_RESULT_FATAL_ERROR;
112 }
113
114 ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize);
115
116 //Is the write larger than writeBufferSize and cannot be buffered? This will not be efficient\fast.
117 if(length > fwbFileInfo->writeBufferSize)
118 {
119 s32 retVal;
120 DEMOPrintf("DEMOFWB Error: DEMOFWBWrite is taking a slow path since length > writeBufferSize!\n");
121
122 //The write will not fit in the buffer, so flush buffered writes first so the writes are correctly
123 //ordered.
124 DEMOFWBFlush(fwbFileInfo);
125 ASSERT(fwbFileInfo->writeBufferWriteLocation == 0);
126
127 //We can't buffer this write, but instead of failing, just write directly to FSA.
128 void *tempPtr;
129 if(((u32)bufferAddress % PPC_IO_BUFFER_ALIGN) == 0)
130 {
131 //address is already 64 byte alligned
132 tempPtr = bufferAddress;
133 }
134 else
135 {
136 //Move the data so the buffer is 64 byte aligned.
137 tempPtr = DEMOAllocEx(length+1, PPC_IO_BUFFER_ALIGN);
138 memcpy(tempPtr, bufferAddress, length);
139 }
140
141 retVal = DEMOFSWrite(&(fwbFileInfo->fileInfo),
142 tempPtr,
143 length);
144
145 if(tempPtr != bufferAddress)
146 {
147 DEMOFree(tempPtr);
148 }
149
150 return retVal;
151 }
152
153 //Can the write fit in the buffer space remaining?
154 if((fwbFileInfo->writeBufferWriteLocation > 0) &&
155 (length > (fwbFileInfo->writeBufferSize - fwbFileInfo->writeBufferWriteLocation)))
156 {
157 //The write, will not fit in the buffer, so flush it first.
158 DEMOFWBFlush(fwbFileInfo);
159 ASSERT(fwbFileInfo->writeBufferWriteLocation == 0);
160 }
161
162 //There should be space in the buffer if we get here.
163 if(length > (fwbFileInfo->writeBufferSize - fwbFileInfo->writeBufferWriteLocation))
164 {
165 ASSERT(0); //Something is very broken;
166 return DEMO_FS_RESULT_FATAL_ERROR;
167 }
168
169 void* writeAddr = (void*)((u32)fwbFileInfo->writeBuffer + fwbFileInfo->writeBufferWriteLocation);
170 memcpy(writeAddr, bufferAddress, length);
171 fwbFileInfo->writeBufferWriteLocation += length;
172
173 ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize);
174
175 return DEMO_FS_RESULT_OK;
176 }
177
DEMOFWBvsnprintfHelper(s32 vsnprintfReturnVal,s32 maxPrintSize,s32 * returnCode,u32 * printedChars)178 inline void DEMOFWBvsnprintfHelper(s32 vsnprintfReturnVal, s32 maxPrintSize, s32* returnCode, u32* printedChars)
179 {
180 if(vsnprintfReturnVal < 0)
181 {
182 DEMOPrintf("DEMOFWB Error: DEMOFWBfprintf returned %d!\n", vsnprintfReturnVal);
183 *returnCode = DEMO_FS_RESULT_FATAL_ERROR;
184 }
185 if(vsnprintfReturnVal > maxPrintSize)
186 {
187 //We must have been truncated!
188 //Subtract off the NULL terminator.
189 *printedChars = maxPrintSize - 1;
190 }
191 else
192 {
193 *printedChars = vsnprintfReturnVal;
194 }
195 }
196
copyChars(char * destination,char * source,u32 length)197 void copyChars(char* destination, char* source, u32 length)
198 {
199 for(u32 i = 0; i < length; i++)
200 {
201 destination[i] = source[i];
202 }
203 }
204
DEMOFWBfprintf(DEMOFWBFileInfo * fwbFileInfo,const char * format,...)205 s32 DEMOFWBfprintf(DEMOFWBFileInfo* fwbFileInfo, const char * format, ...)
206 {
207 s32 retVal = DEMO_FS_RESULT_OK;
208 va_list valist;
209
210 if(fwbFileInfo == NULL)
211 {
212 return DEMO_FS_RESULT_FATAL_ERROR;
213 }
214
215 if(fwbFileInfo->writeBufferWriteLocation == fwbFileInfo->writeBufferSize)
216 {
217 //the buffer is full, so flush it to disk.
218 DEMOFWBFlush(fwbFileInfo);
219 }
220
221 u32 printedChars = 0;
222 void* writeAddr = (void*)((u32)fwbFileInfo->writeBuffer + fwbFileInfo->writeBufferWriteLocation);
223 u32 freeSpace = fwbFileInfo->writeBufferSize - fwbFileInfo->writeBufferWriteLocation;
224
225 ASSERT(freeSpace > 0);
226
227 //We don't really know if the print will fit in the buffer. Try to print "freeSpace" characters of it.
228 va_start(valist, format);
229 s32 vsnprintfResult = vsnprintf(writeAddr, freeSpace, format, valist);
230 va_end(valist);
231 DEMOFWBvsnprintfHelper(vsnprintfResult, freeSpace, &retVal, &printedChars);
232 fwbFileInfo->writeBufferWriteLocation += printedChars;
233
234 if(vsnprintfResult > fwbFileInfo->writeBufferSize)
235 {
236 DEMOPrintf("DEMOFWB Error: DEMOFWBfprintf print length of %d was greater than writeBufferSize(%d) and data was truncated!", vsnprintfResult, fwbFileInfo->writeBufferSize);
237 retVal = DEMO_FS_RESULT_AREA_FULL;
238 }
239
240 //Check if the full print fit in the free space or was truncated.
241 if((DEMO_FS_RESULT_OK == retVal) &&
242 (vsnprintfResult > freeSpace))
243 {
244 //The print was truncated, so we need to flush, retry, and pack that data.
245 //The write buffer should be almost full now. Don't print the null terminator.
246 ASSERT(fwbFileInfo->writeBufferWriteLocation + 1 == fwbFileInfo->writeBufferSize);
247 //Flush the full buffer.
248 DEMOFWBFlush(fwbFileInfo);
249 ASSERT(fwbFileInfo->writeBufferWriteLocation == 0);
250
251 //print again into the empy buffer
252 u32 printedChars2 = 0;
253 va_start(valist, format);
254 s32 vsnprintfResult2 = vsnprintf(fwbFileInfo->writeBuffer, fwbFileInfo->writeBufferSize, format, valist);
255 va_end(valist);
256 DEMOFWBvsnprintfHelper(vsnprintfResult2, fwbFileInfo->writeBufferSize, &retVal, &printedChars2);
257
258 if(DEMO_FS_RESULT_OK == retVal)
259 {
260 ASSERT(vsnprintfResult2 <= fwbFileInfo->writeBufferSize); //This shouldn't happen.
261 ASSERT(vsnprintfResult == vsnprintfResult2); //I assume these should match.
262 ASSERT(printedChars2 == vsnprintfResult2);
263
264 char* newDataStart = (char*)((u32)fwbFileInfo->writeBuffer + printedChars);
265 copyChars((char*)fwbFileInfo->writeBuffer, newDataStart, printedChars2 - printedChars);
266 fwbFileInfo->writeBufferWriteLocation = printedChars2 - printedChars;
267 }
268 }
269
270 ASSERT(fwbFileInfo->writeBufferWriteLocation <= fwbFileInfo->writeBufferSize);
271
272 if(fwbFileInfo->writeBufferWriteLocation == fwbFileInfo->writeBufferSize)
273 {
274 //the buffer is full, so flush it to disk.
275 DEMOFWBFlush(fwbFileInfo);
276 }
277
278 return retVal;
279 }
280
281 // --------------------------------------------------------
282