source: cpp/common/virtfile/virtfile.cpp @ 584

Last change on this file since 584 was 410, checked in by Maciej Komosinski, 9 years ago

ChainFileSystem? can merge Vopendir() results

  • Property svn:eol-style set to native
File size: 6.4 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "virtfile.h"
6#include <common/stl-util.h>
7
8VirtFILE *VirtFILE::Vstdin = NULL;
9VirtFILE *VirtFILE::Vstdout = NULL;
10VirtFILE *VirtFILE::Vstderr = NULL;
11
12VirtFileSystem *VirtFILE::vfs = NULL;
13
14//#define DEBUG_VIRTFILE
15
16VirtFILE *Vfopen(const char* path, const char* mode)
17{
18#ifdef DEBUG_VIRTFILE
19        printf("VirtFILE::Vfopen %s %s (vfs=%p)\n",path,mode,VirtFILE::vfs);
20#endif
21        return VirtFILE::vfs ? VirtFILE::vfs->Vfopen(path, mode) : NULL;
22}
23
24VirtDIR *Vopendir(const char* path)
25{
26#ifdef DEBUG_VIRTFILE
27        printf("VirtFILE::Vfopendir %s (vfs=%p)\n",path,VirtFILE::vfs);
28#endif
29        return VirtFILE::vfs ? VirtFILE::vfs->Vopendir(path) : NULL;
30}
31
32bool Vfexists(const char* path)
33{
34        return VirtFILE::vfs ? VirtFILE::vfs->Vfexists(path) : false;
35}
36
37bool Vdirexists(const char* path, bool is_writable)
38{
39        return VirtFILE::vfs ? VirtFILE::vfs->Vdirexists(path, is_writable) : false;
40}
41
42bool Vmkdir(const char* path)
43{
44        return VirtFILE::vfs ? VirtFILE::vfs->Vmkdir(path) : false;
45}
46
47bool Vmkdirs(const char* path)
48{
49        return VirtFILE::vfs ? VirtFILE::vfs->Vmkdirs(path) : false;
50}
51
52VirtFILE::~VirtFILE()
53{}
54
55void VirtFILE::selectFileSystem(VirtFileSystem *s)
56{
57        vfs = s;
58#ifdef DEBUG_VIRTFILE
59        ::printf("VirtFILE::selectFileSystem: %p := %p\n",vfs,s);
60#endif
61}
62
63int VirtFILE::Vprintf(const char *format, va_list args)
64{
65        string s = ssprintf_va(format, args);
66        return Vwrite(s.c_str(), 1, s.size());
67}
68
69int VirtFILE::printf(const char *format, ...)
70{
71        int ret; va_list argptr;
72        va_start(argptr, format);
73        ret = Vprintf(format, argptr);
74        va_end(argptr);
75        return ret;
76}
77
78int VirtFILE::getSize()
79{
80        int saved_pos = Vtell();
81        Vseek(0, SEEK_END);
82        int size = Vtell();
83        Vseek(saved_pos, SEEK_SET);
84        return size;
85}
86
87void VirtFILE::setVstdin(VirtFILE *f) { Vstdin = f; }
88void VirtFILE::setVstdout(VirtFILE *f) { Vstdout = f; }
89void VirtFILE::setVstderr(VirtFILE *f) { Vstderr = f; }
90VirtFILE* VirtFILE::getVstdin() { return Vstdin; }
91VirtFILE* VirtFILE::getVstdout() { return Vstdout; }
92VirtFILE* VirtFILE::getVstderr() { return Vstderr; }
93//////////////////////////////////////////////////////////////////////////
94
95// base class only returns NULL/false/not supported - implementations perform the actual work
96VirtFILE* VirtFileSystem::Vfopen(const char* path, const char* mode) { return NULL; }
97bool VirtFileSystem::Vfexists(const char* path) { return false; }
98VirtDIR* VirtFileSystem::Vopendir(const char* path) { return NULL; }
99bool VirtFileSystem::Vmkdir(const char* path) { return false; }
100bool VirtFileSystem::Vdirexists(const char* path, bool is_writable) { return false; }
101
102//////////////////////////////////////////////////////////////////////////
103
104
105
106int fread(void *ptr, size_t size, size_t nmemb, VirtFILE* f) { return f->Vread(ptr, size, nmemb); }
107int fwrite(const void *ptr, size_t size, size_t nmemb, VirtFILE* f) { return f->Vwrite(ptr, size, nmemb); }
108
109
110//since we want our own feof(VirtFILE*) function and some systems unfortunately define feof as a macro, we need to #undef it. Same as in virtfile.h
111#if defined _MSC_VER || defined __CYGWIN__ || defined SHP || defined __ANDROID__
112#pragma push_macro("feof")
113#undef feof
114#endif
115#if defined __BORLANDC__ //does not support #pragma push_macro/pop_macro
116#undef feof
117#endif
118
119int feof(VirtFILE* f) { return f->Veof(); }
120
121//...and then restore the original macro:
122#if defined _MSC_VER || defined __CYGWIN__ || defined SHP || defined __ANDROID__
123#pragma pop_macro("feof")
124#endif
125#if defined __BORLANDC__
126#define feof(__f)     ((__f)->flags & _F_EOF)
127#endif
128
129
130int fputc(int c, VirtFILE* f) { return f->Vputc(c); }
131int fputs(const char *s, VirtFILE* f) { return f->Vputs(s); }
132int fgetc(VirtFILE* f) { return f->Vgetc(); }
133int fseek(VirtFILE* f, long offset, int whence) { return f->Vseek(offset, whence); }
134int ftell(VirtFILE* f) { return f->Vtell(); }
135void rewind(VirtFILE* f) { f->Vrewind(); }
136int fflush(VirtFILE* f) { return f->Vflush(); }
137char *fgets(char *s, int size, VirtFILE* f) { return f->Vgets(s, size); }
138int fprintf(VirtFILE* f, const char *format, ...)
139{
140        int ret; va_list argptr;
141        va_start(argptr, format);
142        ret = f->Vprintf(format, argptr);
143        va_end(argptr);
144        return ret;
145}
146int fclose(VirtFILE* f) { delete f; return 0; }
147
148int closedir(VirtDIR* d) { delete d; return 0; }
149dirent* readdir(VirtDIR* d) { return d->Vreaddir(); }
150
151/////////
152
153bool VirtFileSystem::Vmkdirs(const char* path)
154{
155        if (Vdirexists(path, true)) return true;
156        string parentdir = getFileDir(path);
157        if (!Vmkdirs(parentdir.c_str())) return false;
158        return Vmkdir(path);
159}
160
161//////////
162
163
164ChainFileSystem::ChainFileSystem(VirtFileSystem *_chain)
165{
166        chain = _chain;
167#ifdef DEBUG_VIRTFILE
168        printf("ChainFileSystem constructor: %p := %p\n",chain,_chain);
169#endif
170}
171
172
173VirtFILE *ChainFileSystem::Vfopen(const char* path, const char* mode)
174{
175#ifdef DEBUG_VIRTFILE
176        printf("ChainFileSystem::Vfopen %s %s (chain=%p)\n",path,mode,chain);
177#endif
178        return (chain != NULL) ? chain->Vfopen(path, mode) : NULL;
179}
180
181bool ChainFileSystem::Vfexists(const char* path)
182{
183        return (chain != NULL) ? chain->Vfexists(path) : false;
184}
185
186VirtDIR *ChainFileSystem::Vopendir(const char* path)
187{
188#ifdef DEBUG_VIRTFILE
189        printf("ChainFileSystem::Vfopendir %s (chain=%p)\n",path,chain);
190#endif
191        if (chain==NULL) return internalopendir(path);
192        return new Dir(string(path),this,chain);
193}
194
195bool ChainFileSystem::Vmkdir(const char* path)
196{
197        return (chain != NULL) ? chain->Vmkdir(path) : false;
198}
199
200bool ChainFileSystem::Vmkdirs(const char* path)
201{
202        return (chain != NULL) ? chain->Vmkdirs(path) : false;
203}
204
205bool ChainFileSystem::Vdirexists(const char* path, bool is_writable)
206{
207        return (chain != NULL) ? chain->Vdirexists(path, is_writable) : false;
208}
209
210ChainFileSystem::Dir::~Dir()
211{
212if (dir) delete dir;
213}
214
215dirent* ChainFileSystem::Dir::Vreaddir()
216{
217dirent *de;
218  retry:
219if (!dir)
220        {
221        if (first)
222                {
223                dir=first->internalopendir(path.c_str());
224                first=NULL;
225                }
226        else if (second)
227                {
228                dir=second->Vopendir(path.c_str());
229                second=NULL;
230                }
231        else
232                return NULL;
233        }
234de=dir ? dir->Vreaddir() : NULL;
235if (de==NULL)
236        {if (dir) delete dir; dir=NULL; goto retry;}
237
238// no need to check for duplicates if no names are saved and scanning the last location (most common case)
239if (! (duplicates.empty() && (first==NULL) && (second==NULL)) )
240{
241string s(de->d_name);
242if (duplicates.find(s)==duplicates.end())
243        duplicates.insert(s);
244else
245        goto retry;
246}
247
248return de;
249}
Note: See TracBrowser for help on using the repository browser.