source: cpp/common/nonstd_stdio.cpp @ 878

Last change on this file since 878 was 878, checked in by Maciej Komosinski, 6 years ago

Fixed fputs("") reporting an error in Android MFILE implementation

  • Property svn:eol-style set to native
File size: 8.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 "nonstd_stdio.h"
6#include "nonstd.h"
7#include "Convert.h" //utf8ToUtf16()
8#include <common/util-string.h>
9
10#ifdef _WIN32
11#include "Shlwapi.h" //PathIsRelative()
12#ifdef __BORLANDC__
13#pragma link "Shlwapi.lib" //PathIsRelative()
14#endif
15#include <sys/stat.h> //_stat
16#else
17#include <unistd.h>
18#endif
19
20
21
22#ifdef _WIN32
23FILE* mfile_wfopen(const char *path, const char *mode) //to avoid converting args into wide char in all occurrences of mfopen()
24{
25        return _wfopen(Convert::utf8ToUtf16(path).c_str(), Convert::strTOwstr(mode).c_str());
26}
27#endif
28
29bool fileExists(const char* path)
30{
31        //lepiej gdyby uzywalo stat bo mfopen mogloby cos niepotrzebnie wczytywac przy otwarciu pliku ale mfopen wiadomo ze zadziala wszedzie tak samo
32        MFILE *f = mfopen(path, FOPEN_READ_BINARY);
33        if (f == NULL) return false;
34        mfclose(f);
35        return true;
36}
37
38#ifdef _WIN32
39bool isDirWritable(const char* path) //dir must not end with '\'
40{
41        wstring dir = Convert::utf8ToUtf16(path);
42        CreateDirectoryW(dir.c_str(), 0);
43        dir += L"\\test_file.write";
44        _wunlink(dir.c_str());
45        FILE *f = _wfopen(dir.c_str(), L"wt");
46        if (f)
47        {
48                fclose(f);
49                _wunlink(dir.c_str());
50                return true;
51        }
52        else
53                return false;
54}
55#endif
56
57bool directoryExists(const char* path, bool is_writable)
58{
59        struct _stat s;
60        if (path[0] == 0) path = ".";
61#ifdef _WIN32
62        if (_wstat(Convert::utf8ToUtf16(path).c_str(), &s) != 0) return false;
63#else
64        if (_stat(path, &s) != 0) return false;
65#endif
66        if (S_ISDIR(s.st_mode))
67        {
68                if (is_writable)
69                {
70#ifdef _WIN32
71#ifndef W_OK
72#define W_OK 2 //http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx
73#endif
74                        //under Windows, access() is not a reliable way to check if a directory is writable
75                        //http://stackoverflow.com/questions/198071/code-for-checking-write-permissions-for-directories-in-win2k-xp
76                        //bool writable_access = _waccess(Convert::utf8ToUtf16(path).c_str(), W_OK) == 0;
77                        bool writable_trial = isDirWritable(path);
78                        //printf("Checking '%s' for writing(%d) using access(): result=%d\n", path, is_writable, writable_access);
79                        //printf("File creation test: result=%d\n", writable_trial);
80                        //return writable_access;
81                        return writable_trial;
82#else
83                        return access(path, W_OK) == 0;
84#endif
85                }
86                else
87                        return true;
88        }
89        return false;
90}
91
92bool makeDirectory(const char* path)
93{
94#ifdef _WIN32
95        return _wmkdir(Convert::utf8ToUtf16(path).c_str()) == 0;
96#else
97        return mkdir(path,0777) == 0;
98#endif
99}
100
101bool makeDirectories(const char* path)
102{
103        if (directoryExists(path,false)) return true;
104        string parentdir = getFileDir(path);
105        if (!makeDirectories(parentdir.c_str())) return false;
106        return makeDirectory(path);
107}
108
109int getFileSize(const char* path)
110{
111        int size;
112        MFILE *f = mfopen(path, FOPEN_READ_BINARY);
113        if (f == NULL) return -1;
114        size = getFileSize(f);
115        mfclose(f);
116        return size;
117}
118
119int getFileSize(MFILE *f)
120{
121        int saved_pos = mftell(f);
122        mfseek(f, 0, SEEK_END);
123        int size = mftell(f);
124        mfseek(f, saved_pos, SEEK_SET);
125        return size;
126}
127
128bool removeFile(const char* path)
129{
130#ifdef _WIN32
131        return _wunlink(Convert::utf8ToUtf16(path).c_str()) == 0;
132#else
133        return _unlink(path) == 0; //VS: "The POSIX name is deprecated. Instead, use the ISO C++ conformant name: _unlink"
134#endif
135}
136
137bool isAbsolutePath(const char* fname)
138{
139        if (fname == NULL) return false; //SplitFileSystem never passes NULL but this function is public so we never know
140#ifdef _WIN32
141        return PathIsRelativeW(Convert::utf8ToUtf16(fname).c_str()) == FALSE; //http://msdn.microsoft.com/en-us/library/bb773660%28v=vs.85%29.aspx
142#else
143        return fname[0] == PATH_SEPARATOR_CHAR;
144#endif
145}
146
147#if defined SHP && defined BADA_API_1
148
149MFILE *mfopen(const char *path, const char *mode)
150{
151        Osp::Io::File *f = new Osp::Io::File();
152        result r = f->Construct(path, mode);
153        if (IsFailed(r))
154        {
155                delete f;
156                f = NULL;
157        }
158        return f;
159}
160
161void mfclose(MFILE *f)
162{
163        delete f;
164}
165
166int mfread(void *ptr, int size, int count, MFILE *f)
167{
168        int bytes = size * count;
169        int przeczytane = f->Read(ptr, bytes);
170        return przeczytane != bytes ? przeczytane / size : count;
171}
172
173int mfwrite(const void *ptr, int size, int count, MFILE *f)
174{
175        result r = f->Write(ptr, size * count);
176        if (IsFailed(r))
177                return 0; //nie mozemy wykryc jesli udalo sie zapisac czêœæ
178        else
179                return count;
180}
181
182int mfputs(const char *txt, MFILE *f)
183{
184        int len = strlen(txt);
185        int res = mfwrite(txt, len, 1, f);
186        return res == 1 ? 1 : EOF;
187}
188
189char* mfgets(char *str, int num, MFILE *f)
190{
191        bool err = false;
192        int przeczytane = 0;
193        num--; //zeby zawsze zostalo miejsce na wpisanie koncz¹cego NULL
194        do
195        {
196                err = f->Read(str, 1) != 1;
197                if (!err)
198                {
199                        str++;
200                        przeczytane++;
201                }
202        } while (!err && przeczytane<num && *str != '\n');
203        if (*str == '\n' && przeczytane<num)
204                *(str + 1) = 0;
205        return przeczytane == 0 ? NULL : str;
206}
207
208int mfeof(MFILE *f)
209{
210        //brzydkie obejscie zeby w bada wykryc czy FILE jest w stanie EOF
211        static char buf[1];
212        int pos = f->Tell();
213        int przeczytane = f->Read(&buf, 1);
214        f->Seek(Osp::Io::FILESEEKPOSITION_BEGIN,pos);
215        return przeczytane == 1 ? 0 : 1;
216}
217
218int mfseek(MFILE *f, long position, int type)
219{
220        result r;
221        if (type == SEEK_SET)
222                r = f->Seek(Osp::Io::FILESEEKPOSITION_BEGIN, position);
223        else if (type == SEEK_CUR)
224                r = f->Seek(Osp::Io::FILESEEKPOSITION_CURRENT, position);
225        else if (type == SEEK_END)
226                r = f->Seek(Osp::Io::FILESEEKPOSITION_END, position);
227        else
228                return 1;
229        return IsFailed(r) ? 1 : 0;
230}
231
232long mftell(MFILE *f)
233{
234        return f->Tell();
235}
236
237#endif
238
239
240
241
242
243#ifdef __ANDROID__
244#include "log.h"
245#include "dirs.h"
246#include "nonstd_stl.h"
247MFILE *mfopen(const char *path, const char *mode)
248{
249        string respath=getAppResourcesDir();
250        //log_printf("Opening '%s', mode='%s'",path,mode);
251        //log_printf("getAppResourcesDir()='%s'",respath.c_str());
252        //log_printf("getAppWritableDir()='%s'",getAppWritableDir().c_str());
253        NvFile *rfile=NULL; //can only read
254        FILE *rwfile=NULL;
255        if (strstr(path,respath.c_str())==path) //opening resource! so we use a dedicated way to read from assets
256        {
257                path+=respath.length(); //strip the prefix, we need a relative path in assets
258                if (path[0]=='/') path++; //also strip slash if it was there (the prefix has no trailing slash so it doesn't get stipped above)
259                if (strstr(mode,"w"))
260                        log_printf("Warning: attempt to open a read-only resource '%s' in writable mode '%s'",path,mode);
261                rfile=NvFOpen(path); //"mode" not supported! can only read
262                //log_printf("Opened RES file as %p",rfile);
263                if (rfile==NULL) return NULL;
264        } else //a "normal" access (HOME)
265        {
266                rwfile=fopen(path,mode);
267                //log_printf("Opened HOME file as %p",rwfile);
268                if (rwfile==NULL) return NULL;
269        }
270        MFILE *mfile=new MFILE;
271        mfile->rfile=rfile;
272        mfile->rwfile=rwfile;
273        return mfile;
274}
275
276void mfclose(MFILE *f)
277{
278        if (f->rfile)
279                NvFClose(f->rfile);
280        else
281                fclose(f->rwfile);
282
283        delete f;
284}
285
286int mfread(void *ptr, int size, int count, MFILE *f)
287{
288        if (f->rfile)
289                return NvFRead(ptr, size, count, f->rfile); //nvidia introduced my corrections in SDK v10.14, so a fix is no longer needed here
290        else
291                return fread(ptr, size, count, f->rwfile);
292}
293
294int mfwrite(const void *ptr, int size, int count, MFILE *f)
295{
296        if (f->rfile)
297                return 0; //write not supported in assets using nvidia functions
298        else
299                return fwrite(ptr, size, count, f->rwfile);
300}
301
302int mfputs(const char *txt, MFILE *f)
303{
304        int len = strlen(txt);
305        if (len==0) //when writing X 0-byte elements, fwrite() will return 0 ("0 elements written" instead of "X elements") but this is not an error
306                return 1; //for simplicity, we don't even try to write 0 bytes and report a success
307        int res = mfwrite(txt, len, 1, f); //write 1 element of len bytes
308        return res == 1 ? 1 : EOF;
309}
310
311char* mfgets(char *str, int num, MFILE *f)
312{
313        if (f->rfile)
314        {
315                char *ret=NvFGets(str, num, f->rfile);
316                //fixing nvidia inconsistency... their function never returns NULL (fix submitted)
317                if (ret!=NULL && *ret==0 && num>0) //nothing has been read, must have been eof
318                        return NULL;
319                return ret;
320        }
321        else
322                return fgets(str,num,f->rwfile);
323}
324
325int mfeof(MFILE *f)
326{
327        if (f->rfile)
328                return NvFEOF(f->rfile);
329        else
330                return feof(f->rwfile);
331}
332
333int mfseek(MFILE *f, long position, int type)
334{
335        if (f->rfile)
336                return NvFSeek(f->rfile, position, type); //nvidia introduced my corrections in SDK v10.14, so a fix is no longer needed here
337        else
338                return fseek(f->rwfile, position, type);
339}
340
341long mftell(MFILE *f)
342{
343        if (f->rfile)
344                return NvFTell(f->rfile);
345        else
346                return ftell(f->rwfile);
347}
348#endif
Note: See TracBrowser for help on using the repository browser.