Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JSInterface_VFS.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include <sstream>
21 
22 #include "ps/CStr.h"
23 #include "ps/Filesystem.h"
24 //#include "lib/res/file/archive/vfs_optimizer.h" // ArchiveBuilderCancel
28 #include "lib/file/vfs/vfs_util.h"
29 
30 // shared error handling code
31 #define JS_CHECK_FILE_ERR(err)\
32  /* this is liable to happen often, so don't complain */\
33  if (err == ERR::VFS_FILE_NOT_FOUND)\
34  {\
35  JS_SET_RVAL(cx, vp, JSVAL_NULL);\
36  return JS_TRUE;\
37  }\
38  /* unknown failure. we return an error (akin to an exception in JS) that
39  stops the script to make sure this error is noticed. */\
40  else if (err < 0)\
41  return JS_FALSE;\
42  /* else: success */
43 
44 
45 
46 
47 // state held across multiple BuildDirEntListCB calls; init by BuildDirEntList.
49 {
50  JSContext* cx;
51  JSObject* filename_array;
52  int cur_idx;
53 
54  BuildDirEntListState(JSContext* cx_)
55  : cx(cx_)
56  {
57  filename_array = JS_NewArrayObject(cx, 0, NULL);
58  JS_AddObjectRoot(cx, &filename_array);
59  cur_idx = 0;
60  }
61 
63  {
64  JS_RemoveObjectRoot(cx, &filename_array);
65  }
66 };
67 
68 // called for each matching directory entry; add its full pathname to array.
69 static Status BuildDirEntListCB(const VfsPath& pathname, const CFileInfo& UNUSED(fileINfo), uintptr_t cbData)
70 {
72 
73  jsval val = ToJSVal( CStrW(pathname.string()) );
74  JS_SetElement(s->cx, s->filename_array, s->cur_idx++, &val);
75  return INFO::OK;
76 }
77 
78 
79 // Return an array of pathname strings, one for each matching entry in the
80 // specified directory.
81 //
82 // pathnames = buildDirEntList(start_path [, filter_string [, recursive ] ]);
83 // directory: VFS path
84 // filter_string: default "" matches everything; otherwise, see vfs_next_dirent.
85 // recurse: should subdirectories be included in the search? default false.
86 //
87 // note: full pathnames of each file/subdirectory are returned,
88 // ready for use as a "filename" for the other functions.
89 JSBool JSI_VFS::BuildDirEntList(JSContext* cx, uintN argc, jsval* vp)
90 {
91  //
92  // get arguments
93  //
94 
96 
97  CStrW path;
98  if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[0], path))
99  return JS_FALSE;
100 
101  CStrW filter_str = L"";
102  if (argc >= 2)
103  {
104  if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[1], filter_str))
105  return JS_FALSE;
106  }
107  // convert to const wchar_t*; if there's no filter, pass 0 for speed
108  // (interpreted as: "accept all files without comparing").
109  const wchar_t* filter = 0;
110  if (!filter_str.empty())
111  filter = filter_str.c_str();
112 
113  bool recursive = false;
114  if (argc >= 3)
115  {
116  if (!ToPrimitive<bool> (cx, JS_ARGV(cx, vp)[2], recursive))
117  return JS_FALSE;
118  }
119  int flags = recursive ? vfs::DIR_RECURSIVE : 0;
120 
121 
122  // build array in the callback function
124  vfs::ForEachFile(g_VFS, path, BuildDirEntListCB, (uintptr_t)&state, filter, flags);
125 
126  JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(state.filename_array));
127  return JS_TRUE;
128 }
129 
130 
131 // Return time [seconds since 1970] of the last modification to the specified file.
132 //
133 // mtime = getFileMTime(filename);
134 // filename: VFS filename (may include path)
135 JSBool JSI_VFS::GetFileMTime(JSContext* cx, uintN argc, jsval* vp)
136 {
138 
139  CStrW filename;
140  if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[0], filename))
141  return JS_FALSE;
142 
143  CFileInfo fileInfo;
144  Status err = g_VFS->GetFileInfo(filename, &fileInfo);
145  JS_CHECK_FILE_ERR(err);
146 
147  JS_SET_RVAL(cx, vp, ToJSVal((double)fileInfo.MTime()));
148  return JS_TRUE;
149 }
150 
151 
152 // Return current size of file.
153 //
154 // size = getFileSize(filename);
155 // filename: VFS filename (may include path)
156 JSBool JSI_VFS::GetFileSize(JSContext* cx, uintN argc, jsval* vp)
157 {
159 
160  CStrW filename;
161  if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[0], filename))
162  return JS_FALSE;
163 
164  CFileInfo fileInfo;
165  Status err = g_VFS->GetFileInfo(filename, &fileInfo);
166  JS_CHECK_FILE_ERR(err);
167 
168  JS_SET_RVAL(cx, vp, ToJSVal( (unsigned)fileInfo.Size() ));
169  return JS_TRUE;
170 }
171 
172 
173 // Return file contents in a string. Assume file is UTF-8 encoded text.
174 //
175 // contents = readFile(filename);
176 // filename: VFS filename (may include path)
177 JSBool JSI_VFS::ReadFile(JSContext* cx, uintN argc, jsval* vp)
178 {
180 
181  CStrW filename;
182  if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[0], filename))
183  return JS_FALSE;
184 
185  //
186  // read file
187  //
188  CVFSFile file;
189  if (file.Load(g_VFS, filename) != PSRETURN_OK)
190  {
191  JS_SET_RVAL(cx, vp, JSVAL_NULL);
192  return JS_TRUE;
193  }
194 
195  CStr contents = file.DecodeUTF8(); // assume it's UTF-8
196 
197  // Fix CRLF line endings. (This function will only ever be used on text files.)
198  contents.Replace("\r\n", "\n");
199 
200  // Decode as UTF-8
201  JS_SET_RVAL(cx, vp, ToJSVal( contents.FromUTF8() ));
202  return JS_TRUE;
203 }
204 
205 
206 // Return file contents as an array of lines. Assume file is UTF-8 encoded text.
207 //
208 // lines = readFileLines(filename);
209 // filename: VFS filename (may include path)
210 JSBool JSI_VFS::ReadFileLines(JSContext* cx, uintN argc, jsval* vp)
211 {
213 
214  CStrW filename;
215  if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[0], filename))
216  return (JS_FALSE);
217 
218  //
219  // read file
220  //
221  CVFSFile file;
222  if (file.Load(g_VFS, filename) != PSRETURN_OK)
223  {
224  JS_SET_RVAL(cx, vp, JSVAL_NULL);
225  return JS_TRUE;
226  }
227 
228  CStr contents = file.DecodeUTF8(); // assume it's UTF-8
229 
230  // Fix CRLF line endings. (This function will only ever be used on text files.)
231  contents.Replace("\r\n", "\n");
232 
233  //
234  // split into array of strings (one per line)
235  //
236 
237  std::stringstream ss(contents);
238 
239  JSObject* line_array = JS_NewArrayObject(cx, 0, NULL);
240 
241  std::string line;
242  int cur_line = 0;
243  while (std::getline(ss, line))
244  {
245  // Decode each line as UTF-8
246  jsval val = ToJSVal(CStr(line).FromUTF8());
247  JS_SetElement(cx, line_array, cur_line++, &val);
248  }
249 
250  JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL( line_array ));
251  return JS_TRUE ;
252 }
253 
254 
255 // vfs_optimizer
256 
257 JSBool JSI_VFS::ArchiveBuilderCancel(JSContext* cx, uintN argc, jsval* vp)
258 {
259  UNUSED2(cx);
260  UNUSED2(argc);
261 
262 // vfs_opt_auto_build_cancel();
263 
264  JS_SET_RVAL(cx, vp, JSVAL_VOID);
265  return JS_TRUE;
266 }
BuildDirEntListState(JSContext *cx_)
CStr DecodeUTF8() const
Returns contents of a UTF-8 encoded file as a string with optional BOM removed.
Definition: Filesystem.cpp:153
bool ToPrimitive< CStrW >(JSContext *cx, jsval v, CStrW &Storage)
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
const Status OK
Definition: status.h:386
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
Reads a file, then gives read-only access to the contents.
Definition: Filesystem.h:69
bool ToPrimitive< bool >(JSContext *cx, jsval v, bool &Storage)
JSBool GetFileMTime(JSContext *cx, uintN argc, jsval *vp)
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning...
Definition: path.h:75
const String & string() const
Definition: path.h:123
off_t Size() const
Definition: file_system.h:58
static Status BuildDirEntListCB(const VfsPath &pathname, const CFileInfo &fileINfo, uintptr_t cbData)
i64 Status
Error handling system.
Definition: status.h:171
JSBool ReadFile(JSContext *cx, uintN argc, jsval *vp)
time_t MTime() const
Definition: file_system.h:63
Status ForEachFile(const PIVFS &fs, const VfsPath &startPath, FileCallback cb, uintptr_t cbData, const wchar_t *pattern, size_t flags)
call back for each file in a directory tree
Definition: vfs_util.cpp:58
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
Definition: Filesystem.cpp:117
jsval ToJSVal(T &Native)
Definition: JSConversions.h:87
JSBool BuildDirEntList(JSContext *cx, uintN argc, jsval *vp)
JSBool ReadFileLines(JSContext *cx, uintN argc, jsval *vp)
#define JS_CHECK_FILE_ERR(err)
JSBool ArchiveBuilderCancel(JSContext *cx, uintN argc, jsval *vp)
PIVFS g_VFS
Definition: Filesystem.cpp:30
#define JSU_REQUIRE_MIN_PARAMS(min_number)
Definition: JSUtil.h:42
JSBool GetFileSize(JSContext *cx, uintN argc, jsval *vp)
static enum @41 state