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

Last change on this file since 410 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
RevLine 
[286]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.
[109]4
5#include "virtfile.h"
[206]6#include <common/stl-util.h>
[109]7
[298]8VirtFILE *VirtFILE::Vstdin = NULL;
9VirtFILE *VirtFILE::Vstdout = NULL;
10VirtFILE *VirtFILE::Vstderr = NULL;
[109]11
[298]12VirtFileSystem *VirtFILE::vfs = NULL;
[109]13
[302]14//#define DEBUG_VIRTFILE
[301]15
[302]16VirtFILE *Vfopen(const char* path, const char* mode)
[109]17{
[302]18#ifdef DEBUG_VIRTFILE
19        printf("VirtFILE::Vfopen %s %s (vfs=%p)\n",path,mode,VirtFILE::vfs);
[301]20#endif
[302]21        return VirtFILE::vfs ? VirtFILE::vfs->Vfopen(path, mode) : NULL;
[109]22}
23
24VirtDIR *Vopendir(const char* path)
25{
[302]26#ifdef DEBUG_VIRTFILE
27        printf("VirtFILE::Vfopendir %s (vfs=%p)\n",path,VirtFILE::vfs);
[301]28#endif
[302]29        return VirtFILE::vfs ? VirtFILE::vfs->Vopendir(path) : NULL;
[109]30}
31
[295]32bool Vfexists(const char* path)
[109]33{
[302]34        return VirtFILE::vfs ? VirtFILE::vfs->Vfexists(path) : false;
[109]35}
36
[302]37bool Vdirexists(const char* path, bool is_writable)
[295]38{
[302]39        return VirtFILE::vfs ? VirtFILE::vfs->Vdirexists(path, is_writable) : false;
[295]40}
41
42bool Vmkdir(const char* path)
43{
[302]44        return VirtFILE::vfs ? VirtFILE::vfs->Vmkdir(path) : false;
[295]45}
46
47bool Vmkdirs(const char* path)
48{
[302]49        return VirtFILE::vfs ? VirtFILE::vfs->Vmkdirs(path) : false;
[295]50}
51
[109]52VirtFILE::~VirtFILE()
53{}
54
[301]55void VirtFILE::selectFileSystem(VirtFileSystem *s)
56{
[302]57        vfs = s;
58#ifdef DEBUG_VIRTFILE
59        ::printf("VirtFILE::selectFileSystem: %p := %p\n",vfs,s);
[301]60#endif
61}
[109]62
[206]63int VirtFILE::Vprintf(const char *format, va_list args)
64{
[302]65        string s = ssprintf_va(format, args);
66        return Vwrite(s.c_str(), 1, s.size());
[206]67}
68
[109]69int VirtFILE::printf(const char *format, ...)
70{
[302]71        int ret; va_list argptr;
72        va_start(argptr, format);
73        ret = Vprintf(format, argptr);
74        va_end(argptr);
75        return ret;
[109]76}
77
[247]78int VirtFILE::getSize()
79{
[302]80        int saved_pos = Vtell();
81        Vseek(0, SEEK_END);
82        int size = Vtell();
83        Vseek(saved_pos, SEEK_SET);
84        return size;
[247]85}
86
[302]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; }
[109]93//////////////////////////////////////////////////////////////////////////
94
[298]95// base class only returns NULL/false/not supported - implementations perform the actual work
[302]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; }
[109]101
102//////////////////////////////////////////////////////////////////////////
103
104
105
[302]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); }
[123]108
[131]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
[225]111#if defined _MSC_VER || defined __CYGWIN__ || defined SHP || defined __ANDROID__
[302]112#pragma push_macro("feof")
113#undef feof
[123]114#endif
[131]115#if defined __BORLANDC__ //does not support #pragma push_macro/pop_macro
[302]116#undef feof
[131]117#endif
[123]118
[302]119int feof(VirtFILE* f) { return f->Veof(); }
[123]120
121//...and then restore the original macro:
[225]122#if defined _MSC_VER || defined __CYGWIN__ || defined SHP || defined __ANDROID__
[302]123#pragma pop_macro("feof")
[131]124#endif
[225]125#if defined __BORLANDC__
[302]126#define feof(__f)     ((__f)->flags & _F_EOF)
[109]127#endif
128
[123]129
[302]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{
[109]140        int ret; va_list argptr;
[302]141        va_start(argptr, format);
142        ret = f->Vprintf(format, argptr);
[109]143        va_end(argptr);
144        return ret;
[302]145}
146int fclose(VirtFILE* f) { delete f; return 0; }
[109]147
[302]148int closedir(VirtDIR* d) { delete d; return 0; }
149dirent* readdir(VirtDIR* d) { return d->Vreaddir(); }
[123]150
[295]151/////////
152
153bool VirtFileSystem::Vmkdirs(const char* path)
154{
[302]155        if (Vdirexists(path, true)) return true;
156        string parentdir = getFileDir(path);
157        if (!Vmkdirs(parentdir.c_str())) return false;
158        return Vmkdir(path);
[295]159}
160
161//////////
162
[301]163
164ChainFileSystem::ChainFileSystem(VirtFileSystem *_chain)
[295]165{
[302]166        chain = _chain;
167#ifdef DEBUG_VIRTFILE
168        printf("ChainFileSystem constructor: %p := %p\n",chain,_chain);
[301]169#endif
170}
171
172
173VirtFILE *ChainFileSystem::Vfopen(const char* path, const char* mode)
174{
[302]175#ifdef DEBUG_VIRTFILE
176        printf("ChainFileSystem::Vfopen %s %s (chain=%p)\n",path,mode,chain);
[301]177#endif
[295]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{
[302]188#ifdef DEBUG_VIRTFILE
189        printf("ChainFileSystem::Vfopendir %s (chain=%p)\n",path,chain);
[301]190#endif
[410]191        if (chain==NULL) return internalopendir(path);
192        return new Dir(string(path),this,chain);
[295]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
[302]205bool ChainFileSystem::Vdirexists(const char* path, bool is_writable)
[295]206{
[302]207        return (chain != NULL) ? chain->Vdirexists(path, is_writable) : false;
[295]208}
[410]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.