/[jscoverage]/trunk/js/jsfile.cpp
ViewVC logotype

Annotation of /trunk/js/jsfile.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (hide annotations)
Sun Jan 10 07:23:34 2010 UTC (10 years, 7 months ago) by siliconforks
File size: 82924 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

1 siliconforks 507 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 siliconforks 332 * vim: set ts=8 sw=4 et tw=78:
3     *
4     * ***** BEGIN LICENSE BLOCK *****
5     * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6     *
7     * The contents of this file are subject to the Mozilla Public License Version
8     * 1.1 (the "License"); you may not use this file except in compliance with
9     * the License. You may obtain a copy of the License at
10     * http://www.mozilla.org/MPL/
11     *
12     * Software distributed under the License is distributed on an "AS IS" basis,
13     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14     * for the specific language governing rights and limitations under the
15     * License.
16     *
17     * The Original Code is Mozilla Communicator client code, released
18     * March 31, 1998.
19     *
20     * The Initial Developer of the Original Code is
21     * Netscape Communications Corporation.
22     * Portions created by the Initial Developer are Copyright (C) 1998
23     * the Initial Developer. All Rights Reserved.
24     *
25     * Contributor(s):
26     *
27     * Alternatively, the contents of this file may be used under the terms of
28     * either of the GNU General Public License Version 2 or later (the "GPL"),
29     * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30     * in which case the provisions of the GPL or the LGPL are applicable instead
31     * of those above. If you wish to allow use of your version of this file only
32     * under the terms of either the GPL or the LGPL, and not to allow others to
33     * use your version of this file under the terms of the MPL, indicate your
34     * decision by deleting the provisions above and replace them with the notice
35     * and other provisions required by the GPL or the LGPL. If you do not delete
36     * the provisions above, a recipient may use your version of this file under
37     * the terms of any one of the MPL, the GPL or the LGPL.
38     *
39     * ***** END LICENSE BLOCK ***** */
40    
41     /*
42     * JS File object
43     */
44     #if JS_HAS_FILE_OBJECT
45    
46     #include "jsfile.h"
47 siliconforks 507 #include "jsstdint.h"
48 siliconforks 332
49     /* ----------------- Platform-specific includes and defines ----------------- */
50     #if defined(XP_WIN) || defined(XP_OS2)
51     # include <direct.h>
52     # include <io.h>
53     # include <sys/types.h>
54     # include <sys/stat.h>
55     # define FILESEPARATOR '\\'
56     # define FILESEPARATOR2 '/'
57     # define CURRENT_DIR "c:\\"
58     # define POPEN _popen
59     # define PCLOSE _pclose
60 siliconforks 460 #elif defined(SYMBIAN)
61     # include <strings.h>
62     # include <stdio.h>
63     # include <stdlib.h>
64     # include <unistd.h>
65     # include <limits.h>
66     # define FILESEPARATOR '\\'
67     # define FILESEPARATOR2 '/'
68     # define CURRENT_DIR "c:\\"
69     # define POPEN popen
70     # define PCLOSE pclose
71 siliconforks 332 #elif defined(XP_UNIX) || defined(XP_BEOS)
72     # include <strings.h>
73     # include <stdio.h>
74     # include <stdlib.h>
75     # include <unistd.h>
76 siliconforks 507 # include <limits.h>
77 siliconforks 332 # define FILESEPARATOR '/'
78     # define FILESEPARATOR2 '\0'
79     # define CURRENT_DIR "/"
80     # define POPEN popen
81     # define PCLOSE pclose
82     #endif
83    
84     /* --------------- Platform-independent includes and defines ---------------- */
85     #include "jsapi.h"
86     #include "jsatom.h"
87     #include "jscntxt.h"
88     #include "jsdate.h"
89     #include "jsdbgapi.h"
90     #include "jsemit.h"
91     #include "jsfun.h"
92     #include "jslock.h"
93     #include "jsobj.h"
94     #include "jsparse.h"
95     #include "jsscan.h"
96     #include "jsscope.h"
97     #include "jsscript.h"
98     #include "jsstr.h"
99     #include "jsutil.h" /* Added by JSIFY */
100     #include <string.h>
101    
102     /* NSPR dependencies */
103     #include "prio.h"
104     #include "prerror.h"
105    
106     #define SPECIAL_FILE_STRING "Special File"
107     #define CURRENTDIR_PROPERTY "currentDir"
108     #define SEPARATOR_PROPERTY "separator"
109     #define FILE_CONSTRUCTOR "File"
110     #define PIPE_SYMBOL '|'
111    
112     #define ASCII 0
113     #define UTF8 1
114     #define UCS2 2
115    
116     #define asciistring "text"
117     #define utfstring "binary"
118     #define unicodestring "unicode"
119    
120 siliconforks 507 #ifdef PATH_MAX
121     #define MAX_PATH_LENGTH PATH_MAX
122     #else
123 siliconforks 332 #define MAX_PATH_LENGTH 1024
124 siliconforks 507 #endif
125 siliconforks 332 #define MODE_SIZE 256
126     #define NUMBER_SIZE 32
127     #define MAX_LINE_LENGTH 256
128     #define URL_PREFIX "file://"
129    
130     #define STDINPUT_NAME "Standard input stream"
131     #define STDOUTPUT_NAME "Standard output stream"
132     #define STDERROR_NAME "Standard error stream"
133    
134     #define RESOLVE_PATH js_canonicalPath /* js_absolutePath */
135    
136     /* Error handling */
137     typedef enum JSFileErrNum {
138     #define MSG_DEF(name, number, count, exception, format) \
139     name = number,
140     #include "jsfile.msg"
141     #undef MSG_DEF
142     JSFileErr_Limit
143     #undef MSGDEF
144     } JSFileErrNum;
145    
146     #define JSFILE_HAS_DFLT_MSG_STRINGS 1
147    
148     JSErrorFormatString JSFile_ErrorFormatString[JSFileErr_Limit] = {
149     #if JSFILE_HAS_DFLT_MSG_STRINGS
150     #define MSG_DEF(name, number, count, exception, format) \
151     { format, count },
152     #else
153     #define MSG_DEF(name, number, count, exception, format) \
154     { NULL, count },
155     #endif
156     #include "jsfile.msg"
157     #undef MSG_DEF
158     };
159    
160     const JSErrorFormatString *
161     JSFile_GetErrorMessage(void *userRef, const char *locale,
162     const uintN errorNumber)
163     {
164     if ((errorNumber > 0) && (errorNumber < JSFileErr_Limit))
165     return &JSFile_ErrorFormatString[errorNumber];
166     else
167     return NULL;
168     }
169    
170     #define JSFILE_CHECK_NATIVE(op) \
171     if (file->isNative) { \
172     JS_ReportWarning(cx, "Cannot call or access \"%s\" on native file %s",\
173     op, file->path); \
174     goto out; \
175     }
176    
177     #define JSFILE_CHECK_WRITE \
178     if (!file->isOpen) { \
179     JS_ReportWarning(cx, \
180     "File %s is closed, will open it for writing, proceeding", \
181     file->path); \
182     js_FileOpen(cx, obj, file, "write,append,create"); \
183     } \
184     if (!js_canWrite(cx, file)) { \
185     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
186     JSFILEMSG_CANNOT_WRITE, file->path); \
187     goto out; \
188     }
189    
190     #define JSFILE_CHECK_READ \
191     if (!file->isOpen) { \
192     JS_ReportWarning(cx, \
193     "File %s is closed, will open it for reading, proceeding", \
194     file->path); \
195     js_FileOpen(cx, obj, file, "read"); \
196     } \
197     if (!js_canRead(cx, file)) { \
198     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
199     JSFILEMSG_CANNOT_READ, file->path); \
200     goto out; \
201     }
202    
203     #define JSFILE_CHECK_OPEN(op) \
204     if (!file->isOpen) { \
205     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
206     JSFILEMSG_FILE_MUST_BE_OPEN, op); \
207     goto out; \
208     }
209    
210     #define JSFILE_CHECK_CLOSED(op) \
211     if (file->isOpen) { \
212     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
213     JSFILEMSG_FILE_MUST_BE_CLOSED, op); \
214     goto out; \
215     }
216    
217     #define JSFILE_CHECK_ONE_ARG(op) \
218     if (argc != 1) { \
219     char str[NUMBER_SIZE]; \
220     sprintf(str, "%d", argc); \
221     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
222     JSFILEMSG_EXPECTS_ONE_ARG_ERROR, op, str); \
223     goto out; \
224     }
225    
226    
227     /*
228     Security mechanism, should define a callback for this.
229     The parameters are as follows:
230     SECURITY_CHECK(JSContext *cx, JSPrincipals *ps, char *op_name, JSFile *file)
231     XXX Should this be a real function returning a JSBool result (and getting
232     some typesafety help from the compiler?).
233     */
234     #define SECURITY_CHECK(cx, ps, op, file) \
235     /* Define a callback here... */
236    
237    
238     /* Structure representing the file internally */
239     typedef struct JSFile {
240     char *path; /* the path to the file. */
241     JSBool isOpen;
242     int32 mode; /* mode used to open the file: read, write, append, create, etc.. */
243     int32 type; /* Asciiz, utf, unicode */
244     char byteBuffer[3]; /* bytes read in advance by js_FileRead ( UTF8 encoding ) */
245     jsint nbBytesInBuf; /* number of bytes stored in the buffer above */
246     jschar charBuffer; /* character read in advance by readln ( mac files only ) */
247     JSBool charBufferUsed; /* flag indicating if the buffer above is being used */
248     JSBool hasRandomAccess;/* can the file be randomly accessed? false for stdin, and
249     UTF-encoded files. */
250     JSBool hasAutoflush; /* should we force a flush for each line break? */
251     JSBool isNative; /* if the file is using OS-specific file FILE type */
252     /* We can actually put the following two in a union since they should never be used at the same time */
253     PRFileDesc *handle; /* the handle for the file, if open. */
254     FILE *nativehandle; /* native handle, for stuff NSPR doesn't do. */
255     JSBool isPipe; /* if the file is really an OS pipe */
256     } JSFile;
257    
258     /* a few forward declarations... */
259     JS_PUBLIC_API(JSObject*) js_NewFileObject(JSContext *cx, char *filename);
260     static JSBool file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
261     static JSBool file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
262    
263     /* New filename manipulation procesures */
264     /* assumes we don't have leading/trailing spaces */
265     static JSBool
266     js_filenameHasAPipe(const char *filename)
267     {
268     if (!filename)
269     return JS_FALSE;
270    
271     return filename[0] == PIPE_SYMBOL ||
272     filename[strlen(filename) - 1] == PIPE_SYMBOL;
273     }
274    
275     static JSBool
276     js_isAbsolute(const char *name)
277     {
278 siliconforks 460 #if defined(XP_WIN) || defined(XP_OS2) || defined(SYMBIAN)
279 siliconforks 332 return *name && name[1] == ':';
280     #else
281     return (name[0]
282     # if defined(XP_UNIX) || defined(XP_BEOS)
283     ==
284     # else
285     !=
286     # endif
287     FILESEPARATOR);
288     #endif
289     }
290    
291     /*
292     * Concatenates base and name to produce a valid filename.
293     * Returned string must be freed.
294     */
295     static char*
296     js_combinePath(JSContext *cx, const char *base, const char *name)
297     {
298     int len = strlen(base);
299 siliconforks 507 char* result = cx->malloc(len + strlen(name) + 2);
300 siliconforks 332
301     if (!result)
302     return NULL;
303    
304     strcpy(result, base);
305    
306     if (base[len - 1] != FILESEPARATOR && base[len - 1] != FILESEPARATOR2) {
307     result[len] = FILESEPARATOR;
308     result[len + 1] = '\0';
309     }
310     strcat(result, name);
311     return result;
312     }
313    
314     /* Extract the last component from a path name. Returned string must be freed */
315     static char *
316     js_fileBaseName(JSContext *cx, const char *pathname)
317     {
318     jsint index, aux;
319     char *result;
320    
321     index = strlen(pathname)-1;
322    
323 siliconforks 507 /* Chop off trailing separators. */
324 siliconforks 332 while (index > 0 && (pathname[index]==FILESEPARATOR ||
325     pathname[index]==FILESEPARATOR2)) {
326     --index;
327     }
328    
329     aux = index;
330    
331     /* Now find the next separator. */
332     while (index >= 0 && pathname[index] != FILESEPARATOR &&
333     pathname[index] != FILESEPARATOR2) {
334     --index;
335     }
336    
337     /* Allocate and copy. */
338 siliconforks 507 result = cx->malloc(aux - index + 1);
339 siliconforks 332 if (!result)
340     return NULL;
341     strncpy(result, pathname + index + 1, aux - index);
342     result[aux - index] = '\0';
343     return result;
344     }
345    
346     /*
347     * Returns everything but the last component from a path name.
348     * Returned string must be freed.
349     */
350     static char *
351     js_fileDirectoryName(JSContext *cx, const char *pathname)
352     {
353     char *result;
354     const char *cp, *end;
355     size_t pathsize;
356    
357     end = pathname + strlen(pathname);
358     cp = end - 1;
359    
360     /* If this is already a directory, chop off the trailing /s. */
361     while (cp >= pathname) {
362     if (*cp != FILESEPARATOR && *cp != FILESEPARATOR2)
363     break;
364     --cp;
365     }
366    
367     if (cp < pathname && end != pathname) {
368     /* There were just /s, return the root. */
369 siliconforks 507 result = cx->malloc(1 + 1); /* The separator + trailing NUL. */
370 siliconforks 332 result[0] = FILESEPARATOR;
371     result[1] = '\0';
372     return result;
373     }
374    
375     /* Now chop off the last portion. */
376     while (cp >= pathname) {
377     if (*cp == FILESEPARATOR || *cp == FILESEPARATOR2)
378     break;
379     --cp;
380     }
381    
382     /* Check if this is a leaf. */
383     if (cp < pathname) {
384     /* It is, return "pathname/". */
385     if (end[-1] == FILESEPARATOR || end[-1] == FILESEPARATOR2) {
386     /* Already has its terminating /. */
387     return JS_strdup(cx, pathname);
388     }
389    
390     pathsize = end - pathname + 1;
391 siliconforks 507 result = cx->malloc(pathsize + 1);
392 siliconforks 332 if (!result)
393     return NULL;
394    
395     strcpy(result, pathname);
396     result[pathsize - 1] = FILESEPARATOR;
397     result[pathsize] = '\0';
398    
399     return result;
400     }
401    
402     /* Return everything up to and including the seperator. */
403     pathsize = cp - pathname + 1;
404 siliconforks 507 result = cx->malloc(pathsize + 1);
405 siliconforks 332 if (!result)
406     return NULL;
407    
408     strncpy(result, pathname, pathsize);
409     result[pathsize] = '\0';
410    
411     return result;
412     }
413    
414     static char *
415     js_absolutePath(JSContext *cx, const char * path)
416     {
417     JSObject *obj;
418     JSString *str;
419     jsval prop;
420    
421     if (js_isAbsolute(path)) {
422     return JS_strdup(cx, path);
423     } else {
424     obj = JS_GetGlobalObject(cx);
425     if (!JS_GetProperty(cx, obj, FILE_CONSTRUCTOR, &prop)) {
426     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
427     JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR);
428     return JS_strdup(cx, path);
429     }
430    
431     obj = JSVAL_TO_OBJECT(prop);
432     if (!JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, &prop)) {
433     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
434     JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR);
435     return JS_strdup(cx, path);
436     }
437    
438     str = JS_ValueToString(cx, prop);
439     if (!str)
440     return JS_strdup(cx, path);
441    
442     /* should we have an array of curr dirs indexed by drive for windows? */
443     return js_combinePath(cx, JS_GetStringBytes(str), path);
444     }
445     }
446    
447     /* Side effect: will remove spaces in the beginning/end of the filename */
448     static char *
449     js_canonicalPath(JSContext *cx, char *oldpath)
450     {
451     char *tmp;
452     char *path = oldpath;
453     char *base, *dir, *current, *result;
454     jsint c;
455     jsint back = 0;
456     unsigned int i = 0, j = strlen(path)-1;
457    
458     /* This is probably optional */
459     /* Remove possible spaces in the beginning and end */
460     while (i < j && path[i] == ' ')
461     i++;
462     while (j >= 0 && path[j] == ' ')
463     j--;
464    
465 siliconforks 507 tmp = cx->malloc(j-i+2);
466 siliconforks 332 if (!tmp)
467     return NULL;
468    
469     strncpy(tmp, path + i, j - i + 1);
470     tmp[j - i + 1] = '\0';
471    
472     path = tmp;
473    
474     /* Pipe support. */
475     if (js_filenameHasAPipe(path))
476     return path;
477    
478     /* file:// support. */
479     if (!strncmp(path, URL_PREFIX, strlen(URL_PREFIX))) {
480     tmp = js_canonicalPath(cx, path + strlen(URL_PREFIX));
481 siliconforks 507 cx->free(path);
482 siliconforks 332 return tmp;
483     }
484    
485     if (!js_isAbsolute(path)) {
486     tmp = js_absolutePath(cx, path);
487     if (!tmp)
488     return NULL;
489 siliconforks 507 cx->free(path);
490 siliconforks 332 path = tmp;
491     }
492    
493     result = JS_strdup(cx, "");
494    
495     current = path;
496    
497     base = js_fileBaseName(cx, current);
498     dir = js_fileDirectoryName(cx, current);
499    
500     while (strcmp(dir, current)) {
501     if (!strcmp(base, "..")) {
502     back++;
503     } else {
504     if (back > 0) {
505     back--;
506     } else {
507     tmp = result;
508 siliconforks 507 result = cx->malloc(strlen(base) + 1 + strlen(tmp) + 1);
509 siliconforks 332 if (!result)
510     goto out;
511    
512     strcpy(result, base);
513     c = strlen(result);
514     if (*tmp) {
515     result[c] = FILESEPARATOR;
516     result[c + 1] = '\0';
517     strcat(result, tmp);
518     }
519 siliconforks 507 cx->free(tmp);
520 siliconforks 332 }
521     }
522 siliconforks 507 cx->free(current);
523     cx->free(base);
524 siliconforks 332 current = dir;
525     base = js_fileBaseName(cx, current);
526     dir = js_fileDirectoryName(cx, current);
527     }
528    
529     tmp = result;
530 siliconforks 507 result = cx->malloc(strlen(dir) + 1 + strlen(tmp) + 1);
531 siliconforks 332 if (!result)
532     goto out;
533    
534     strcpy(result, dir);
535     c = strlen(result);
536     if (tmp[0]!='\0') {
537     if ((result[c-1]!=FILESEPARATOR)&&(result[c-1]!=FILESEPARATOR2)) {
538     result[c] = FILESEPARATOR;
539     result[c+1] = '\0';
540     }
541     strcat(result, tmp);
542     }
543    
544     out:
545     if (tmp)
546 siliconforks 507 cx->free(tmp);
547 siliconforks 332 if (dir)
548 siliconforks 507 cx->free(dir);
549 siliconforks 332 if (base)
550 siliconforks 507 cx->free(base);
551 siliconforks 332 if (current)
552 siliconforks 507 cx->free(current);
553 siliconforks 332
554     return result;
555     }
556    
557     /* -------------------------- Text conversion ------------------------------- */
558     /* The following is ripped from libi18n/unicvt.c and include files.. */
559    
560     /*
561     * UTF8 defines and macros
562     */
563     #define ONE_OCTET_BASE 0x00 /* 0xxxxxxx */
564     #define ONE_OCTET_MASK 0x7F /* x1111111 */
565     #define CONTINUING_OCTET_BASE 0x80 /* 10xxxxxx */
566     #define CONTINUING_OCTET_MASK 0x3F /* 00111111 */
567     #define TWO_OCTET_BASE 0xC0 /* 110xxxxx */
568     #define TWO_OCTET_MASK 0x1F /* 00011111 */
569     #define THREE_OCTET_BASE 0xE0 /* 1110xxxx */
570     #define THREE_OCTET_MASK 0x0F /* 00001111 */
571     #define FOUR_OCTET_BASE 0xF0 /* 11110xxx */
572     #define FOUR_OCTET_MASK 0x07 /* 00000111 */
573     #define FIVE_OCTET_BASE 0xF8 /* 111110xx */
574     #define FIVE_OCTET_MASK 0x03 /* 00000011 */
575     #define SIX_OCTET_BASE 0xFC /* 1111110x */
576     #define SIX_OCTET_MASK 0x01 /* 00000001 */
577    
578     #define IS_UTF8_1ST_OF_1(x) (( (x)&~ONE_OCTET_MASK ) == ONE_OCTET_BASE)
579     #define IS_UTF8_1ST_OF_2(x) (( (x)&~TWO_OCTET_MASK ) == TWO_OCTET_BASE)
580     #define IS_UTF8_1ST_OF_3(x) (( (x)&~THREE_OCTET_MASK) == THREE_OCTET_BASE)
581     #define IS_UTF8_1ST_OF_4(x) (( (x)&~FOUR_OCTET_MASK ) == FOUR_OCTET_BASE)
582     #define IS_UTF8_1ST_OF_5(x) (( (x)&~FIVE_OCTET_MASK ) == FIVE_OCTET_BASE)
583     #define IS_UTF8_1ST_OF_6(x) (( (x)&~SIX_OCTET_MASK ) == SIX_OCTET_BASE)
584     #define IS_UTF8_2ND_THRU_6TH(x) \
585     (( (x)&~CONTINUING_OCTET_MASK ) == CONTINUING_OCTET_BASE)
586     #define IS_UTF8_1ST_OF_UCS2(x) \
587     IS_UTF8_1ST_OF_1(x) \
588     || IS_UTF8_1ST_OF_2(x) \
589     || IS_UTF8_1ST_OF_3(x)
590    
591    
592     #define MAX_UCS2 0xFFFF
593     #define DEFAULT_CHAR 0x003F /* Default char is "?" */
594     #define BYTE_MASK 0xBF
595     #define BYTE_MARK 0x80
596    
597    
598     /* Function: one_ucs2_to_utf8_char
599     *
600     * Function takes one UCS-2 char and writes it to a UTF-8 buffer.
601     * We need a UTF-8 buffer because we don't know before this
602     * function how many bytes of utf-8 data will be written. It also
603     * takes a pointer to the end of the UTF-8 buffer so that we don't
604     * overwrite data. This function returns the number of UTF-8 bytes
605     * of data written, or -1 if the buffer would have been overrun.
606     */
607    
608     #define LINE_SEPARATOR 0x2028
609     #define PARAGRAPH_SEPARATOR 0x2029
610     static int16 one_ucs2_to_utf8_char(unsigned char *tobufp,
611     unsigned char *tobufendp,
612     uint16 onechar)
613     {
614     int16 numUTF8bytes = 0;
615    
616     if (onechar == LINE_SEPARATOR || onechar == PARAGRAPH_SEPARATOR) {
617     strcpy((char*)tobufp, "\n");
618     return strlen((char*)tobufp);
619     }
620    
621     if (onechar < 0x80) {
622     numUTF8bytes = 1;
623     } else if (onechar < 0x800) {
624     numUTF8bytes = 2;
625     } else {
626     /* 0x800 >= onechar <= MAX_UCS2 */
627     numUTF8bytes = 3;
628     }
629    
630     tobufp += numUTF8bytes;
631    
632     /* return error if we don't have space for the whole character */
633     if (tobufp > tobufendp) {
634     return(-1);
635     }
636    
637     switch(numUTF8bytes) {
638     case 3: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6;
639     *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6;
640     *--tobufp = onechar | THREE_OCTET_BASE;
641     break;
642    
643     case 2: *--tobufp = (onechar | BYTE_MARK) & BYTE_MASK; onechar >>=6;
644     *--tobufp = onechar | TWO_OCTET_BASE;
645     break;
646    
647     case 1: *--tobufp = (unsigned char)onechar;
648     break;
649     }
650    
651     return numUTF8bytes;
652     }
653    
654     /*
655     * utf8_to_ucs2_char
656     *
657     * Convert a utf8 multibyte character to ucs2
658     *
659     * inputs: pointer to utf8 character(s)
660     * length of utf8 buffer ("read" length limit)
661     * pointer to return ucs2 character
662     *
663     * outputs: number of bytes in the utf8 character
664     * -1 if not a valid utf8 character sequence
665     * -2 if the buffer is too short
666     */
667     static int16
668     utf8_to_ucs2_char(const unsigned char *utf8p, int16 buflen, uint16 *ucs2p)
669     {
670     uint16 lead, cont1, cont2;
671    
672     /*
673     * Check for minimum buffer length
674     */
675     if ((buflen < 1) || (utf8p == NULL)) {
676     return -2;
677     }
678     lead = (uint16) (*utf8p);
679    
680     /*
681     * Check for a one octet sequence
682     */
683     if (IS_UTF8_1ST_OF_1(lead)) {
684     *ucs2p = lead & ONE_OCTET_MASK;
685     return 1;
686     }
687    
688     /*
689     * Check for a two octet sequence
690     */
691     if (IS_UTF8_1ST_OF_2(*utf8p)) {
692     if (buflen < 2)
693     return -2;
694     cont1 = (uint16) *(utf8p+1);
695     if (!IS_UTF8_2ND_THRU_6TH(cont1))
696     return -1;
697     *ucs2p = (lead & TWO_OCTET_MASK) << 6;
698     *ucs2p |= cont1 & CONTINUING_OCTET_MASK;
699     return 2;
700     }
701    
702     /*
703     * Check for a three octet sequence
704     */
705     else if (IS_UTF8_1ST_OF_3(lead)) {
706     if (buflen < 3)
707     return -2;
708     cont1 = (uint16) *(utf8p+1);
709     cont2 = (uint16) *(utf8p+2);
710     if ( (!IS_UTF8_2ND_THRU_6TH(cont1))
711     || (!IS_UTF8_2ND_THRU_6TH(cont2)))
712     return -1;
713     *ucs2p = (lead & THREE_OCTET_MASK) << 12;
714     *ucs2p |= (cont1 & CONTINUING_OCTET_MASK) << 6;
715     *ucs2p |= cont2 & CONTINUING_OCTET_MASK;
716     return 3;
717     }
718     else { /* not a valid utf8/ucs2 character */
719     return -1;
720     }
721     }
722    
723     /* ----------------------------- Helper functions --------------------------- */
724     /* Ripped off from lm_win.c .. */
725     /* where is strcasecmp?.. for now, it's case sensitive..
726     *
727     * strcasecmp is in strings.h, but on windows it's called _stricmp...
728     * will need to #ifdef this
729     */
730    
731     static int32
732     js_FileHasOption(JSContext *cx, const char *oldoptions, const char *name)
733     {
734     char *comma, *equal, *current;
735     char *options = JS_strdup(cx, oldoptions);
736     int32 found = 0;
737    
738     current = options;
739     for (;;) {
740     comma = strchr(current, ',');
741     if (comma) *comma = '\0';
742     equal = strchr(current, '=');
743     if (equal) *equal = '\0';
744     if (strcmp(current, name) == 0) {
745     if (!equal || strcmp(equal + 1, "yes") == 0)
746     found = 1;
747     else
748     found = atoi(equal + 1);
749     }
750     if (equal) *equal = '=';
751     if (comma) *comma = ',';
752     if (found || !comma)
753     break;
754     current = comma + 1;
755     }
756 siliconforks 507 cx->free(options);
757 siliconforks 332 return found;
758     }
759    
760     /* empty the buffer */
761     static void
762     js_ResetBuffers(JSFile * file)
763     {
764     file->charBufferUsed = JS_FALSE;
765     file->nbBytesInBuf = 0;
766     }
767    
768     /* Reset file attributes */
769     static void
770     js_ResetAttributes(JSFile * file)
771     {
772     file->mode = file->type = 0;
773     file->isOpen = JS_FALSE;
774     file->handle = NULL;
775     file->nativehandle = NULL;
776     file->hasRandomAccess = JS_TRUE; /* Innocent until proven guilty. */
777     file->hasAutoflush = JS_FALSE;
778     file->isNative = JS_FALSE;
779     file->isPipe = JS_FALSE;
780    
781     js_ResetBuffers(file);
782     }
783    
784     static JSBool
785     js_FileOpen(JSContext *cx, JSObject *obj, JSFile *file, char *mode){
786     JSString *type, *mask;
787     jsval v[2];
788     jsval rval;
789    
790     type = JS_InternString(cx, asciistring);
791     mask = JS_NewStringCopyZ(cx, mode);
792     v[0] = STRING_TO_JSVAL(mask);
793     v[1] = STRING_TO_JSVAL(type);
794    
795     if (!file_open(cx, obj, 2, v, &rval))
796     return JS_FALSE;
797     return JS_TRUE;
798     }
799    
800     /* Buffered version of PR_Read. Used by js_FileRead */
801     static int32
802     js_BufferedRead(JSFile *f, unsigned char *buf, int32 len)
803     {
804     int32 count = 0;
805    
806     while (f->nbBytesInBuf>0&&len>0) {
807     buf[0] = f->byteBuffer[0];
808     f->byteBuffer[0] = f->byteBuffer[1];
809     f->byteBuffer[1] = f->byteBuffer[2];
810     f->nbBytesInBuf--;
811     len--;
812     buf+=1;
813     count++;
814     }
815    
816     if (len > 0) {
817     count += (!f->isNative)
818     ? PR_Read(f->handle, buf, len)
819     : fread(buf, 1, len, f->nativehandle);
820     }
821     return count;
822     }
823    
824     static int32
825     js_FileRead(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode)
826     {
827     unsigned char *aux;
828     int32 count = 0, i;
829     jsint remainder;
830     unsigned char utfbuf[3];
831    
832     if (file->charBufferUsed) {
833     buf[0] = file->charBuffer;
834     buf++;
835     len--;
836     file->charBufferUsed = JS_FALSE;
837     }
838    
839     switch (mode) {
840     case ASCII:
841 siliconforks 507 aux = (unsigned char*)cx->malloc(len);
842 siliconforks 332 if (!aux)
843     return 0;
844    
845     count = js_BufferedRead(file, aux, len);
846     if (count == -1) {
847 siliconforks 507 cx->free(aux);
848 siliconforks 332 return 0;
849     }
850    
851     for (i = 0; i < len; i++)
852     buf[i] = (jschar)aux[i];
853    
854 siliconforks 507 cx->free(aux);
855 siliconforks 332 break;
856    
857     case UTF8:
858     remainder = 0;
859     for (count = 0;count<len;count++) {
860     i = js_BufferedRead(file, utfbuf+remainder, 3-remainder);
861     if (i<=0) {
862     return count;
863     }
864     i = utf8_to_ucs2_char(utfbuf, (int16)i, &buf[count] );
865     if (i<0) {
866     return count;
867     } else {
868     if (i==1) {
869     utfbuf[0] = utfbuf[1];
870     utfbuf[1] = utfbuf[2];
871     remainder = 2;
872     } else if (i==2) {
873     utfbuf[0] = utfbuf[2];
874     remainder = 1;
875     } else if (i==3) {
876     remainder = 0;
877     }
878     }
879     }
880     while (remainder>0) {
881     file->byteBuffer[file->nbBytesInBuf] = utfbuf[0];
882     file->nbBytesInBuf++;
883     utfbuf[0] = utfbuf[1];
884     utfbuf[1] = utfbuf[2];
885     remainder--;
886     }
887     break;
888    
889     case UCS2:
890     count = js_BufferedRead(file, (unsigned char *)buf, len * 2) >> 1;
891     if (count == -1)
892     return 0;
893    
894     break;
895    
896     default:
897     /* Not reached. */
898     JS_ASSERT(0);
899     }
900    
901     if(count == -1) {
902     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
903     JSFILEMSG_OP_FAILED, "read", file->path);
904     }
905    
906     return count;
907     }
908    
909     static int32
910     js_FileSeek(JSContext *cx, JSFile *file, int32 len, int32 mode)
911     {
912     int32 count = 0, i;
913     jsint remainder;
914     unsigned char utfbuf[3];
915     jschar tmp;
916    
917     switch (mode) {
918     case ASCII:
919     count = PR_Seek(file->handle, len, PR_SEEK_CUR);
920     break;
921    
922     case UTF8:
923     remainder = 0;
924     for (count = 0;count<len;count++) {
925     i = js_BufferedRead(file, utfbuf+remainder, 3-remainder);
926     if (i<=0) {
927     return 0;
928     }
929     i = utf8_to_ucs2_char(utfbuf, (int16)i, &tmp );
930     if (i<0) {
931     return 0;
932     } else {
933     if (i==1) {
934     utfbuf[0] = utfbuf[1];
935     utfbuf[1] = utfbuf[2];
936     remainder = 2;
937     } else if (i==2) {
938     utfbuf[0] = utfbuf[2];
939     remainder = 1;
940     } else if (i==3) {
941     remainder = 0;
942     }
943     }
944     }
945     while (remainder>0) {
946     file->byteBuffer[file->nbBytesInBuf] = utfbuf[0];
947     file->nbBytesInBuf++;
948     utfbuf[0] = utfbuf[1];
949     utfbuf[1] = utfbuf[2];
950     remainder--;
951     }
952     break;
953    
954     case UCS2:
955     count = PR_Seek(file->handle, len*2, PR_SEEK_CUR)/2;
956     break;
957    
958     default:
959     /* Not reached. */
960     JS_ASSERT(0);
961     }
962    
963     if(count == -1) {
964     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
965     JSFILEMSG_OP_FAILED, "seek", file->path);
966     }
967    
968     return count;
969     }
970    
971     static int32
972     js_FileWrite(JSContext *cx, JSFile *file, jschar *buf, int32 len, int32 mode)
973     {
974     unsigned char *aux;
975     int32 count = 0, i, j;
976     unsigned char *utfbuf;
977    
978     switch (mode) {
979     case ASCII:
980 siliconforks 507 aux = (unsigned char*)cx->malloc(len);
981 siliconforks 332 if (!aux)
982     return 0;
983    
984     for (i = 0; i<len; i++)
985     aux[i] = buf[i] % 256;
986    
987     count = (!file->isNative)
988     ? PR_Write(file->handle, aux, len)
989     : fwrite(aux, 1, len, file->nativehandle);
990    
991     if (count==-1) {
992 siliconforks 507 cx->free(aux);
993 siliconforks 332 return 0;
994     }
995    
996 siliconforks 507 cx->free(aux);
997 siliconforks 332 break;
998    
999     case UTF8:
1000 siliconforks 507 utfbuf = (unsigned char*)cx->malloc(len*3);
1001 siliconforks 332 if (!utfbuf) return 0;
1002     i = 0;
1003     for (count = 0;count<len;count++) {
1004     j = one_ucs2_to_utf8_char(utfbuf+i, utfbuf+len*3, buf[count]);
1005     if (j==-1) {
1006 siliconforks 507 cx->free(utfbuf);
1007 siliconforks 332 return 0;
1008     }
1009     i+=j;
1010     }
1011     j = (!file->isNative)
1012     ? PR_Write(file->handle, utfbuf, i)
1013     : fwrite(utfbuf, 1, i, file->nativehandle);
1014    
1015     if (j<i) {
1016 siliconforks 507 cx->free(utfbuf);
1017 siliconforks 332 return 0;
1018     }
1019 siliconforks 507 cx->free(utfbuf);
1020 siliconforks 332 break;
1021    
1022     case UCS2:
1023     count = (!file->isNative)
1024     ? PR_Write(file->handle, buf, len*2) >> 1
1025     : fwrite(buf, 1, len*2, file->nativehandle) >> 1;
1026    
1027     if (count == -1)
1028     return 0;
1029     break;
1030    
1031     default:
1032     /* Not reached. */
1033     JS_ASSERT(0);
1034     }
1035    
1036     if(count == -1) {
1037     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1038     JSFILEMSG_OP_FAILED, "write", file->path);
1039     }
1040    
1041     return count;
1042     }
1043    
1044     /* ----------------------------- Property checkers -------------------------- */
1045     static JSBool
1046     js_exists(JSContext *cx, JSFile *file)
1047     {
1048     if (file->isNative) {
1049     /* It doesn't make sense for a pipe of stdstream. */
1050     return JS_FALSE;
1051     }
1052    
1053     return PR_Access(file->path, PR_ACCESS_EXISTS) == PR_SUCCESS;
1054     }
1055    
1056     static JSBool
1057     js_canRead(JSContext *cx, JSFile *file)
1058     {
1059     if (!file->isNative) {
1060     if (file->isOpen && !(file->mode & PR_RDONLY))
1061     return JS_FALSE;
1062     return PR_Access(file->path, PR_ACCESS_READ_OK) == PR_SUCCESS;
1063     }
1064    
1065     if (file->isPipe) {
1066     /* Is this pipe open for reading? */
1067     return file->path[0] == PIPE_SYMBOL;
1068     }
1069    
1070     return !strcmp(file->path, STDINPUT_NAME);
1071     }
1072    
1073     static JSBool
1074     js_canWrite(JSContext *cx, JSFile *file)
1075     {
1076     if (!file->isNative) {
1077     if (file->isOpen && !(file->mode & PR_WRONLY))
1078     return JS_FALSE;
1079     return PR_Access(file->path, PR_ACCESS_WRITE_OK) == PR_SUCCESS;
1080     }
1081    
1082     if(file->isPipe) {
1083     /* Is this pipe open for writing? */
1084     return file->path[strlen(file->path)-1] == PIPE_SYMBOL;
1085     }
1086    
1087     return !strcmp(file->path, STDOUTPUT_NAME) ||
1088     !strcmp(file->path, STDERROR_NAME);
1089     }
1090    
1091     static JSBool
1092     js_isFile(JSContext *cx, JSFile *file)
1093     {
1094     if (!file->isNative) {
1095     PRFileInfo info;
1096    
1097     if (file->isOpen
1098     ? PR_GetOpenFileInfo(file->handle, &info)
1099     : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) {
1100     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1101     JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
1102     return JS_FALSE;
1103     }
1104    
1105     return info.type == PR_FILE_FILE;
1106     }
1107    
1108     /* This doesn't make sense for a pipe of stdstream. */
1109     return JS_FALSE;
1110     }
1111    
1112     static JSBool
1113     js_isDirectory(JSContext *cx, JSFile *file)
1114     {
1115     if(!file->isNative){
1116     PRFileInfo info;
1117    
1118     /* Hack needed to get get_property to work. */
1119     if (!js_exists(cx, file))
1120     return JS_FALSE;
1121    
1122     if (file->isOpen
1123     ? PR_GetOpenFileInfo(file->handle, &info)
1124     : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) {
1125     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1126     JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
1127     return JS_FALSE;
1128     }
1129    
1130     return info.type == PR_FILE_DIRECTORY;
1131     }
1132    
1133     /* This doesn't make sense for a pipe of stdstream. */
1134     return JS_FALSE;
1135     }
1136    
1137     static jsval
1138     js_size(JSContext *cx, JSFile *file)
1139     {
1140     PRFileInfo info;
1141    
1142     JSFILE_CHECK_NATIVE("size");
1143    
1144     if (file->isOpen
1145     ? PR_GetOpenFileInfo(file->handle, &info)
1146     : PR_GetFileInfo(file->path, &info) != PR_SUCCESS) {
1147     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1148     JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
1149     return JSVAL_VOID;
1150     }
1151    
1152     return INT_TO_JSVAL(info.size);
1153    
1154     out:
1155     return JSVAL_VOID;
1156     }
1157    
1158     /*
1159     * Return the parent object
1160     */
1161     static JSBool
1162     js_parent(JSContext *cx, JSFile *file, jsval *resultp)
1163     {
1164     char *str;
1165    
1166     /* Since we only care about pipes and native files, return NULL. */
1167     if (file->isNative) {
1168     *resultp = JSVAL_VOID;
1169     return JS_TRUE;
1170     }
1171    
1172     str = js_fileDirectoryName(cx, file->path);
1173     if (!str)
1174     return JS_FALSE;
1175    
1176     /* If the directory is equal to the original path, we're at the root. */
1177     if (!strcmp(file->path, str)) {
1178     *resultp = JSVAL_NULL;
1179     } else {
1180     JSObject *obj = js_NewFileObject(cx, str);
1181     if (!obj) {
1182 siliconforks 507 cx->free(str);
1183 siliconforks 332 return JS_FALSE;
1184     }
1185     *resultp = OBJECT_TO_JSVAL(obj);
1186     }
1187    
1188 siliconforks 507 cx->free(str);
1189 siliconforks 332 return JS_TRUE;
1190     }
1191    
1192     static JSBool
1193     js_name(JSContext *cx, JSFile *file, jsval *vp)
1194     {
1195     char *name;
1196     JSString *str;
1197    
1198     if (file->isPipe) {
1199     *vp = JSVAL_VOID;
1200     return JS_TRUE;
1201     }
1202    
1203     name = js_fileBaseName(cx, file->path);
1204     if (!name)
1205     return JS_FALSE;
1206    
1207     str = JS_NewString(cx, name, strlen(name));
1208     if (!str) {
1209 siliconforks 507 cx->free(name);
1210 siliconforks 332 return JS_FALSE;
1211     }
1212    
1213     *vp = STRING_TO_JSVAL(str);
1214     return JS_TRUE;
1215     }
1216    
1217     /* ------------------------------ File object methods ---------------------------- */
1218     static JSBool
1219     file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1220     {
1221     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1222     JSString *strmode, *strtype;
1223     char *ctype, *mode;
1224     int32 mask, type;
1225     int len;
1226    
1227     mode = NULL;
1228    
1229     SECURITY_CHECK(cx, NULL, "open", file);
1230    
1231     /* A native file that is already open */
1232     if(file->isOpen && file->isNative) {
1233     JS_ReportWarning(cx, "Native file %s is already open, proceeding",
1234     file->path);
1235     goto good;
1236     }
1237    
1238     /* Close before proceeding */
1239     if (file->isOpen) {
1240     JS_ReportWarning(cx, "File %s is already open, we will close it and "
1241     "reopen, proceeding", file->path);
1242     if(!file_close(cx, obj, 0, NULL, rval))
1243     goto out;
1244     }
1245    
1246     if (js_isDirectory(cx, file)) {
1247     JS_ReportWarning(cx, "%s seems to be a directory, there is no point in "
1248     "trying to open it, proceeding", file->path);
1249     goto good;
1250     }
1251    
1252     /* Path must be defined at this point */
1253     len = strlen(file->path);
1254    
1255     /* Mode */
1256     if (argc >= 1) {
1257     strmode = JS_ValueToString(cx, argv[0]);
1258     if (!strmode) {
1259     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1260     JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR,
1261     argv[0]);
1262     goto out;
1263     }
1264     mode = JS_strdup(cx, JS_GetStringBytes(strmode));
1265     } else {
1266     if(file->path[0]==PIPE_SYMBOL) {
1267     /* pipe default mode */
1268     mode = JS_strdup(cx, "read");
1269     } else if(file->path[len-1]==PIPE_SYMBOL) {
1270     /* pipe default mode */
1271     mode = JS_strdup(cx, "write");
1272     } else {
1273     /* non-destructive, permissive defaults. */
1274     mode = JS_strdup(cx, "readWrite,append,create");
1275     }
1276     }
1277    
1278     /* Process the mode */
1279     mask = 0;
1280     /* TODO: this is pretty ugly, we walk thru the string too many times */
1281     mask |= js_FileHasOption(cx, mode, "read") ? PR_RDONLY : 0;
1282     mask |= js_FileHasOption(cx, mode, "write") ? PR_WRONLY : 0;
1283     mask |= js_FileHasOption(cx, mode, "readWrite")? PR_RDWR : 0;
1284     mask |= js_FileHasOption(cx, mode, "append") ? PR_APPEND : 0;
1285     mask |= js_FileHasOption(cx, mode, "create") ? PR_CREATE_FILE : 0;
1286     mask |= js_FileHasOption(cx, mode, "replace") ? PR_TRUNCATE : 0;
1287    
1288     if (mask & PR_RDWR)
1289     mask |= (PR_RDONLY | PR_WRONLY);
1290     if ((mask & PR_RDONLY) && (mask & PR_WRONLY))
1291     mask |= PR_RDWR;
1292    
1293     file->hasAutoflush |= js_FileHasOption(cx, mode, "autoflush");
1294    
1295     /* Type */
1296     if (argc > 1) {
1297     strtype = JS_ValueToString(cx, argv[1]);
1298     if (!strtype) {
1299     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1300     JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR,
1301     argv[1]);
1302     goto out;
1303     }
1304     ctype = JS_GetStringBytes(strtype);
1305    
1306     if(!strcmp(ctype, utfstring)) {
1307     type = UTF8;
1308     } else if (!strcmp(ctype, unicodestring)) {
1309     type = UCS2;
1310     } else {
1311     if (strcmp(ctype, asciistring)) {
1312     JS_ReportWarning(cx, "File type %s is not supported, using "
1313     "'text' instead, proceeding", ctype);
1314     }
1315     type = ASCII;
1316     }
1317     } else {
1318     type = ASCII;
1319     }
1320    
1321     /* Save the relevant fields */
1322     file->type = type;
1323     file->mode = mask;
1324     file->nativehandle = NULL;
1325     file->hasRandomAccess = (type != UTF8);
1326    
1327     /*
1328     * Deal with pipes here. We can't use NSPR for pipes, so we have to use
1329     * POPEN.
1330     */
1331     if (file->path[0]==PIPE_SYMBOL || file->path[len-1]==PIPE_SYMBOL) {
1332     if (file->path[0] == PIPE_SYMBOL && file->path[len-1] == PIPE_SYMBOL) {
1333     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1334     JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED);
1335     goto out;
1336     } else {
1337     int i = 0;
1338     char pipemode[3];
1339     SECURITY_CHECK(cx, NULL, "pipe_open", file);
1340    
1341     if(file->path[0] == PIPE_SYMBOL){
1342     if(mask & (PR_WRONLY | PR_APPEND | PR_CREATE_FILE | PR_TRUNCATE)){
1343     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1344     JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES,
1345     mode, file->path);
1346     goto out;
1347     }
1348     /* open(SPOOLER, "| cat -v | lpr -h 2>/dev/null") -- pipe for writing */
1349     pipemode[i++] = 'r';
1350     #ifndef XP_UNIX
1351     pipemode[i++] = file->type==UTF8 ? 'b' : 't';
1352     #endif
1353     pipemode[i++] = '\0';
1354     file->nativehandle = POPEN(&file->path[1], pipemode);
1355     } else if(file->path[len-1] == PIPE_SYMBOL) {
1356 siliconforks 507 char *command = cx->malloc(len);
1357 siliconforks 332
1358     strncpy(command, file->path, len-1);
1359     command[len-1] = '\0';
1360     /* open(STATUS, "netstat -an 2>&1 |") */
1361     pipemode[i++] = 'w';
1362     #ifndef XP_UNIX
1363     pipemode[i++] = file->type==UTF8 ? 'b' : 't';
1364     #endif
1365     pipemode[i++] = '\0';
1366     file->nativehandle = POPEN(command, pipemode);
1367 siliconforks 507 cx->free(command);
1368 siliconforks 332 }
1369     /* set the flags */
1370     file->isNative = JS_TRUE;
1371     file->isPipe = JS_TRUE;
1372     file->hasRandomAccess = JS_FALSE;
1373     }
1374     } else {
1375     /* TODO: what about the permissions?? Java ignores the problem... */
1376     file->handle = PR_Open(file->path, mask, 0644);
1377     }
1378    
1379     js_ResetBuffers(file);
1380 siliconforks 507 cx->free(mode);
1381 siliconforks 332 mode = NULL;
1382    
1383     /* Set the open flag and return result */
1384     if (file->handle == NULL && file->nativehandle == NULL) {
1385     file->isOpen = JS_FALSE;
1386    
1387     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1388     JSFILEMSG_OP_FAILED, "open", file->path);
1389     goto out;
1390     }
1391    
1392     good:
1393     file->isOpen = JS_TRUE;
1394     *rval = JSVAL_TRUE;
1395     return JS_TRUE;
1396    
1397     out:
1398     if(mode)
1399 siliconforks 507 cx->free(mode);
1400 siliconforks 332 return JS_FALSE;
1401     }
1402    
1403     static JSBool
1404     file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1405     {
1406     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1407    
1408     SECURITY_CHECK(cx, NULL, "close", file);
1409    
1410     if(!file->isOpen){
1411     JS_ReportWarning(cx, "File %s is not open, can't close it, proceeding",
1412     file->path);
1413     goto out;
1414     }
1415    
1416     if(!file->isPipe){
1417     if(file->isNative){
1418     JS_ReportWarning(cx, "Unable to close a native file, proceeding", file->path);
1419     goto out;
1420     }else{
1421     if(file->handle && PR_Close(file->handle)){
1422     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1423     JSFILEMSG_OP_FAILED, "close", file->path);
1424    
1425     goto out;
1426     }
1427     }
1428     }else{
1429     if(PCLOSE(file->nativehandle)==-1){
1430     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1431     JSFILEMSG_OP_FAILED, "pclose", file->path);
1432     goto out;
1433     }
1434     }
1435    
1436     js_ResetAttributes(file);
1437     *rval = JSVAL_TRUE;
1438     return JS_TRUE;
1439    
1440     out:
1441     return JS_FALSE;
1442     }
1443    
1444    
1445     static JSBool
1446     file_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1447     {
1448     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1449    
1450     SECURITY_CHECK(cx, NULL, "remove", file);
1451     JSFILE_CHECK_NATIVE("remove");
1452     JSFILE_CHECK_CLOSED("remove");
1453    
1454     if ((js_isDirectory(cx, file) ?
1455     PR_RmDir(file->path) : PR_Delete(file->path))==PR_SUCCESS) {
1456     js_ResetAttributes(file);
1457     *rval = JSVAL_TRUE;
1458     return JS_TRUE;
1459     } else {
1460     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1461     JSFILEMSG_OP_FAILED, "remove", file->path);
1462     goto out;
1463     }
1464     out:
1465     *rval = JSVAL_FALSE;
1466     return JS_FALSE;
1467     }
1468    
1469     /* Raw PR-based function. No text processing. Just raw data copying. */
1470     static JSBool
1471     file_copyTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1472     {
1473     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1474     char *dest = NULL;
1475     PRFileDesc *handle = NULL;
1476     char *buffer;
1477     jsval count, size;
1478     JSBool fileInitiallyOpen=JS_FALSE;
1479    
1480     SECURITY_CHECK(cx, NULL, "copyTo", file); /* may need a second argument!*/
1481     JSFILE_CHECK_ONE_ARG("copyTo");
1482     JSFILE_CHECK_NATIVE("copyTo");
1483     /* remeber the state */
1484     fileInitiallyOpen = file->isOpen;
1485     JSFILE_CHECK_READ;
1486    
1487 siliconforks 507 JSString *str = JS_ValueToString(cx, argv[0]);
1488     if (!str)
1489     goto out;
1490 siliconforks 332
1491 siliconforks 507 dest = JS_GetStringBytes(str);
1492    
1493 siliconforks 332 /* make sure we are not reading a file open for writing */
1494     if (file->isOpen && !js_canRead(cx, file)) {
1495     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1496     JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR, file->path);
1497     goto out;
1498     }
1499    
1500     if (file->handle==NULL){
1501     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1502     JSFILEMSG_OP_FAILED, "open", file->path);
1503     goto out;
1504     }
1505    
1506     handle = PR_Open(dest, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0644);
1507    
1508     if(!handle){
1509     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1510     JSFILEMSG_OP_FAILED, "open", dest);
1511     goto out;
1512     }
1513    
1514     if ((size=js_size(cx, file))==JSVAL_VOID) {
1515     goto out;
1516     }
1517    
1518 siliconforks 507 buffer = cx->malloc(size);
1519 siliconforks 332
1520     count = INT_TO_JSVAL(PR_Read(file->handle, buffer, size));
1521    
1522     /* reading panic */
1523     if (count!=size) {
1524 siliconforks 507 cx->free(buffer);
1525 siliconforks 332 JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1526     JSFILEMSG_COPY_READ_ERROR, file->path);
1527     goto out;
1528     }
1529    
1530     count = INT_TO_JSVAL(PR_Write(handle, buffer, JSVAL_TO_INT(size)));
1531    
1532     /* writing panic */
1533     if (count!=size) {
1534 siliconforks 507 cx->free(buffer);
1535 siliconforks 332 JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1536     JSFILEMSG_COPY_WRITE_ERROR, file->path);
1537     goto out;
1538     }
1539    
1540 siliconforks 507 cx->free(buffer);
1541 siliconforks 332
1542     if(!fileInitiallyOpen){
1543     if(!file_close(cx, obj, 0, NULL, rval)) goto out;
1544     }
1545    
1546     if(PR_Close(handle)!=PR_SUCCESS){
1547     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1548     JSFILEMSG_OP_FAILED, "close", dest);
1549     goto out;
1550     }
1551    
1552     *rval = JSVAL_TRUE;
1553     return JS_TRUE;
1554     out:
1555     if(file->isOpen && !fileInitiallyOpen){
1556     if(PR_Close(file->handle)!=PR_SUCCESS){
1557     JS_ReportWarning(cx, "Can't close %s, proceeding", file->path);
1558     }
1559     }
1560    
1561     if(handle && PR_Close(handle)!=PR_SUCCESS){
1562     JS_ReportWarning(cx, "Can't close %s, proceeding", dest);
1563     }
1564    
1565     *rval = JSVAL_FALSE;
1566     return JS_FALSE;
1567     }
1568    
1569     static JSBool
1570     file_renameTo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1571     {
1572     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1573     char *dest;
1574    
1575     SECURITY_CHECK(cx, NULL, "renameTo", file); /* may need a second argument!*/
1576     JSFILE_CHECK_ONE_ARG("renameTo");
1577     JSFILE_CHECK_NATIVE("renameTo");
1578     JSFILE_CHECK_CLOSED("renameTo");
1579    
1580 siliconforks 507 JSString *str = JS_ValueToString(cx, argv[0]);
1581     if (!str)
1582     goto out;
1583 siliconforks 332
1584 siliconforks 507 dest = RESOLVE_PATH(cx, JS_GetStringBytes(str));
1585    
1586 siliconforks 332 if (PR_Rename(file->path, dest)==PR_SUCCESS){
1587     /* copy the new filename */
1588 siliconforks 507 cx->free(file->path);
1589 siliconforks 332 file->path = dest;
1590     *rval = JSVAL_TRUE;
1591     return JS_TRUE;
1592     }else{
1593     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1594     JSFILEMSG_RENAME_FAILED, file->path, dest);
1595     goto out;
1596     }
1597     out:
1598     *rval = JSVAL_FALSE;
1599     return JS_FALSE;
1600     }
1601    
1602     static JSBool
1603     file_flush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1604     {
1605     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1606    
1607     SECURITY_CHECK(cx, NULL, "flush", file);
1608     JSFILE_CHECK_NATIVE("flush");
1609     JSFILE_CHECK_OPEN("flush");
1610    
1611     if (PR_Sync(file->handle)==PR_SUCCESS){
1612     *rval = JSVAL_TRUE;
1613     return JS_TRUE;
1614     }else{
1615     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1616     JSFILEMSG_OP_FAILED, "flush", file->path);
1617     goto out;
1618     }
1619     out:
1620     *rval = JSVAL_FALSE;
1621     return JS_FALSE;
1622     }
1623    
1624     static JSBool
1625     file_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1626     {
1627     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1628     JSString *str;
1629     int32 count;
1630     uintN i;
1631    
1632     SECURITY_CHECK(cx, NULL, "write", file);
1633     JSFILE_CHECK_WRITE;
1634    
1635     for (i = 0; i<argc; i++) {
1636     str = JS_ValueToString(cx, argv[i]);
1637     count = js_FileWrite(cx, file, JS_GetStringChars(str),
1638     JS_GetStringLength(str), file->type);
1639     if (count==-1){
1640     *rval = JSVAL_FALSE;
1641     return JS_FALSE;
1642     }
1643     }
1644    
1645     *rval = JSVAL_TRUE;
1646     return JS_TRUE;
1647     out:
1648     *rval = JSVAL_FALSE;
1649     return JS_FALSE;
1650     }
1651    
1652     static JSBool
1653     file_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1654     {
1655     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1656     JSString *str;
1657    
1658     SECURITY_CHECK(cx, NULL, "writeln", file);
1659     JSFILE_CHECK_WRITE;
1660    
1661     /* don't report an error here */
1662     if(!file_write(cx, obj, argc, argv, rval)) return JS_FALSE;
1663     /* don't do security here -- we passed the check in file_write */
1664     str = JS_NewStringCopyZ(cx, "\n");
1665    
1666     if (js_FileWrite(cx, file, JS_GetStringChars(str), JS_GetStringLength(str),
1667     file->type)==-1){
1668     *rval = JSVAL_FALSE;
1669     return JS_FALSE;
1670     }
1671    
1672     /* eol causes flush if hasAutoflush is turned on */
1673     if (file->hasAutoflush)
1674     file_flush(cx, obj, 0, NULL, rval);
1675    
1676     *rval = JSVAL_TRUE;
1677     return JS_TRUE;
1678     out:
1679     *rval = JSVAL_FALSE;
1680     return JS_FALSE;
1681     }
1682    
1683     static JSBool
1684     file_writeAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1685     {
1686     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1687     jsuint i;
1688     jsuint limit;
1689     JSObject *array;
1690     JSObject *elem;
1691     jsval elemval;
1692    
1693     SECURITY_CHECK(cx, NULL, "writeAll", file);
1694     JSFILE_CHECK_ONE_ARG("writeAll");
1695     JSFILE_CHECK_WRITE;
1696    
1697     if (!JS_IsArrayObject(cx, JSVAL_TO_OBJECT(argv[0]))) {
1698     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1699     JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR);
1700     goto out;
1701     }
1702    
1703     array = JSVAL_TO_OBJECT(argv[0]);
1704    
1705     JS_GetArrayLength(cx, array, &limit);
1706    
1707     for (i = 0; i<limit; i++) {
1708     if (!JS_GetElement(cx, array, i, &elemval)) return JS_FALSE;
1709     elem = JSVAL_TO_OBJECT(elemval);
1710     file_writeln(cx, obj, 1, &elemval, rval);
1711     }
1712    
1713     *rval = JSVAL_TRUE;
1714     return JS_TRUE;
1715     out:
1716     *rval = JSVAL_FALSE;
1717     return JS_FALSE;
1718     }
1719    
1720     static JSBool
1721     file_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1722     {
1723     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1724     JSString *str;
1725     int32 want, count;
1726     jschar *buf;
1727    
1728     SECURITY_CHECK(cx, NULL, "read", file);
1729     JSFILE_CHECK_ONE_ARG("read");
1730     JSFILE_CHECK_READ;
1731    
1732     if (!JS_ValueToInt32(cx, argv[0], &want)){
1733     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1734     JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "read", argv[0]);
1735     goto out;
1736     }
1737    
1738     /* want = (want>262144)?262144:want; * arbitrary size limitation */
1739    
1740 siliconforks 507 buf = cx->malloc(want*sizeof buf[0]);
1741 siliconforks 332 if (!buf) goto out;
1742    
1743     count = js_FileRead(cx, file, buf, want, file->type);
1744     if (count>0) {
1745     str = JS_NewUCStringCopyN(cx, buf, count);
1746     *rval = STRING_TO_JSVAL(str);
1747 siliconforks 507 cx->free(buf);
1748 siliconforks 332 return JS_TRUE;
1749     } else {
1750 siliconforks 507 cx->free(buf);
1751 siliconforks 332 goto out;
1752     }
1753     out:
1754     *rval = JSVAL_FALSE;
1755     return JS_FALSE;
1756     }
1757    
1758     static JSBool
1759     file_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1760     {
1761     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1762     JSString *str;
1763     jschar *buf = NULL, *tmp;
1764     int32 offset, read;
1765     intN room;
1766     jschar data, data2;
1767    
1768     SECURITY_CHECK(cx, NULL, "readln", file);
1769     JSFILE_CHECK_READ;
1770    
1771 siliconforks 507 buf = cx->malloc(MAX_LINE_LENGTH * sizeof data);
1772 siliconforks 332 if (!buf)
1773     return JS_FALSE;
1774    
1775     room = MAX_LINE_LENGTH - 1;
1776     offset = 0;
1777    
1778     for (;;) {
1779     read = js_FileRead(cx, file, &data, 1, file->type);
1780     if (read < 0)
1781     goto out;
1782     if (read == 0)
1783     goto eof;
1784    
1785     switch (data) {
1786     case '\r':
1787     read = js_FileRead(cx, file, &data2, 1, file->type);
1788     if (read < 0)
1789     goto out;
1790    
1791     if (read == 1 && data2 != '\n') {
1792     /* We read one char too far. Buffer it. */
1793     file->charBuffer = data2;
1794     file->charBufferUsed = JS_TRUE;
1795     }
1796    
1797     /* Fall through. */
1798     case '\n':
1799     goto done;
1800    
1801     default:
1802     if (--room < 0) {
1803 siliconforks 507 tmp = cx->realloc(buf, (offset + MAX_LINE_LENGTH) * sizeof data);
1804 siliconforks 332 if (!tmp)
1805     goto out;
1806    
1807     room = MAX_LINE_LENGTH - 1;
1808     buf = tmp;
1809     }
1810    
1811     buf[offset++] = data;
1812     break;
1813     }
1814     }
1815    
1816     eof:
1817     if (offset == 0) {
1818     *rval = JSVAL_NULL;
1819     return JS_TRUE;
1820     }
1821    
1822     done:
1823     buf[offset] = 0;
1824 siliconforks 507 tmp = cx->realloc(buf, (offset + 1) * sizeof data);
1825 siliconforks 332 if (!tmp)
1826     goto out;
1827    
1828     str = JS_NewUCString(cx, tmp, offset);
1829     if (!str)
1830     goto out;
1831    
1832     *rval = STRING_TO_JSVAL(str);
1833     return JS_TRUE;
1834    
1835     out:
1836     if (buf)
1837 siliconforks 507 cx->free(buf);
1838 siliconforks 332
1839     return JS_FALSE;
1840     }
1841    
1842     static JSBool
1843     file_readAll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1844     {
1845     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1846     JSObject *array;
1847     jsint len;
1848     jsval line;
1849     JSBool lineok = JS_FALSE;
1850    
1851     SECURITY_CHECK(cx, NULL, "readAll", file);
1852     JSFILE_CHECK_READ;
1853    
1854     array = JS_NewArrayObject(cx, 0, NULL);
1855     if (!array)
1856     return JS_FALSE;
1857     *rval = OBJECT_TO_JSVAL(array);
1858    
1859     len = 0;
1860    
1861     lineok = file_readln(cx, obj, 0, NULL, &line);
1862     while (lineok && !JSVAL_IS_NULL(line)) {
1863     JS_SetElement(cx, array, len++, &line);
1864     lineok = file_readln(cx, obj, 0, NULL, &line);
1865     }
1866    
1867     out:
1868     return lineok;
1869     }
1870    
1871     static JSBool
1872     file_seek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1873     {
1874     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1875     int32 toskip;
1876     int32 pos;
1877    
1878     SECURITY_CHECK(cx, NULL, "seek", file);
1879     JSFILE_CHECK_ONE_ARG("seek");
1880     JSFILE_CHECK_NATIVE("seek");
1881     JSFILE_CHECK_READ;
1882    
1883     if (!JS_ValueToInt32(cx, argv[0], &toskip)){
1884     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1885     JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, "seek", argv[0]);
1886     goto out;
1887     }
1888    
1889     if(!file->hasRandomAccess){
1890     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1891     JSFILEMSG_NO_RANDOM_ACCESS, file->path);
1892     goto out;
1893     }
1894    
1895     if(js_isDirectory(cx, file)){
1896     JS_ReportWarning(cx,"Seek on directories is not supported, proceeding");
1897     goto out;
1898     }
1899    
1900     pos = js_FileSeek(cx, file, toskip, file->type);
1901    
1902     if (pos!=-1) {
1903     *rval = INT_TO_JSVAL(pos);
1904     return JS_TRUE;
1905     }
1906     out:
1907     *rval = JSVAL_VOID;
1908     return JS_FALSE;
1909     }
1910    
1911     static JSBool
1912     file_list(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1913     {
1914     PRDir *dir;
1915     PRDirEntry *entry;
1916     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
1917     JSObject *array;
1918     JSObject *eachFile;
1919     jsint len;
1920     jsval v;
1921     JSRegExp *re = NULL;
1922     JSFunction *func = NULL;
1923     JSString *str;
1924     jsval args[1];
1925     char *filePath;
1926    
1927     SECURITY_CHECK(cx, NULL, "list", file);
1928     JSFILE_CHECK_NATIVE("list");
1929    
1930     if (argc==1) {
1931     if (VALUE_IS_REGEXP(cx, argv[0])) {
1932     re = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
1933     }else
1934     if (VALUE_IS_FUNCTION(cx, argv[0])) {
1935     func = JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0]));
1936     }else{
1937     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1938     JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, argv[0]);
1939     goto out;
1940     }
1941     }
1942    
1943     if (!js_isDirectory(cx, file)) {
1944     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1945     JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE, file->path);
1946     goto out;
1947     }
1948    
1949     dir = PR_OpenDir(file->path);
1950     if(!dir){
1951     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
1952     JSFILEMSG_OP_FAILED, "open", file->path);
1953     goto out;
1954     }
1955    
1956     /* create JSArray here... */
1957     array = JS_NewArrayObject(cx, 0, NULL);
1958     len = 0;
1959    
1960     while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))!=NULL) {
1961     /* first, check if we have a regexp */
1962     if (re!=NULL) {
1963     size_t index = 0;
1964    
1965     str = JS_NewStringCopyZ(cx, entry->name);
1966     if(!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &v)){
1967     /* don't report anything here */
1968     goto out;
1969     }
1970     /* not matched! */
1971     if (JSVAL_IS_NULL(v)) {
1972     continue;
1973     }
1974     }else
1975     if (func!=NULL) {
1976     str = JS_NewStringCopyZ(cx, entry->name);
1977     args[0] = STRING_TO_JSVAL(str);
1978     if(!JS_CallFunction(cx, obj, func, 1, args, &v)){
1979     goto out;
1980     }
1981    
1982     if (v==JSVAL_FALSE) {
1983     continue;
1984     }
1985     }
1986    
1987     filePath = js_combinePath(cx, file->path, (char*)entry->name);
1988    
1989     eachFile = js_NewFileObject(cx, filePath);
1990 siliconforks 507 cx->free(filePath);
1991 siliconforks 332 if (!eachFile){
1992     JS_ReportWarning(cx, "File %s cannot be retrieved", filePath);
1993     continue;
1994     }
1995     v = OBJECT_TO_JSVAL(eachFile);
1996     JS_SetElement(cx, array, len, &v);
1997     JS_SetProperty(cx, array, entry->name, &v);
1998     len++;
1999     }
2000    
2001     if(PR_CloseDir(dir)!=PR_SUCCESS){
2002     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2003     JSFILEMSG_OP_FAILED, "close", file->path);
2004     goto out;
2005     }
2006     *rval = OBJECT_TO_JSVAL(array);
2007     return JS_TRUE;
2008     out:
2009     *rval = JSVAL_NULL;
2010     return JS_FALSE;
2011     }
2012    
2013     static JSBool
2014     file_mkdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2015     {
2016     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
2017    
2018     SECURITY_CHECK(cx, NULL, "mkdir", file);
2019     JSFILE_CHECK_ONE_ARG("mkdir");
2020     JSFILE_CHECK_NATIVE("mkdir");
2021    
2022     /* if the current file is not a directory, find out the directory name */
2023     if (!js_isDirectory(cx, file)) {
2024     char *dir = js_fileDirectoryName(cx, file->path);
2025     JSObject *dirObj = js_NewFileObject(cx, dir);
2026    
2027 siliconforks 507 cx->free(dir);
2028 siliconforks 332
2029     /* call file_mkdir with the right set of parameters if needed */
2030     if (file_mkdir(cx, dirObj, argc, argv, rval))
2031     return JS_TRUE;
2032     else
2033     goto out;
2034     }else{
2035 siliconforks 507 JSString *str = JS_ValueToString(cx, argv[0]);
2036     if (!str)
2037     goto out;
2038    
2039     char *dirName = JS_GetStringBytes(str);
2040 siliconforks 332 char *fullName;
2041    
2042     fullName = js_combinePath(cx, file->path, dirName);
2043     if (PR_MkDir(fullName, 0755)==PR_SUCCESS){
2044     *rval = JSVAL_TRUE;
2045 siliconforks 507 cx->free(fullName);
2046 siliconforks 332 return JS_TRUE;
2047     }else{
2048     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2049     JSFILEMSG_OP_FAILED, "mkdir", fullName);
2050 siliconforks 507 cx->free(fullName);
2051 siliconforks 332 goto out;
2052     }
2053     }
2054     out:
2055     *rval = JSVAL_FALSE;
2056     return JS_FALSE;
2057     }
2058    
2059     static JSBool
2060     file_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval*rval)
2061     {
2062     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
2063     JSString *str;
2064    
2065     str = JS_NewStringCopyZ(cx, file->path);
2066     if (!str)
2067     return JS_FALSE;
2068     *rval = STRING_TO_JSVAL(str);
2069     return JS_TRUE;
2070     }
2071    
2072     static JSBool
2073     file_toURL(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
2074     {
2075     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
2076     char url[MAX_PATH_LENGTH];
2077     jschar *urlChars;
2078     size_t len;
2079     JSString *str;
2080    
2081     JSFILE_CHECK_NATIVE("toURL");
2082    
2083     sprintf(url, "file://%s", file->path);
2084    
2085     len = strlen(url);
2086     urlChars = js_InflateString(cx, url, &len);
2087     if (!urlChars)
2088     return JS_FALSE;
2089     str = js_NewString(cx, urlChars, len);
2090     if (!str) {
2091 siliconforks 507 cx->free(urlChars);
2092 siliconforks 332 return JS_FALSE;
2093     }
2094     *rval = STRING_TO_JSVAL(str);
2095    
2096     /* TODO: js_escape in jsstr.h may go away at some point */
2097     return js_str_escape(cx, obj, 0, rval, rval);
2098    
2099     out:
2100     *rval = JSVAL_VOID;
2101     return JS_FALSE;
2102     }
2103    
2104    
2105     static void
2106     file_finalize(JSContext *cx, JSObject *obj)
2107     {
2108     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
2109    
2110     if(file) {
2111     /* Close the file before exiting. */
2112     if(file->isOpen && !file->isNative) {
2113     jsval vp;
2114     file_close(cx, obj, 0, NULL, &vp);
2115     }
2116    
2117     if (file->path)
2118 siliconforks 507 cx->free(file->path);
2119 siliconforks 332
2120 siliconforks 507 cx->free(file);
2121 siliconforks 332 }
2122     }
2123    
2124     /*
2125     Allocates memory for the file object, sets fields to defaults.
2126     */
2127     static JSFile*
2128     file_init(JSContext *cx, JSObject *obj, char *bytes)
2129     {
2130     JSFile *file;
2131    
2132 siliconforks 507 file = cx->malloc(sizeof *file);
2133 siliconforks 332 if (!file)
2134     return NULL;
2135     memset(file, 0 , sizeof *file);
2136    
2137     js_ResetAttributes(file);
2138    
2139     file->path = RESOLVE_PATH(cx, bytes);
2140    
2141     if (!JS_SetPrivate(cx, obj, file)) {
2142     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2143     JSFILEMSG_CANNOT_SET_PRIVATE_FILE, file->path);
2144 siliconforks 507 cx->free(file);
2145 siliconforks 332 return NULL;
2146     }
2147    
2148     return file;
2149     }
2150    
2151     /* Returns a JSObject. This function is globally visible */
2152     JS_PUBLIC_API(JSObject*)
2153     js_NewFileObject(JSContext *cx, char *filename)
2154     {
2155     JSObject *obj;
2156     JSFile *file;
2157    
2158     obj = JS_NewObject(cx, &js_FileClass, NULL, NULL);
2159     if (!obj){
2160     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2161     JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObject");
2162     return NULL;
2163     }
2164     file = file_init(cx, obj, filename);
2165     if(!file) return NULL;
2166     return obj;
2167     }
2168    
2169     /* Internal function, used for cases which NSPR file support doesn't cover */
2170     JSObject*
2171     js_NewFileObjectFromFILE(JSContext *cx, FILE *nativehandle, char *filename,
2172     int32 mode, JSBool open, JSBool randomAccess)
2173     {
2174     JSObject *obj;
2175     JSFile *file;
2176    
2177     obj = JS_NewObject(cx, &js_FileClass, NULL, NULL);
2178     if (!obj){
2179     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2180     JSFILEMSG_OBJECT_CREATION_FAILED, "js_NewFileObjectFromFILE");
2181     return NULL;
2182     }
2183     file = file_init(cx, obj, filename);
2184     if(!file) return NULL;
2185    
2186     file->nativehandle = nativehandle;
2187    
2188     /* free result of RESOLVE_PATH from file_init. */
2189     JS_ASSERT(file->path != NULL);
2190 siliconforks 507 cx->free(file->path);
2191 siliconforks 332
2192     file->path = strdup(filename);
2193     file->isOpen = open;
2194     file->mode = mode;
2195     file->hasRandomAccess = randomAccess;
2196     file->isNative = JS_TRUE;
2197     return obj;
2198     }
2199    
2200     /*
2201     Real file constructor that is called from JavaScript.
2202     Basically, does error processing and calls file_init.
2203     */
2204     static JSBool
2205     file_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
2206     jsval *rval)
2207     {
2208     JSString *str;
2209     JSFile *file;
2210    
2211 siliconforks 460 if (!JS_IsConstructing(cx)) {
2212 siliconforks 332 /* Replace obj with a new File object. */
2213     obj = JS_NewObject(cx, &js_FileClass, NULL, NULL);
2214     if (!obj)
2215     return JS_FALSE;
2216     *rval = OBJECT_TO_JSVAL(obj);
2217     }
2218    
2219     str = (argc == 0)
2220     ? JS_InternString(cx, "")
2221     : JS_ValueToString(cx, argv[0]);
2222    
2223     if (!str) {
2224     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2225     JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR,
2226     argv[0]);
2227     return JS_FALSE;
2228     }
2229    
2230     file = file_init(cx, obj, JS_GetStringBytes(str));
2231     if (!file)
2232     return JS_FALSE;
2233    
2234     SECURITY_CHECK(cx, NULL, "constructor", file);
2235    
2236     return JS_TRUE;
2237     }
2238    
2239     /* -------------------- File methods and properties ------------------------- */
2240     static JSFunctionSpec file_functions[] = {
2241     { "open", file_open, 0},
2242     { "close", file_close, 0},
2243     { "remove", file_remove, 0},
2244     { "copyTo", file_copyTo, 0},
2245     { "renameTo", file_renameTo, 0},
2246     { "flush", file_flush, 0},
2247     { "seek", file_seek, 0},
2248     { "read", file_read, 0},
2249     { "readln", file_readln, 0},
2250     { "readAll", file_readAll, 0},
2251     { "write", file_write, 0},
2252     { "writeln", file_writeln, 0},
2253     { "writeAll", file_writeAll, 0},
2254     { "list", file_list, 0},
2255     { "mkdir", file_mkdir, 0},
2256     { "toString", file_toString, 0},
2257     { "toURL", file_toURL, 0},
2258     {0}
2259     };
2260    
2261     enum file_tinyid {
2262     FILE_LENGTH = -2,
2263     FILE_PARENT = -3,
2264     FILE_PATH = -4,
2265     FILE_NAME = -5,
2266     FILE_ISDIR = -6,
2267     FILE_ISFILE = -7,
2268     FILE_EXISTS = -8,
2269     FILE_CANREAD = -9,
2270     FILE_CANWRITE = -10,
2271     FILE_OPEN = -11,
2272     FILE_TYPE = -12,
2273     FILE_MODE = -13,
2274     FILE_CREATED = -14,
2275     FILE_MODIFIED = -15,
2276     FILE_SIZE = -16,
2277     FILE_RANDOMACCESS = -17,
2278     FILE_POSITION = -18,
2279     FILE_APPEND = -19,
2280     FILE_REPLACE = -20,
2281     FILE_AUTOFLUSH = -21,
2282     FILE_ISNATIVE = -22,
2283     };
2284    
2285     static JSPropertySpec file_props[] = {
2286     {"length", FILE_LENGTH, JSPROP_ENUMERATE | JSPROP_READONLY },
2287     {"parent", FILE_PARENT, JSPROP_ENUMERATE | JSPROP_READONLY },
2288     {"path", FILE_PATH, JSPROP_ENUMERATE | JSPROP_READONLY },
2289     {"name", FILE_NAME, JSPROP_ENUMERATE | JSPROP_READONLY },
2290     {"isDirectory", FILE_ISDIR, JSPROP_ENUMERATE | JSPROP_READONLY },
2291     {"isFile", FILE_ISFILE, JSPROP_ENUMERATE | JSPROP_READONLY },
2292     {"exists", FILE_EXISTS, JSPROP_ENUMERATE | JSPROP_READONLY },
2293     {"canRead", FILE_CANREAD, JSPROP_ENUMERATE | JSPROP_READONLY },
2294     {"canWrite", FILE_CANWRITE, JSPROP_ENUMERATE | JSPROP_READONLY },
2295     {"canAppend", FILE_APPEND, JSPROP_ENUMERATE | JSPROP_READONLY },
2296     {"canReplace", FILE_REPLACE, JSPROP_ENUMERATE | JSPROP_READONLY },
2297     {"isOpen", FILE_OPEN, JSPROP_ENUMERATE | JSPROP_READONLY },
2298     {"type", FILE_TYPE, JSPROP_ENUMERATE | JSPROP_READONLY },
2299     {"mode", FILE_MODE, JSPROP_ENUMERATE | JSPROP_READONLY },
2300     {"creationTime", FILE_CREATED, JSPROP_ENUMERATE | JSPROP_READONLY },
2301     {"lastModified", FILE_MODIFIED, JSPROP_ENUMERATE | JSPROP_READONLY },
2302     {"size", FILE_SIZE, JSPROP_ENUMERATE | JSPROP_READONLY },
2303     {"hasRandomAccess", FILE_RANDOMACCESS, JSPROP_ENUMERATE | JSPROP_READONLY },
2304     {"hasAutoFlush", FILE_AUTOFLUSH, JSPROP_ENUMERATE | JSPROP_READONLY },
2305     {"position", FILE_POSITION, JSPROP_ENUMERATE },
2306     {"isNative", FILE_ISNATIVE, JSPROP_ENUMERATE | JSPROP_READONLY },
2307     {0}
2308     };
2309    
2310     /* ------------------------- Property getter/setter ------------------------- */
2311     static JSBool
2312     file_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
2313     {
2314     JSFile *file = JS_GetInstancePrivate(cx, obj, &js_FileClass, NULL);
2315     char *bytes;
2316     JSString *str;
2317     jsint tiny;
2318     PRFileInfo info;
2319     JSBool flag;
2320     PRExplodedTime expandedTime;
2321    
2322     tiny = JSVAL_TO_INT(id);
2323     if (!file)
2324     return JS_TRUE;
2325    
2326     switch (tiny) {
2327     case FILE_PARENT:
2328     SECURITY_CHECK(cx, NULL, "parent", file);
2329     if (!js_parent(cx, file, vp))
2330     return JS_FALSE;
2331     break;
2332     case FILE_PATH:
2333     str = JS_NewStringCopyZ(cx, file->path);
2334     if (!str)
2335     return JS_FALSE;
2336     *vp = STRING_TO_JSVAL(str);
2337     break;
2338     case FILE_NAME:
2339     if (!js_name(cx, file, vp))
2340     return JS_FALSE;
2341     break;
2342     case FILE_ISDIR:
2343     SECURITY_CHECK(cx, NULL, "isDirectory", file);
2344     *vp = BOOLEAN_TO_JSVAL(js_isDirectory(cx, file));
2345     break;
2346     case FILE_ISFILE:
2347     SECURITY_CHECK(cx, NULL, "isFile", file);
2348     *vp = BOOLEAN_TO_JSVAL(js_isFile(cx, file));
2349     break;
2350     case FILE_EXISTS:
2351     SECURITY_CHECK(cx, NULL, "exists", file);
2352     *vp = BOOLEAN_TO_JSVAL(js_exists(cx, file));
2353     break;
2354     case FILE_ISNATIVE:
2355     SECURITY_CHECK(cx, NULL, "isNative", file);
2356     *vp = BOOLEAN_TO_JSVAL(file->isNative);
2357     break;
2358     case FILE_CANREAD:
2359     SECURITY_CHECK(cx, NULL, "canRead", file);
2360     *vp = BOOLEAN_TO_JSVAL(js_canRead(cx, file));
2361     break;
2362     case FILE_CANWRITE:
2363     SECURITY_CHECK(cx, NULL, "canWrite", file);
2364     *vp = BOOLEAN_TO_JSVAL(js_canWrite(cx, file));
2365     break;
2366     case FILE_OPEN:
2367     SECURITY_CHECK(cx, NULL, "isOpen", file);
2368     *vp = BOOLEAN_TO_JSVAL(file->isOpen);
2369     break;
2370     case FILE_APPEND :
2371     SECURITY_CHECK(cx, NULL, "canAppend", file);
2372     JSFILE_CHECK_OPEN("canAppend");
2373     *vp = BOOLEAN_TO_JSVAL(!file->isNative &&
2374     (file->mode&PR_APPEND)==PR_APPEND);
2375     break;
2376     case FILE_REPLACE :
2377     SECURITY_CHECK(cx, NULL, "canReplace", file);
2378     JSFILE_CHECK_OPEN("canReplace");
2379     *vp = BOOLEAN_TO_JSVAL(!file->isNative &&
2380     (file->mode&PR_TRUNCATE)==PR_TRUNCATE);
2381     break;
2382     case FILE_AUTOFLUSH :
2383     SECURITY_CHECK(cx, NULL, "hasAutoFlush", file);
2384     JSFILE_CHECK_OPEN("hasAutoFlush");
2385     *vp = BOOLEAN_TO_JSVAL(!file->isNative && file->hasAutoflush);
2386     break;
2387     case FILE_TYPE:
2388     SECURITY_CHECK(cx, NULL, "type", file);
2389     JSFILE_CHECK_OPEN("type");
2390     if(js_isDirectory(cx, file)){
2391     *vp = JSVAL_VOID;
2392     break;
2393     }
2394    
2395     switch (file->type) {
2396     case ASCII:
2397     *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, asciistring));
2398     break;
2399     case UTF8:
2400     *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, utfstring));
2401     break;
2402     case UCS2:
2403     *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, unicodestring));
2404     break;
2405     default:
2406     JS_ReportWarning(cx, "Unsupported file type %d, proceeding",
2407     file->type);
2408     }
2409     break;
2410     case FILE_MODE:
2411     SECURITY_CHECK(cx, NULL, "mode", file);
2412     JSFILE_CHECK_OPEN("mode");
2413 siliconforks 507 bytes = cx->malloc(MODE_SIZE);
2414 siliconforks 332 bytes[0] = '\0';
2415     flag = JS_FALSE;
2416    
2417     if ((file->mode&PR_RDONLY)==PR_RDONLY) {
2418     if (flag) strcat(bytes, ",");
2419     strcat(bytes, "read");
2420     flag = JS_TRUE;
2421     }
2422     if ((file->mode&PR_WRONLY)==PR_WRONLY) {
2423     if (flag) strcat(bytes, ",");
2424     strcat(bytes, "write");
2425     flag = JS_TRUE;
2426     }
2427     if ((file->mode&PR_RDWR)==PR_RDWR) {
2428     if (flag) strcat(bytes, ",");
2429     strcat(bytes, "readWrite");
2430     flag = JS_TRUE;
2431     }
2432     if ((file->mode&PR_APPEND)==PR_APPEND) {
2433     if (flag) strcat(bytes, ",");
2434     strcat(bytes, "append");
2435     flag = JS_TRUE;
2436     }
2437     if ((file->mode&PR_CREATE_FILE)==PR_CREATE_FILE) {
2438     if (flag) strcat(bytes, ",");
2439     strcat(bytes, "create");
2440     flag = JS_TRUE;
2441     }
2442     if ((file->mode&PR_TRUNCATE)==PR_TRUNCATE) {
2443     if (flag) strcat(bytes, ",");
2444     strcat(bytes, "replace");
2445     flag = JS_TRUE;
2446     }
2447     if (file->hasAutoflush) {
2448     if (flag) strcat(bytes, ",");
2449     strcat(bytes, "hasAutoFlush");
2450     flag = JS_TRUE;
2451     }
2452     *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, bytes));
2453 siliconforks 507 cx->free(bytes);
2454 siliconforks 332 break;
2455     case FILE_CREATED:
2456     SECURITY_CHECK(cx, NULL, "creationTime", file);
2457     JSFILE_CHECK_NATIVE("creationTime");
2458     if(((file->isOpen)?
2459     PR_GetOpenFileInfo(file->handle, &info):
2460     PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){
2461     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2462     JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
2463     goto out;
2464     }
2465    
2466     PR_ExplodeTime(info.creationTime, PR_LocalTimeParameters,&expandedTime);
2467     *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year,
2468     expandedTime.tm_month,
2469     expandedTime.tm_mday,
2470     expandedTime.tm_hour,
2471     expandedTime.tm_min,
2472     expandedTime.tm_sec));
2473     break;
2474     case FILE_MODIFIED:
2475     SECURITY_CHECK(cx, NULL, "lastModified", file);
2476     JSFILE_CHECK_NATIVE("lastModified");
2477     if(((file->isOpen)?
2478     PR_GetOpenFileInfo(file->handle, &info):
2479     PR_GetFileInfo(file->path, &info))!=PR_SUCCESS){
2480     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2481     JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, file->path);
2482     goto out;
2483     }
2484    
2485     PR_ExplodeTime(info.modifyTime, PR_LocalTimeParameters, &expandedTime);
2486     *vp = OBJECT_TO_JSVAL(js_NewDateObject(cx, expandedTime.tm_year,
2487     expandedTime.tm_month,
2488     expandedTime.tm_mday,
2489     expandedTime.tm_hour,
2490     expandedTime.tm_min,
2491     expandedTime.tm_sec));
2492     break;
2493     case FILE_SIZE:
2494     SECURITY_CHECK(cx, NULL, "size", file);
2495     *vp = js_size(cx, file);
2496     break;
2497     case FILE_LENGTH:
2498     SECURITY_CHECK(cx, NULL, "length", file);
2499     JSFILE_CHECK_NATIVE("length");
2500    
2501     if (js_isDirectory(cx, file)) { /* XXX debug me */
2502     PRDir *dir;
2503     PRDirEntry *entry;
2504     jsint count = 0;
2505    
2506     if(!(dir = PR_OpenDir(file->path))){
2507     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2508     JSFILEMSG_CANNOT_OPEN_DIR, file->path);
2509     goto out;
2510     }
2511    
2512     while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH))) {
2513     count++;
2514     }
2515    
2516     if(!PR_CloseDir(dir)){
2517     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2518     JSFILEMSG_OP_FAILED, "close", file->path);
2519    
2520     goto out;
2521     }
2522    
2523     *vp = INT_TO_JSVAL(count);
2524     break;
2525     }else{
2526     /* return file size */
2527     *vp = js_size(cx, file);
2528     }
2529     break;
2530     case FILE_RANDOMACCESS:
2531     SECURITY_CHECK(cx, NULL, "hasRandomAccess", file);
2532     JSFILE_CHECK_OPEN("hasRandomAccess");
2533     *vp = BOOLEAN_TO_JSVAL(file->hasRandomAccess);
2534     break;
2535     case FILE_POSITION:
2536     SECURITY_CHECK(cx, NULL, "position", file);
2537     JSFILE_CHECK_NATIVE("position");
2538     JSFILE_CHECK_OPEN("position");
2539    
2540     if(!file->hasRandomAccess){
2541     JS_ReportWarning(cx, "File %s doesn't support random access, can't report the position, proceeding");
2542     *vp = JSVAL_VOID;
2543     break;
2544     }
2545    
2546     if (file->isOpen && js_isFile(cx, file)) {
2547     int pos = PR_Seek(file->handle, 0, PR_SEEK_CUR);
2548     if(pos!=-1){
2549     *vp = INT_TO_JSVAL(pos);
2550     }else{
2551     JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
2552     JSFILEMSG_CANNOT_REPORT_POSITION, file->path);
2553     goto out;
2554     }
2555     }else {
2556     JS_ReportWarning(cx, "File %s is closed or not a plain file,"
2557     " can't report position, proceeding");
2558     goto out;
2559     }
2560     break;
2561     default:
2562     SECURITY_CHECK(cx, NULL, "file_access", file);
2563    
2564     /* this is some other property -- try to use the dir["file"] syntax */
2565     if (js_isDirectory(cx, file)) {
2566     PRDir *dir = NULL;
2567     PRDirEntry *entry = NULL;
2568     char *prop_name;
2569    
2570     str = JS_ValueToString(cx, id);
2571     if (!str)
2572     return JS_FALSE;