- initial commit of Genesis3D 1.6
[genesis3d.git] / G3D / VFile / FSMEMORY.C
1 /****************************************************************************************/\r
2 /*  FSMEMORY.C                                                                          */\r
3 /*                                                                                      */\r
4 /*  Author: Eli Boling                                                                  */\r
5 /*  Description: Memory file system implementation                                      */\r
6 /*     Bug repair for 1.1 release - thanks to Tim Brengle                               */\r
7 /*                                                                                      */\r
8 /*  The contents of this file are subject to the Genesis3D Public License               */\r
9 /*  Version 1.01 (the "License"); you may not use this file except in                   */\r
10 /*  compliance with the License. You may obtain a copy of the License at                */\r
11 /*  http://www.genesis3d.com                                                            */\r
12 /*                                                                                      */\r
13 /*  Software distributed under the License is distributed on an "AS IS"                 */\r
14 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */\r
15 /*  the License for the specific language governing rights and limitations              */\r
16 /*  under the License.                                                                  */\r
17 /*                                                                                      */\r
18 /*  The Original Code is Genesis3D, released March 25, 1999.                            */\r
19 /*Genesis3D Version 1.1 released November 15, 1999                            */\r
20 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */\r
21 /*                                                                                      */\r
22 /****************************************************************************************/\r
23 #define WIN32_LEAN_AND_MEAN\r
24 #include        <windows.h>\r
25 \r
26 #include        <stdio.h>\r
27 #include        <stdlib.h>\r
28 #include        <string.h>\r
29 #include        <assert.h>\r
30 \r
31 #include        "basetype.h"\r
32 #include        "ram.h"\r
33 \r
34 #include        "vfile.h"\r
35 #include        "vfile._h"\r
36 \r
37 #include        "fsmemory.h"\r
38 \r
39 //      "MF01"\r
40 #define MEMORYFILE_SIGNATURE    0x3130464D\r
41 \r
42 //      "MF02"\r
43 #define MEMORYFINDER_SIGNATURE  0x3230464D\r
44 \r
45 #define CHECK_HANDLE(H) assert(H);assert(H->Signature == MEMORYFILE_SIGNATURE);\r
46 #define CHECK_FINDER(F) assert(F);assert(F->Signature == MEMORYFINDER_SIGNATURE);\r
47 \r
48 #define MEMORY_FILE_GROW        0x2000\r
49 \r
50 typedef struct  MemoryFile\r
51 {\r
52         unsigned int    Signature;\r
53         char *                  Memory;\r
54         int                             Size;\r
55         int                             AllocatedSize;\r
56         int                             Position;\r
57         geBoolean               WeOwnMemory;\r
58         geBoolean               ReadOnly;\r
59 }       MemoryFile;\r
60 \r
61 static  void *  GENESISCC FSMemory_FinderCreate(\r
62         geVFile *               FS,\r
63         void *                  Handle,\r
64         const char *    FileSpec)\r
65 {\r
66         return NULL;\r
67 }\r
68 \r
69 static  geBoolean       GENESISCC FSMemory_FinderGetNextFile(void *Handle)\r
70 {\r
71         assert(!Handle);\r
72         return GE_FALSE;\r
73 }\r
74 \r
75 static  geBoolean       GENESISCC FSMemory_FinderGetProperties(void *Handle, geVFile_Properties *Props)\r
76 {\r
77         assert(!Handle);\r
78         return GE_FALSE;\r
79 }\r
80 \r
81 static  void GENESISCC FSMemory_FinderDestroy(void *Handle)\r
82 {\r
83         assert(!Handle);\r
84 }\r
85 \r
86 static  void *  GENESISCC FSMemory_Open(\r
87         geVFile *               FS,\r
88         void *                  Handle,\r
89         const char *    Name,\r
90         void *                  Context,\r
91         unsigned int    OpenModeFlags)\r
92 {\r
93         return NULL;\r
94 }\r
95 \r
96 static  void *  GENESISCC FSMemory_OpenNewSystem(\r
97         geVFile *               FS,\r
98         const char *    Name,\r
99         void *                  Context,\r
100         unsigned int    OpenModeFlags)\r
101 {\r
102         MemoryFile *                    NewFS;\r
103         geVFile_MemoryContext * MemContext;\r
104 \r
105         if      (FS || Name || !Context)\r
106                 return NULL;\r
107 \r
108         MemContext = Context;\r
109 \r
110         // Don't allow the user to pass in memory pointer if we're updating or creating, because\r
111         // we don't know what allocation functions we should use to resize their block if\r
112         // necessary.  If you want to create a new file, you have to pass in NULL and let\r
113         // us manage the allocations.\r
114         if      (MemContext->Data && (OpenModeFlags & (GE_VFILE_OPEN_UPDATE | GE_VFILE_OPEN_CREATE)))\r
115                 return NULL;\r
116 \r
117         if      (OpenModeFlags & GE_VFILE_OPEN_DIRECTORY)\r
118                 return NULL;\r
119 \r
120         NewFS = geRam_Allocate(sizeof(*NewFS));\r
121         if      (!NewFS)\r
122                 return NewFS;\r
123         memset(NewFS, 0, sizeof(*NewFS));\r
124 \r
125         NewFS->Memory = MemContext->Data;\r
126         NewFS->Size = MemContext->DataLength;\r
127         NewFS->AllocatedSize = NewFS->Size;\r
128 \r
129         if      (NewFS->Memory)\r
130         {\r
131                 NewFS->ReadOnly = GE_TRUE;\r
132                 NewFS->WeOwnMemory = GE_FALSE;\r
133         }\r
134         else\r
135         {\r
136                 NewFS->ReadOnly = GE_FALSE;\r
137                 NewFS->WeOwnMemory = GE_TRUE;\r
138         }\r
139 \r
140         NewFS->Signature = MEMORYFILE_SIGNATURE;\r
141 \r
142         return NewFS;\r
143 }\r
144 \r
145 static  geBoolean       GENESISCC FSMemory_UpdateContext(\r
146         geVFile *               FS,\r
147         void *                  Handle,\r
148         void *                  Context,\r
149         int                     ContextSize)\r
150 {\r
151         MemoryFile *                    File;\r
152         geVFile_MemoryContext * MemoryContext;\r
153 \r
154         assert(FS);\r
155         assert(Context);\r
156         \r
157         File = Handle;\r
158         \r
159         CHECK_HANDLE(File);\r
160 \r
161         if      (ContextSize != sizeof(geVFile_MemoryContext))\r
162                 return GE_FALSE;\r
163 \r
164         MemoryContext = Context;\r
165         \r
166         MemoryContext->Data               = File->Memory;\r
167         MemoryContext->DataLength = File->Size;\r
168 \r
169         return GE_TRUE;\r
170 }\r
171 \r
172 static  void    GENESISCC FSMemory_Close(void *Handle)\r
173 {\r
174         MemoryFile *    File;\r
175         \r
176         File = Handle;\r
177         \r
178         CHECK_HANDLE(File);\r
179 \r
180         if      (File->WeOwnMemory == GE_TRUE && File->Memory)\r
181                 geRam_Free(File->Memory);\r
182         geRam_Free(File);\r
183 }\r
184 \r
185 static int GENESISCC ClampOperationSize(const MemoryFile *File, int Size)\r
186 {\r
187         return min(File->Size - File->Position, Size);\r
188 }\r
189 \r
190 static char * GENESISCC DataPtr(const MemoryFile *File)\r
191 {\r
192         return File->Memory + File->Position;\r
193 }\r
194 \r
195 static  geBoolean       GENESISCC FSMemory_GetS(void *Handle, void *Buff, int MaxLen)\r
196 {\r
197         MemoryFile *    File;\r
198         char *                  p;\r
199         char *                  Start;\r
200         char *                  pBuff;\r
201 \r
202         assert(Buff);\r
203         assert(MaxLen != 0);\r
204 \r
205         File = Handle;\r
206 \r
207         CHECK_HANDLE(File);\r
208 \r
209         MaxLen = ClampOperationSize(File, MaxLen);\r
210         if      (MaxLen == 0)\r
211                 return GE_FALSE;\r
212 \r
213         p = DataPtr(File);\r
214         pBuff = Buff;\r
215         Start = p;\r
216 \r
217 //---------\r
218 //   Bug fix thanks to Tim Brengle\r
219 //---------\r
220 \r
221         //while (*p != '\n' && MaxLen > 0)\r
222         while   (*p != '\n' && MaxLen > 1)\r
223         {\r
224                 *pBuff++ = *p++;\r
225                 MaxLen--;\r
226         }\r
227 \r
228         File->Position += p - Start + 1;\r
229         assert(File->Position <= File->Size);\r
230         assert(File->Size <= File->AllocatedSize);\r
231 \r
232         #if 0\r
233                 if      (MaxLen != 0)\r
234                 {\r
235                         *pBuff = *p;\r
236                         return GE_TRUE;\r
237                 }\r
238                 return GE_FALSE;\r
239         #endif\r
240         \r
241         *(pBuff + 1) = 0;\r
242         return GE_TRUE;\r
243         \r
244 }\r
245 \r
246 static  geBoolean       GENESISCC FSMemory_Read(void *Handle, void *Buff, int Count)\r
247 {\r
248         MemoryFile *    File;\r
249 \r
250         assert(Buff);\r
251         assert(Count != 0);\r
252 \r
253         File = Handle;\r
254 \r
255         CHECK_HANDLE(File);\r
256 \r
257         if      (ClampOperationSize(File, Count) != Count)\r
258                 return GE_FALSE;\r
259 \r
260         memcpy(Buff, DataPtr(File), Count);\r
261 \r
262         File->Position += Count;\r
263         assert(File->Position <= File->Size);\r
264         assert(File->Size <= File->AllocatedSize);\r
265 \r
266         return GE_TRUE;\r
267 }\r
268 \r
269 static  geBoolean       GENESISCC TestForExpansion(MemoryFile *File, int Size)\r
270 {\r
271         assert(File);\r
272         assert(File->ReadOnly == GE_FALSE);\r
273         assert(File->WeOwnMemory == GE_TRUE);\r
274 \r
275         assert(File->AllocatedSize >= File->Size);\r
276         assert(File->AllocatedSize >= File->Position);\r
277 \r
278         if      (File->AllocatedSize - File->Position < Size)\r
279         {\r
280                 int             NewSize;\r
281                 char *  NewBlock;\r
282 \r
283                 NewSize = ((File->AllocatedSize + Size + (MEMORY_FILE_GROW - 1)) / MEMORY_FILE_GROW) * MEMORY_FILE_GROW;\r
284                 NewBlock = geRam_Realloc(File->Memory, NewSize);\r
285                 if      (!NewBlock)\r
286                         return GE_FALSE;\r
287                 File->Memory = NewBlock;\r
288                 File->AllocatedSize = NewSize;\r
289 //printf("FSMemory: Expanded file to %d bytes\n", NewSize);\r
290         }\r
291 \r
292         return GE_TRUE;\r
293 }\r
294 \r
295 static  geBoolean       GENESISCC FSMemory_Write(void *Handle, const void *Buff, int Count)\r
296 {\r
297         MemoryFile *    File;\r
298 \r
299         assert(Buff);\r
300         assert(Count != 0);\r
301 \r
302         File = Handle;\r
303 \r
304         CHECK_HANDLE(File);\r
305 \r
306         if      (File->ReadOnly == GE_TRUE)\r
307                 return GE_FALSE;\r
308 \r
309         if      (TestForExpansion(File, Count) == GE_FALSE)\r
310                 return GE_FALSE;\r
311 \r
312         memcpy(DataPtr(File), Buff, Count);\r
313         \r
314         File->Position += Count;\r
315         if      (File->Size < File->Position)\r
316                 File->Size = File->Position;\r
317 \r
318         return GE_TRUE;\r
319 }\r
320 \r
321 static  geBoolean       GENESISCC FSMemory_Seek(void *Handle, int Where, geVFile_Whence Whence)\r
322 {\r
323         MemoryFile *    File;\r
324 \r
325         File = Handle;\r
326 \r
327         CHECK_HANDLE(File);\r
328 \r
329         switch  (Whence)\r
330         {\r
331         int             NewPos;\r
332 \r
333         case    GE_VFILE_SEEKCUR:\r
334                 NewPos = File->Position + Where;\r
335                 if      (NewPos > File->AllocatedSize)\r
336                 {\r
337                         if      (File->ReadOnly == GE_TRUE)\r
338                                 return GE_FALSE;\r
339                         if      (TestForExpansion(File, Where) == GE_FALSE)\r
340                                 return GE_FALSE;\r
341                 }\r
342                 File->Position = NewPos;\r
343                 break;\r
344 \r
345         case    GE_VFILE_SEEKEND:\r
346                 if      (File->Size < Where)\r
347                         return GE_FALSE;\r
348                 File->Position = File->Size - Where;\r
349                 break;\r
350 \r
351         case    GE_VFILE_SEEKSET:\r
352                 if      (Where > File->AllocatedSize)\r
353                 {\r
354                         if      (File->ReadOnly == GE_TRUE)\r
355                                 return GE_FALSE;\r
356                         if      (TestForExpansion(File, Where - File->Position) == GE_FALSE)\r
357                                 return GE_FALSE;\r
358                 }\r
359                 File->Position = Where;\r
360                 break;\r
361 \r
362         default:\r
363                 assert(!"Unknown seek kind");\r
364         }\r
365 \r
366         if      (File->Position > File->Size)\r
367                 File->Size = File->Position;\r
368         \r
369         assert(File->Size <= File->AllocatedSize);\r
370         assert(File->Position <= File->AllocatedSize);\r
371 \r
372         return GE_TRUE;\r
373 }\r
374 \r
375 static  geBoolean       GENESISCC FSMemory_EOF(const void *Handle)\r
376 {\r
377         const MemoryFile *      File;\r
378 \r
379         File = Handle;\r
380 \r
381         CHECK_HANDLE(File);\r
382 \r
383         if      (File->Position == File->Size)\r
384                 return GE_TRUE;\r
385 \r
386         return GE_FALSE;\r
387 }\r
388 \r
389 static  geBoolean       GENESISCC FSMemory_Tell(const void *Handle, long *Position)\r
390 {\r
391         const MemoryFile *      File;\r
392 \r
393         File = Handle;\r
394 \r
395         CHECK_HANDLE(File);\r
396 \r
397         *Position = File->Position;\r
398 \r
399         return GE_TRUE;\r
400 }\r
401 \r
402 static  geBoolean       GENESISCC FSMemory_Size(const void *Handle, long *Size)\r
403 {\r
404         const MemoryFile *      File;\r
405 \r
406         File = Handle;\r
407 \r
408         CHECK_HANDLE(File);\r
409         \r
410         *Size = File->Size;\r
411 \r
412         return GE_TRUE;\r
413 }\r
414 \r
415 static  geBoolean       GENESISCC FSMemory_GetProperties(const void *Handle, geVFile_Properties *Properties)\r
416 {\r
417         assert(!"Not implemented");\r
418         return GE_FALSE;\r
419 }\r
420 \r
421 static  geBoolean       GENESISCC FSMemory_SetSize(void *Handle, long Size)\r
422 {\r
423         assert(!"Not implemented");\r
424         return GE_FALSE;\r
425 }\r
426 \r
427 static  geBoolean       GENESISCC FSMemory_SetAttributes(void *Handle, geVFile_Attributes Attributes)\r
428 {\r
429         assert(!"Not implemented");\r
430         return GE_FALSE;\r
431 }\r
432 \r
433 static  geBoolean       GENESISCC FSMemory_SetTime(void *Handle, const geVFile_Time *Time)\r
434 {\r
435         assert(!"Not implemented");\r
436         return GE_FALSE;\r
437 }\r
438 \r
439 static  geBoolean       GENESISCC FSMemory_SetHints(void *Handle, const geVFile_Hints *Hints)\r
440 {\r
441         assert(!"Not implemented");\r
442         return GE_FALSE;\r
443 }\r
444 \r
445 static  geBoolean       GENESISCC FSMemory_FileExists(geVFile *FS, void *Handle, const char *Name)\r
446 {\r
447         return GE_FALSE;\r
448 }\r
449 \r
450 static  geBoolean       GENESISCC FSMemory_Disperse(\r
451         geVFile *               FS,\r
452         void *          Handle,\r
453         const char *Directory,\r
454         geBoolean       Recursive)\r
455 {\r
456         return GE_FALSE;\r
457 }\r
458 \r
459 static  geBoolean       GENESISCC FSMemory_DeleteFile(geVFile *FS, void *Handle, const char *Name)\r
460 {\r
461         return GE_FALSE;\r
462 }\r
463 \r
464 static  geBoolean       GENESISCC FSMemory_RenameFile(geVFile *FS, void *Handle, const char *Name, const char *NewName)\r
465 {\r
466         return GE_FALSE;\r
467 }\r
468 \r
469 static  geVFile_SystemAPIs      FSMemory_APIs =\r
470 {\r
471         FSMemory_FinderCreate,\r
472         FSMemory_FinderGetNextFile,\r
473         FSMemory_FinderGetProperties,\r
474         FSMemory_FinderDestroy,\r
475 \r
476         FSMemory_OpenNewSystem,\r
477         FSMemory_UpdateContext,\r
478         FSMemory_Open,\r
479         FSMemory_DeleteFile,\r
480         FSMemory_RenameFile,\r
481         FSMemory_FileExists,\r
482         FSMemory_Disperse,\r
483         FSMemory_Close,\r
484 \r
485         FSMemory_GetS,\r
486         FSMemory_Read,\r
487         FSMemory_Write,\r
488         FSMemory_Seek,\r
489         FSMemory_EOF,\r
490         FSMemory_Tell,\r
491         FSMemory_Size,\r
492 \r
493         FSMemory_GetProperties,\r
494 \r
495         FSMemory_SetSize,\r
496         FSMemory_SetAttributes,\r
497         FSMemory_SetTime,\r
498         FSMemory_SetHints,\r
499 };\r
500 \r
501 const geVFile_SystemAPIs * GENESISCC FSMemory_GetAPIs(void)\r
502 {\r
503         return &FSMemory_APIs;\r
504 }\r
505 \r