1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla Communicator client code, released
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.
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.
39 * ***** END LICENSE BLOCK ***** */
44 #if JS_HAS_FILE_OBJECT
49 /* ----------------- Platform-specific includes and defines ----------------- */
50 #if defined(XP_WIN) || defined(XP_OS2)
53 # include <sys/types.h>
54 # include <sys/stat.h>
55 # define FILESEPARATOR '\\'
56 # define FILESEPARATOR2 '/'
57 # define CURRENT_DIR "c:\\"
59 # define PCLOSE _pclose
60 #elif defined(XP_UNIX) || defined(XP_BEOS)
65 # define FILESEPARATOR '/'
66 # define FILESEPARATOR2 '\0'
67 # define CURRENT_DIR "/"
69 # define PCLOSE pclose
72 /* --------------- Platform-independent includes and defines ---------------- */
87 #include "jsutil.h" /* Added by JSIFY */
90 /* NSPR dependencies */
94 #define SPECIAL_FILE_STRING "Special File"
95 #define CURRENTDIR_PROPERTY "currentDir"
96 #define SEPARATOR_PROPERTY "separator"
97 #define FILE_CONSTRUCTOR "File"
98 #define PIPE_SYMBOL '|'
104 #define asciistring "text"
105 #define utfstring "binary"
106 #define unicodestring "unicode"
108 #define MAX_PATH_LENGTH 1024
109 #define MODE_SIZE 256
110 #define NUMBER_SIZE 32
111 #define MAX_LINE_LENGTH 256
112 #define URL_PREFIX "file://"
114 #define STDINPUT_NAME "Standard input stream"
115 #define STDOUTPUT_NAME "Standard output stream"
116 #define STDERROR_NAME "Standard error stream"
118 #define RESOLVE_PATH js_canonicalPath /* js_absolutePath */
121 typedef enum JSFileErrNum
{
122 #define MSG_DEF(name, number, count, exception, format) \
124 #include "jsfile.msg"
130 #define JSFILE_HAS_DFLT_MSG_STRINGS 1
132 JSErrorFormatString JSFile_ErrorFormatString
[JSFileErr_Limit
] = {
133 #if JSFILE_HAS_DFLT_MSG_STRINGS
134 #define MSG_DEF(name, number, count, exception, format) \
137 #define MSG_DEF(name, number, count, exception, format) \
140 #include "jsfile.msg"
144 const JSErrorFormatString
*
145 JSFile_GetErrorMessage(void *userRef
, const char *locale
,
146 const uintN errorNumber
)
148 if ((errorNumber
> 0) && (errorNumber
< JSFileErr_Limit
))
149 return &JSFile_ErrorFormatString
[errorNumber
];
154 #define JSFILE_CHECK_NATIVE(op) \
155 if (file->isNative) { \
156 JS_ReportWarning(cx, "Cannot call or access \"%s\" on native file %s",\
161 #define JSFILE_CHECK_WRITE \
162 if (!file->isOpen) { \
163 JS_ReportWarning(cx, \
164 "File %s is closed, will open it for writing, proceeding", \
166 js_FileOpen(cx, obj, file, "write,append,create"); \
168 if (!js_canWrite(cx, file)) { \
169 JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
170 JSFILEMSG_CANNOT_WRITE, file->path); \
174 #define JSFILE_CHECK_READ \
175 if (!file->isOpen) { \
176 JS_ReportWarning(cx, \
177 "File %s is closed, will open it for reading, proceeding", \
179 js_FileOpen(cx, obj, file, "read"); \
181 if (!js_canRead(cx, file)) { \
182 JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
183 JSFILEMSG_CANNOT_READ, file->path); \
187 #define JSFILE_CHECK_OPEN(op) \
188 if (!file->isOpen) { \
189 JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
190 JSFILEMSG_FILE_MUST_BE_OPEN, op); \
194 #define JSFILE_CHECK_CLOSED(op) \
195 if (file->isOpen) { \
196 JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
197 JSFILEMSG_FILE_MUST_BE_CLOSED, op); \
201 #define JSFILE_CHECK_ONE_ARG(op) \
203 char str[NUMBER_SIZE]; \
204 sprintf(str, "%d", argc); \
205 JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
206 JSFILEMSG_EXPECTS_ONE_ARG_ERROR, op, str); \
212 Security mechanism, should define a callback for this.
213 The parameters are as follows:
214 SECURITY_CHECK(JSContext *cx, JSPrincipals *ps, char *op_name, JSFile *file)
215 XXX Should this be a real function returning a JSBool result (and getting
216 some typesafety help from the compiler?).
218 #define SECURITY_CHECK(cx, ps, op, file) \
219 /* Define a callback here... */
222 /* Structure representing the file internally */
223 typedef struct JSFile
{
224 char *path
; /* the path to the file. */
226 int32 mode
; /* mode used to open the file: read, write, append, create, etc.. */
227 int32 type
; /* Asciiz, utf, unicode */
228 char byteBuffer
[3]; /* bytes read in advance by js_FileRead ( UTF8 encoding ) */
229 jsint nbBytesInBuf
; /* number of bytes stored in the buffer above */
230 jschar charBuffer
; /* character read in advance by readln ( mac files only ) */
231 JSBool charBufferUsed
; /* flag indicating if the buffer above is being used */
232 JSBool hasRandomAccess
;/* can the file be randomly accessed? false for stdin, and
233 UTF-encoded files. */
234 JSBool hasAutoflush
; /* should we force a flush for each line break? */
235 JSBool isNative
; /* if the file is using OS-specific file FILE type */
236 /* We can actually put the following two in a union since they should never be used at the same time */
237 PRFileDesc
*handle
; /* the handle for the file, if open. */
238 FILE *nativehandle
; /* native handle, for stuff NSPR doesn't do. */
239 JSBool isPipe
; /* if the file is really an OS pipe */
242 /* a few forward declarations... */
243 JS_PUBLIC_API(JSObject
*) js_NewFileObject(JSContext
*cx
, char *filename
);
244 static JSBool
file_open(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
245 static JSBool
file_close(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
);
247 /* New filename manipulation procesures */
248 /* assumes we don't have leading/trailing spaces */
250 js_filenameHasAPipe(const char *filename
)
255 return filename
[0] == PIPE_SYMBOL
||
256 filename
[strlen(filename
) - 1] == PIPE_SYMBOL
;
260 js_isAbsolute(const char *name
)
262 #if defined(XP_WIN) || defined(XP_OS2)
263 return *name
&& name
[1] == ':';
266 # if defined(XP_UNIX) || defined(XP_BEOS)
276 * Concatenates base and name to produce a valid filename.
277 * Returned string must be freed.
280 js_combinePath(JSContext
*cx
, const char *base
, const char *name
)
282 int len
= strlen(base
);
283 char* result
= JS_malloc(cx
, len
+ strlen(name
) + 2);
288 strcpy(result
, base
);
290 if (base
[len
- 1] != FILESEPARATOR
&& base
[len
- 1] != FILESEPARATOR2
) {
291 result
[len
] = FILESEPARATOR
;
292 result
[len
+ 1] = '\0';
294 strcat(result
, name
);
298 /* Extract the last component from a path name. Returned string must be freed */
300 js_fileBaseName(JSContext
*cx
, const char *pathname
)
305 index
= strlen(pathname
)-1;
307 /* Chop off trailing seperators. */
308 while (index
> 0 && (pathname
[index
]==FILESEPARATOR
||
309 pathname
[index
]==FILESEPARATOR2
)) {
315 /* Now find the next separator. */
316 while (index
>= 0 && pathname
[index
] != FILESEPARATOR
&&
317 pathname
[index
] != FILESEPARATOR2
) {
321 /* Allocate and copy. */
322 result
= JS_malloc(cx
, aux
- index
+ 1);
325 strncpy(result
, pathname
+ index
+ 1, aux
- index
);
326 result
[aux
- index
] = '\0';
331 * Returns everything but the last component from a path name.
332 * Returned string must be freed.
335 js_fileDirectoryName(JSContext
*cx
, const char *pathname
)
338 const char *cp
, *end
;
341 end
= pathname
+ strlen(pathname
);
344 /* If this is already a directory, chop off the trailing /s. */
345 while (cp
>= pathname
) {
346 if (*cp
!= FILESEPARATOR
&& *cp
!= FILESEPARATOR2
)
351 if (cp
< pathname
&& end
!= pathname
) {
352 /* There were just /s, return the root. */
353 result
= JS_malloc(cx
, 1 + 1); /* The separator + trailing NUL. */
354 result
[0] = FILESEPARATOR
;
359 /* Now chop off the last portion. */
360 while (cp
>= pathname
) {
361 if (*cp
== FILESEPARATOR
|| *cp
== FILESEPARATOR2
)
366 /* Check if this is a leaf. */
368 /* It is, return "pathname/". */
369 if (end
[-1] == FILESEPARATOR
|| end
[-1] == FILESEPARATOR2
) {
370 /* Already has its terminating /. */
371 return JS_strdup(cx
, pathname
);
374 pathsize
= end
- pathname
+ 1;
375 result
= JS_malloc(cx
, pathsize
+ 1);
379 strcpy(result
, pathname
);
380 result
[pathsize
- 1] = FILESEPARATOR
;
381 result
[pathsize
] = '\0';
386 /* Return everything up to and including the seperator. */
387 pathsize
= cp
- pathname
+ 1;
388 result
= JS_malloc(cx
, pathsize
+ 1);
392 strncpy(result
, pathname
, pathsize
);
393 result
[pathsize
] = '\0';
399 js_absolutePath(JSContext
*cx
, const char * path
)
405 if (js_isAbsolute(path
)) {
406 return JS_strdup(cx
, path
);
408 obj
= JS_GetGlobalObject(cx
);
409 if (!JS_GetProperty(cx
, obj
, FILE_CONSTRUCTOR
, &prop
)) {
410 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
411 JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR
);
412 return JS_strdup(cx
, path
);
415 obj
= JSVAL_TO_OBJECT(prop
);
416 if (!JS_GetProperty(cx
, obj
, CURRENTDIR_PROPERTY
, &prop
)) {
417 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
418 JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR
);
419 return JS_strdup(cx
, path
);
422 str
= JS_ValueToString(cx
, prop
);
424 return JS_strdup(cx
, path
);
426 /* should we have an array of curr dirs indexed by drive for windows? */
427 return js_combinePath(cx
, JS_GetStringBytes(str
), path
);
431 /* Side effect: will remove spaces in the beginning/end of the filename */
433 js_canonicalPath(JSContext
*cx
, char *oldpath
)
436 char *path
= oldpath
;
437 char *base
, *dir
, *current
, *result
;
440 unsigned int i
= 0, j
= strlen(path
)-1;
442 /* This is probably optional */
443 /* Remove possible spaces in the beginning and end */
444 while (i
< j
&& path
[i
] == ' ')
446 while (j
>= 0 && path
[j
] == ' ')
449 tmp
= JS_malloc(cx
, j
-i
+2);
453 strncpy(tmp
, path
+ i
, j
- i
+ 1);
454 tmp
[j
- i
+ 1] = '\0';
459 if (js_filenameHasAPipe(path
))
462 /* file:// support. */
463 if (!strncmp(path
, URL_PREFIX
, strlen(URL_PREFIX
))) {
464 tmp
= js_canonicalPath(cx
, path
+ strlen(URL_PREFIX
));
469 if (!js_isAbsolute(path
)) {
470 tmp
= js_absolutePath(cx
, path
);
477 result
= JS_strdup(cx
, "");
481 base
= js_fileBaseName(cx
, current
);
482 dir
= js_fileDirectoryName(cx
, current
);
484 while (strcmp(dir
, current
)) {
485 if (!strcmp(base
, "..")) {
492 result
= JS_malloc(cx
, strlen(base
) + 1 + strlen(tmp
) + 1);
496 strcpy(result
, base
);
499 result
[c
] = FILESEPARATOR
;
500 result
[c
+ 1] = '\0';
506 JS_free(cx
, current
);
509 base
= js_fileBaseName(cx
, current
);
510 dir
= js_fileDirectoryName(cx
, current
);
514 result
= JS_malloc(cx
, strlen(dir
)+1+strlen(tmp
)+1);
521 if ((result
[c
-1]!=FILESEPARATOR
)&&(result
[c
-1]!=FILESEPARATOR2
)) {
522 result
[c
] = FILESEPARATOR
;
536 JS_free(cx
, current
);
541 /* -------------------------- Text conversion ------------------------------- */
542 /* The following is ripped from libi18n/unicvt.c and include files.. */
545 * UTF8 defines and macros
547 #define ONE_OCTET_BASE 0x00 /* 0xxxxxxx */
548 #define ONE_OCTET_MASK 0x7F /* x1111111 */
549 #define CONTINUING_OCTET_BASE 0x80 /* 10xxxxxx */
550 #define CONTINUING_OCTET_MASK 0x3F /* 00111111 */
551 #define TWO_OCTET_BASE 0xC0 /* 110xxxxx */
552 #define TWO_OCTET_MASK 0x1F /* 00011111 */
553 #define THREE_OCTET_BASE 0xE0 /* 1110xxxx */
554 #define THREE_OCTET_MASK 0x0F /* 00001111 */
555 #define FOUR_OCTET_BASE 0xF0 /* 11110xxx */
556 #define FOUR_OCTET_MASK 0x07 /* 00000111 */
557 #define FIVE_OCTET_BASE 0xF8 /* 111110xx */
558 #define FIVE_OCTET_MASK 0x03 /* 00000011 */
559 #define SIX_OCTET_BASE 0xFC /* 1111110x */
560 #define SIX_OCTET_MASK 0x01 /* 00000001 */
562 #define IS_UTF8_1ST_OF_1(x) (( (x)&~ONE_OCTET_MASK ) == ONE_OCTET_BASE)
563 #define IS_UTF8_1ST_OF_2(x) (( (x)&~TWO_OCTET_MASK ) == TWO_OCTET_BASE)
564 #define IS_UTF8_1ST_OF_3(x) (( (x)&~THREE_OCTET_MASK) == THREE_OCTET_BASE)
565 #define IS_UTF8_1ST_OF_4(x) (( (x)&~FOUR_OCTET_MASK ) == FOUR_OCTET_BASE)
566 #define IS_UTF8_1ST_OF_5(x) (( (x)&~FIVE_OCTET_MASK ) == FIVE_OCTET_BASE)
567 #define IS_UTF8_1ST_OF_6(x) (( (x)&~SIX_OCTET_MASK ) == SIX_OCTET_BASE)
568 #define IS_UTF8_2ND_THRU_6TH(x) \
569 (( (x)&~CONTINUING_OCTET_MASK ) == CONTINUING_OCTET_BASE)
570 #define IS_UTF8_1ST_OF_UCS2(x) \
571 IS_UTF8_1ST_OF_1(x) \
572 || IS_UTF8_1ST_OF_2(x) \
573 || IS_UTF8_1ST_OF_3(x)
576 #define MAX_UCS2 0xFFFF
577 #define DEFAULT_CHAR 0x003F /* Default char is "?" */
578 #define BYTE_MASK 0xBF
579 #define BYTE_MARK 0x80
582 /* Function: one_ucs2_to_utf8_char
584 * Function takes one UCS-2 char and writes it to a UTF-8 buffer.
585 * We need a UTF-8 buffer because we don't know before this
586 * function how many bytes of utf-8 data will be written. It also
587 * takes a pointer to the end of the UTF-8 buffer so that we don't
588 * overwrite data. This function returns the number of UTF-8 bytes
589 * of data written, or -1 if the buffer would have been overrun.
592 #define LINE_SEPARATOR 0x2028
593 #define PARAGRAPH_SEPARATOR 0x2029
594 static int16
one_ucs2_to_utf8_char(unsigned char *tobufp
,
595 unsigned char *tobufendp
,
598 int16 numUTF8bytes
= 0;
600 if (onechar
== LINE_SEPARATOR
|| onechar
== PARAGRAPH_SEPARATOR
) {
601 strcpy((char*)tobufp
, "\n");
602 return strlen((char*)tobufp
);
605 if (onechar
< 0x80) {
607 } else if (onechar
< 0x800) {
610 /* 0x800 >= onechar <= MAX_UCS2 */
614 tobufp
+= numUTF8bytes
;
616 /* return error if we don't have space for the whole character */
617 if (tobufp
> tobufendp
) {
621 switch(numUTF8bytes
) {
622 case 3: *--tobufp
= (onechar
| BYTE_MARK
) & BYTE_MASK
; onechar
>>=6;
623 *--tobufp
= (onechar
| BYTE_MARK
) & BYTE_MASK
; onechar
>>=6;
624 *--tobufp
= onechar
| THREE_OCTET_BASE
;
627 case 2: *--tobufp
= (onechar
| BYTE_MARK
) & BYTE_MASK
; onechar
>>=6;
628 *--tobufp
= onechar
| TWO_OCTET_BASE
;
631 case 1: *--tobufp
= (unsigned char)onechar
;
641 * Convert a utf8 multibyte character to ucs2
643 * inputs: pointer to utf8 character(s)
644 * length of utf8 buffer ("read" length limit)
645 * pointer to return ucs2 character
647 * outputs: number of bytes in the utf8 character
648 * -1 if not a valid utf8 character sequence
649 * -2 if the buffer is too short
652 utf8_to_ucs2_char(const unsigned char *utf8p
, int16 buflen
, uint16
*ucs2p
)
654 uint16 lead
, cont1
, cont2
;
657 * Check for minimum buffer length
659 if ((buflen
< 1) || (utf8p
== NULL
)) {
662 lead
= (uint16
) (*utf8p
);
665 * Check for a one octet sequence
667 if (IS_UTF8_1ST_OF_1(lead
)) {
668 *ucs2p
= lead
& ONE_OCTET_MASK
;
673 * Check for a two octet sequence
675 if (IS_UTF8_1ST_OF_2(*utf8p
)) {
678 cont1
= (uint16
) *(utf8p
+1);
679 if (!IS_UTF8_2ND_THRU_6TH(cont1
))
681 *ucs2p
= (lead
& TWO_OCTET_MASK
) << 6;
682 *ucs2p
|= cont1
& CONTINUING_OCTET_MASK
;
687 * Check for a three octet sequence
689 else if (IS_UTF8_1ST_OF_3(lead
)) {
692 cont1
= (uint16
) *(utf8p
+1);
693 cont2
= (uint16
) *(utf8p
+2);
694 if ( (!IS_UTF8_2ND_THRU_6TH(cont1
))
695 || (!IS_UTF8_2ND_THRU_6TH(cont2
)))
697 *ucs2p
= (lead
& THREE_OCTET_MASK
) << 12;
698 *ucs2p
|= (cont1
& CONTINUING_OCTET_MASK
) << 6;
699 *ucs2p
|= cont2
& CONTINUING_OCTET_MASK
;
702 else { /* not a valid utf8/ucs2 character */
707 /* ----------------------------- Helper functions --------------------------- */
708 /* Ripped off from lm_win.c .. */
709 /* where is strcasecmp?.. for now, it's case sensitive..
711 * strcasecmp is in strings.h, but on windows it's called _stricmp...
712 * will need to #ifdef this
716 js_FileHasOption(JSContext
*cx
, const char *oldoptions
, const char *name
)
718 char *comma
, *equal
, *current
;
719 char *options
= JS_strdup(cx
, oldoptions
);
724 comma
= strchr(current
, ',');
725 if (comma
) *comma
= '\0';
726 equal
= strchr(current
, '=');
727 if (equal
) *equal
= '\0';
728 if (strcmp(current
, name
) == 0) {
729 if (!equal
|| strcmp(equal
+ 1, "yes") == 0)
732 found
= atoi(equal
+ 1);
734 if (equal
) *equal
= '=';
735 if (comma
) *comma
= ',';
740 JS_free(cx
, options
);
744 /* empty the buffer */
746 js_ResetBuffers(JSFile
* file
)
748 file
->charBufferUsed
= JS_FALSE
;
749 file
->nbBytesInBuf
= 0;
752 /* Reset file attributes */
754 js_ResetAttributes(JSFile
* file
)
756 file
->mode
= file
->type
= 0;
757 file
->isOpen
= JS_FALSE
;
759 file
->nativehandle
= NULL
;
760 file
->hasRandomAccess
= JS_TRUE
; /* Innocent until proven guilty. */
761 file
->hasAutoflush
= JS_FALSE
;
762 file
->isNative
= JS_FALSE
;
763 file
->isPipe
= JS_FALSE
;
765 js_ResetBuffers(file
);
769 js_FileOpen(JSContext
*cx
, JSObject
*obj
, JSFile
*file
, char *mode
){
770 JSString
*type
, *mask
;
774 type
= JS_InternString(cx
, asciistring
);
775 mask
= JS_NewStringCopyZ(cx
, mode
);
776 v
[0] = STRING_TO_JSVAL(mask
);
777 v
[1] = STRING_TO_JSVAL(type
);
779 if (!file_open(cx
, obj
, 2, v
, &rval
))
784 /* Buffered version of PR_Read. Used by js_FileRead */
786 js_BufferedRead(JSFile
*f
, unsigned char *buf
, int32 len
)
790 while (f
->nbBytesInBuf
>0&&len
>0) {
791 buf
[0] = f
->byteBuffer
[0];
792 f
->byteBuffer
[0] = f
->byteBuffer
[1];
793 f
->byteBuffer
[1] = f
->byteBuffer
[2];
801 count
+= (!f
->isNative
)
802 ? PR_Read(f
->handle
, buf
, len
)
803 : fread(buf
, 1, len
, f
->nativehandle
);
809 js_FileRead(JSContext
*cx
, JSFile
*file
, jschar
*buf
, int32 len
, int32 mode
)
814 unsigned char utfbuf
[3];
816 if (file
->charBufferUsed
) {
817 buf
[0] = file
->charBuffer
;
820 file
->charBufferUsed
= JS_FALSE
;
825 aux
= (unsigned char*)JS_malloc(cx
, len
);
829 count
= js_BufferedRead(file
, aux
, len
);
835 for (i
= 0; i
< len
; i
++)
836 buf
[i
] = (jschar
)aux
[i
];
843 for (count
= 0;count
<len
;count
++) {
844 i
= js_BufferedRead(file
, utfbuf
+remainder
, 3-remainder
);
848 i
= utf8_to_ucs2_char(utfbuf
, (int16
)i
, &buf
[count
] );
853 utfbuf
[0] = utfbuf
[1];
854 utfbuf
[1] = utfbuf
[2];
857 utfbuf
[0] = utfbuf
[2];
864 while (remainder
>0) {
865 file
->byteBuffer
[file
->nbBytesInBuf
] = utfbuf
[0];
866 file
->nbBytesInBuf
++;
867 utfbuf
[0] = utfbuf
[1];
868 utfbuf
[1] = utfbuf
[2];
874 count
= js_BufferedRead(file
, (unsigned char *)buf
, len
* 2) >> 1;
886 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
887 JSFILEMSG_OP_FAILED
, "read", file
->path
);
894 js_FileSeek(JSContext
*cx
, JSFile
*file
, int32 len
, int32 mode
)
898 unsigned char utfbuf
[3];
903 count
= PR_Seek(file
->handle
, len
, PR_SEEK_CUR
);
908 for (count
= 0;count
<len
;count
++) {
909 i
= js_BufferedRead(file
, utfbuf
+remainder
, 3-remainder
);
913 i
= utf8_to_ucs2_char(utfbuf
, (int16
)i
, &tmp
);
918 utfbuf
[0] = utfbuf
[1];
919 utfbuf
[1] = utfbuf
[2];
922 utfbuf
[0] = utfbuf
[2];
929 while (remainder
>0) {
930 file
->byteBuffer
[file
->nbBytesInBuf
] = utfbuf
[0];
931 file
->nbBytesInBuf
++;
932 utfbuf
[0] = utfbuf
[1];
933 utfbuf
[1] = utfbuf
[2];
939 count
= PR_Seek(file
->handle
, len
*2, PR_SEEK_CUR
)/2;
948 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
949 JSFILEMSG_OP_FAILED
, "seek", file
->path
);
956 js_FileWrite(JSContext
*cx
, JSFile
*file
, jschar
*buf
, int32 len
, int32 mode
)
959 int32 count
= 0, i
, j
;
960 unsigned char *utfbuf
;
964 aux
= (unsigned char*)JS_malloc(cx
, len
);
968 for (i
= 0; i
<len
; i
++)
969 aux
[i
] = buf
[i
] % 256;
971 count
= (!file
->isNative
)
972 ? PR_Write(file
->handle
, aux
, len
)
973 : fwrite(aux
, 1, len
, file
->nativehandle
);
984 utfbuf
= (unsigned char*)JS_malloc(cx
, len
*3);
985 if (!utfbuf
) return 0;
987 for (count
= 0;count
<len
;count
++) {
988 j
= one_ucs2_to_utf8_char(utfbuf
+i
, utfbuf
+len
*3, buf
[count
]);
995 j
= (!file
->isNative
)
996 ? PR_Write(file
->handle
, utfbuf
, i
)
997 : fwrite(utfbuf
, 1, i
, file
->nativehandle
);
1000 JS_free(cx
, utfbuf
);
1003 JS_free(cx
, utfbuf
);
1007 count
= (!file
->isNative
)
1008 ? PR_Write(file
->handle
, buf
, len
*2) >> 1
1009 : fwrite(buf
, 1, len
*2, file
->nativehandle
) >> 1;
1021 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1022 JSFILEMSG_OP_FAILED
, "write", file
->path
);
1028 /* ----------------------------- Property checkers -------------------------- */
1030 js_exists(JSContext
*cx
, JSFile
*file
)
1032 if (file
->isNative
) {
1033 /* It doesn't make sense for a pipe of stdstream. */
1037 return PR_Access(file
->path
, PR_ACCESS_EXISTS
) == PR_SUCCESS
;
1041 js_canRead(JSContext
*cx
, JSFile
*file
)
1043 if (!file
->isNative
) {
1044 if (file
->isOpen
&& !(file
->mode
& PR_RDONLY
))
1046 return PR_Access(file
->path
, PR_ACCESS_READ_OK
) == PR_SUCCESS
;
1050 /* Is this pipe open for reading? */
1051 return file
->path
[0] == PIPE_SYMBOL
;
1054 return !strcmp(file
->path
, STDINPUT_NAME
);
1058 js_canWrite(JSContext
*cx
, JSFile
*file
)
1060 if (!file
->isNative
) {
1061 if (file
->isOpen
&& !(file
->mode
& PR_WRONLY
))
1063 return PR_Access(file
->path
, PR_ACCESS_WRITE_OK
) == PR_SUCCESS
;
1067 /* Is this pipe open for writing? */
1068 return file
->path
[strlen(file
->path
)-1] == PIPE_SYMBOL
;
1071 return !strcmp(file
->path
, STDOUTPUT_NAME
) ||
1072 !strcmp(file
->path
, STDERROR_NAME
);
1076 js_isFile(JSContext
*cx
, JSFile
*file
)
1078 if (!file
->isNative
) {
1082 ? PR_GetOpenFileInfo(file
->handle
, &info
)
1083 : PR_GetFileInfo(file
->path
, &info
) != PR_SUCCESS
) {
1084 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1085 JSFILEMSG_CANNOT_ACCESS_FILE_STATUS
, file
->path
);
1089 return info
.type
== PR_FILE_FILE
;
1092 /* This doesn't make sense for a pipe of stdstream. */
1097 js_isDirectory(JSContext
*cx
, JSFile
*file
)
1099 if(!file
->isNative
){
1102 /* Hack needed to get get_property to work. */
1103 if (!js_exists(cx
, file
))
1107 ? PR_GetOpenFileInfo(file
->handle
, &info
)
1108 : PR_GetFileInfo(file
->path
, &info
) != PR_SUCCESS
) {
1109 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1110 JSFILEMSG_CANNOT_ACCESS_FILE_STATUS
, file
->path
);
1114 return info
.type
== PR_FILE_DIRECTORY
;
1117 /* This doesn't make sense for a pipe of stdstream. */
1122 js_size(JSContext
*cx
, JSFile
*file
)
1126 JSFILE_CHECK_NATIVE("size");
1129 ? PR_GetOpenFileInfo(file
->handle
, &info
)
1130 : PR_GetFileInfo(file
->path
, &info
) != PR_SUCCESS
) {
1131 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1132 JSFILEMSG_CANNOT_ACCESS_FILE_STATUS
, file
->path
);
1136 return INT_TO_JSVAL(info
.size
);
1143 * Return the parent object
1146 js_parent(JSContext
*cx
, JSFile
*file
, jsval
*resultp
)
1150 /* Since we only care about pipes and native files, return NULL. */
1151 if (file
->isNative
) {
1152 *resultp
= JSVAL_VOID
;
1156 str
= js_fileDirectoryName(cx
, file
->path
);
1160 /* If the directory is equal to the original path, we're at the root. */
1161 if (!strcmp(file
->path
, str
)) {
1162 *resultp
= JSVAL_NULL
;
1164 JSObject
*obj
= js_NewFileObject(cx
, str
);
1169 *resultp
= OBJECT_TO_JSVAL(obj
);
1177 js_name(JSContext
*cx
, JSFile
*file
, jsval
*vp
)
1187 name
= js_fileBaseName(cx
, file
->path
);
1191 str
= JS_NewString(cx
, name
, strlen(name
));
1197 *vp
= STRING_TO_JSVAL(str
);
1201 /* ------------------------------ File object methods ---------------------------- */
1203 file_open(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1205 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1206 JSString
*strmode
, *strtype
;
1213 SECURITY_CHECK(cx
, NULL
, "open", file
);
1215 /* A native file that is already open */
1216 if(file
->isOpen
&& file
->isNative
) {
1217 JS_ReportWarning(cx
, "Native file %s is already open, proceeding",
1222 /* Close before proceeding */
1224 JS_ReportWarning(cx
, "File %s is already open, we will close it and "
1225 "reopen, proceeding", file
->path
);
1226 if(!file_close(cx
, obj
, 0, NULL
, rval
))
1230 if (js_isDirectory(cx
, file
)) {
1231 JS_ReportWarning(cx
, "%s seems to be a directory, there is no point in "
1232 "trying to open it, proceeding", file
->path
);
1236 /* Path must be defined at this point */
1237 len
= strlen(file
->path
);
1241 strmode
= JS_ValueToString(cx
, argv
[0]);
1243 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1244 JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR
,
1248 mode
= JS_strdup(cx
, JS_GetStringBytes(strmode
));
1250 if(file
->path
[0]==PIPE_SYMBOL
) {
1251 /* pipe default mode */
1252 mode
= JS_strdup(cx
, "read");
1253 } else if(file
->path
[len
-1]==PIPE_SYMBOL
) {
1254 /* pipe default mode */
1255 mode
= JS_strdup(cx
, "write");
1257 /* non-destructive, permissive defaults. */
1258 mode
= JS_strdup(cx
, "readWrite,append,create");
1262 /* Process the mode */
1264 /* TODO: this is pretty ugly, we walk thru the string too many times */
1265 mask
|= js_FileHasOption(cx
, mode
, "read") ? PR_RDONLY
: 0;
1266 mask
|= js_FileHasOption(cx
, mode
, "write") ? PR_WRONLY
: 0;
1267 mask
|= js_FileHasOption(cx
, mode
, "readWrite")? PR_RDWR
: 0;
1268 mask
|= js_FileHasOption(cx
, mode
, "append") ? PR_APPEND
: 0;
1269 mask
|= js_FileHasOption(cx
, mode
, "create") ? PR_CREATE_FILE
: 0;
1270 mask
|= js_FileHasOption(cx
, mode
, "replace") ? PR_TRUNCATE
: 0;
1273 mask
|= (PR_RDONLY
| PR_WRONLY
);
1274 if ((mask
& PR_RDONLY
) && (mask
& PR_WRONLY
))
1277 file
->hasAutoflush
|= js_FileHasOption(cx
, mode
, "autoflush");
1281 strtype
= JS_ValueToString(cx
, argv
[1]);
1283 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1284 JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR
,
1288 ctype
= JS_GetStringBytes(strtype
);
1290 if(!strcmp(ctype
, utfstring
)) {
1292 } else if (!strcmp(ctype
, unicodestring
)) {
1295 if (strcmp(ctype
, asciistring
)) {
1296 JS_ReportWarning(cx
, "File type %s is not supported, using "
1297 "'text' instead, proceeding", ctype
);
1305 /* Save the relevant fields */
1308 file
->nativehandle
= NULL
;
1309 file
->hasRandomAccess
= (type
!= UTF8
);
1312 * Deal with pipes here. We can't use NSPR for pipes, so we have to use
1315 if (file
->path
[0]==PIPE_SYMBOL
|| file
->path
[len
-1]==PIPE_SYMBOL
) {
1316 if (file
->path
[0] == PIPE_SYMBOL
&& file
->path
[len
-1] == PIPE_SYMBOL
) {
1317 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1318 JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED
);
1323 SECURITY_CHECK(cx
, NULL
, "pipe_open", file
);
1325 if(file
->path
[0] == PIPE_SYMBOL
){
1326 if(mask
& (PR_WRONLY
| PR_APPEND
| PR_CREATE_FILE
| PR_TRUNCATE
)){
1327 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1328 JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES
,
1332 /* open(SPOOLER, "| cat -v | lpr -h 2>/dev/null") -- pipe for writing */
1333 pipemode
[i
++] = 'r';
1335 pipemode
[i
++] = file
->type
==UTF8
? 'b' : 't';
1337 pipemode
[i
++] = '\0';
1338 file
->nativehandle
= POPEN(&file
->path
[1], pipemode
);
1339 } else if(file
->path
[len
-1] == PIPE_SYMBOL
) {
1340 char *command
= JS_malloc(cx
, len
);
1342 strncpy(command
, file
->path
, len
-1);
1343 command
[len
-1] = '\0';
1344 /* open(STATUS, "netstat -an 2>&1 |") */
1345 pipemode
[i
++] = 'w';
1347 pipemode
[i
++] = file
->type
==UTF8
? 'b' : 't';
1349 pipemode
[i
++] = '\0';
1350 file
->nativehandle
= POPEN(command
, pipemode
);
1351 JS_free(cx
, command
);
1354 file
->isNative
= JS_TRUE
;
1355 file
->isPipe
= JS_TRUE
;
1356 file
->hasRandomAccess
= JS_FALSE
;
1359 /* TODO: what about the permissions?? Java ignores the problem... */
1360 file
->handle
= PR_Open(file
->path
, mask
, 0644);
1363 js_ResetBuffers(file
);
1367 /* Set the open flag and return result */
1368 if (file
->handle
== NULL
&& file
->nativehandle
== NULL
) {
1369 file
->isOpen
= JS_FALSE
;
1371 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1372 JSFILEMSG_OP_FAILED
, "open", file
->path
);
1377 file
->isOpen
= JS_TRUE
;
1388 file_close(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1390 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1392 SECURITY_CHECK(cx
, NULL
, "close", file
);
1395 JS_ReportWarning(cx
, "File %s is not open, can't close it, proceeding",
1402 JS_ReportWarning(cx
, "Unable to close a native file, proceeding", file
->path
);
1405 if(file
->handle
&& PR_Close(file
->handle
)){
1406 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1407 JSFILEMSG_OP_FAILED
, "close", file
->path
);
1413 if(PCLOSE(file
->nativehandle
)==-1){
1414 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1415 JSFILEMSG_OP_FAILED
, "pclose", file
->path
);
1420 js_ResetAttributes(file
);
1430 file_remove(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1432 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1434 SECURITY_CHECK(cx
, NULL
, "remove", file
);
1435 JSFILE_CHECK_NATIVE("remove");
1436 JSFILE_CHECK_CLOSED("remove");
1438 if ((js_isDirectory(cx
, file
) ?
1439 PR_RmDir(file
->path
) : PR_Delete(file
->path
))==PR_SUCCESS
) {
1440 js_ResetAttributes(file
);
1444 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1445 JSFILEMSG_OP_FAILED
, "remove", file
->path
);
1449 *rval
= JSVAL_FALSE
;
1453 /* Raw PR-based function. No text processing. Just raw data copying. */
1455 file_copyTo(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1457 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1459 PRFileDesc
*handle
= NULL
;
1462 JSBool fileInitiallyOpen
=JS_FALSE
;
1464 SECURITY_CHECK(cx
, NULL
, "copyTo", file
); /* may need a second argument!*/
1465 JSFILE_CHECK_ONE_ARG("copyTo");
1466 JSFILE_CHECK_NATIVE("copyTo");
1467 /* remeber the state */
1468 fileInitiallyOpen
= file
->isOpen
;
1471 dest
= JS_GetStringBytes(JS_ValueToString(cx
, argv
[0]));
1473 /* make sure we are not reading a file open for writing */
1474 if (file
->isOpen
&& !js_canRead(cx
, file
)) {
1475 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1476 JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR
, file
->path
);
1480 if (file
->handle
==NULL
){
1481 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1482 JSFILEMSG_OP_FAILED
, "open", file
->path
);
1486 handle
= PR_Open(dest
, PR_WRONLY
|PR_CREATE_FILE
|PR_TRUNCATE
, 0644);
1489 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1490 JSFILEMSG_OP_FAILED
, "open", dest
);
1494 if ((size
=js_size(cx
, file
))==JSVAL_VOID
) {
1498 buffer
= JS_malloc(cx
, size
);
1500 count
= INT_TO_JSVAL(PR_Read(file
->handle
, buffer
, size
));
1504 JS_free(cx
, buffer
);
1505 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1506 JSFILEMSG_COPY_READ_ERROR
, file
->path
);
1510 count
= INT_TO_JSVAL(PR_Write(handle
, buffer
, JSVAL_TO_INT(size
)));
1514 JS_free(cx
, buffer
);
1515 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1516 JSFILEMSG_COPY_WRITE_ERROR
, file
->path
);
1520 JS_free(cx
, buffer
);
1522 if(!fileInitiallyOpen
){
1523 if(!file_close(cx
, obj
, 0, NULL
, rval
)) goto out
;
1526 if(PR_Close(handle
)!=PR_SUCCESS
){
1527 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1528 JSFILEMSG_OP_FAILED
, "close", dest
);
1535 if(file
->isOpen
&& !fileInitiallyOpen
){
1536 if(PR_Close(file
->handle
)!=PR_SUCCESS
){
1537 JS_ReportWarning(cx
, "Can't close %s, proceeding", file
->path
);
1541 if(handle
&& PR_Close(handle
)!=PR_SUCCESS
){
1542 JS_ReportWarning(cx
, "Can't close %s, proceeding", dest
);
1545 *rval
= JSVAL_FALSE
;
1550 file_renameTo(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1552 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1555 SECURITY_CHECK(cx
, NULL
, "renameTo", file
); /* may need a second argument!*/
1556 JSFILE_CHECK_ONE_ARG("renameTo");
1557 JSFILE_CHECK_NATIVE("renameTo");
1558 JSFILE_CHECK_CLOSED("renameTo");
1560 dest
= RESOLVE_PATH(cx
, JS_GetStringBytes(JS_ValueToString(cx
, argv
[0])));
1562 if (PR_Rename(file
->path
, dest
)==PR_SUCCESS
){
1563 /* copy the new filename */
1564 JS_free(cx
, file
->path
);
1569 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1570 JSFILEMSG_RENAME_FAILED
, file
->path
, dest
);
1574 *rval
= JSVAL_FALSE
;
1579 file_flush(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1581 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1583 SECURITY_CHECK(cx
, NULL
, "flush", file
);
1584 JSFILE_CHECK_NATIVE("flush");
1585 JSFILE_CHECK_OPEN("flush");
1587 if (PR_Sync(file
->handle
)==PR_SUCCESS
){
1591 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1592 JSFILEMSG_OP_FAILED
, "flush", file
->path
);
1596 *rval
= JSVAL_FALSE
;
1601 file_write(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1603 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1608 SECURITY_CHECK(cx
, NULL
, "write", file
);
1611 for (i
= 0; i
<argc
; i
++) {
1612 str
= JS_ValueToString(cx
, argv
[i
]);
1613 count
= js_FileWrite(cx
, file
, JS_GetStringChars(str
),
1614 JS_GetStringLength(str
), file
->type
);
1616 *rval
= JSVAL_FALSE
;
1624 *rval
= JSVAL_FALSE
;
1629 file_writeln(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1631 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1634 SECURITY_CHECK(cx
, NULL
, "writeln", file
);
1637 /* don't report an error here */
1638 if(!file_write(cx
, obj
, argc
, argv
, rval
)) return JS_FALSE
;
1639 /* don't do security here -- we passed the check in file_write */
1640 str
= JS_NewStringCopyZ(cx
, "\n");
1642 if (js_FileWrite(cx
, file
, JS_GetStringChars(str
), JS_GetStringLength(str
),
1644 *rval
= JSVAL_FALSE
;
1648 /* eol causes flush if hasAutoflush is turned on */
1649 if (file
->hasAutoflush
)
1650 file_flush(cx
, obj
, 0, NULL
, rval
);
1655 *rval
= JSVAL_FALSE
;
1660 file_writeAll(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1662 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1669 SECURITY_CHECK(cx
, NULL
, "writeAll", file
);
1670 JSFILE_CHECK_ONE_ARG("writeAll");
1673 if (!JS_IsArrayObject(cx
, JSVAL_TO_OBJECT(argv
[0]))) {
1674 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1675 JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR
);
1679 array
= JSVAL_TO_OBJECT(argv
[0]);
1681 JS_GetArrayLength(cx
, array
, &limit
);
1683 for (i
= 0; i
<limit
; i
++) {
1684 if (!JS_GetElement(cx
, array
, i
, &elemval
)) return JS_FALSE
;
1685 elem
= JSVAL_TO_OBJECT(elemval
);
1686 file_writeln(cx
, obj
, 1, &elemval
, rval
);
1692 *rval
= JSVAL_FALSE
;
1697 file_read(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1699 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1704 SECURITY_CHECK(cx
, NULL
, "read", file
);
1705 JSFILE_CHECK_ONE_ARG("read");
1708 if (!JS_ValueToInt32(cx
, argv
[0], &want
)){
1709 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1710 JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER
, "read", argv
[0]);
1714 /* want = (want>262144)?262144:want; * arbitrary size limitation */
1716 buf
= JS_malloc(cx
, want
*sizeof buf
[0]);
1719 count
= js_FileRead(cx
, file
, buf
, want
, file
->type
);
1721 str
= JS_NewUCStringCopyN(cx
, buf
, count
);
1722 *rval
= STRING_TO_JSVAL(str
);
1730 *rval
= JSVAL_FALSE
;
1735 file_readln(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1737 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1739 jschar
*buf
= NULL
, *tmp
;
1744 SECURITY_CHECK(cx
, NULL
, "readln", file
);
1747 buf
= JS_malloc(cx
, MAX_LINE_LENGTH
* sizeof data
);
1751 room
= MAX_LINE_LENGTH
- 1;
1755 read
= js_FileRead(cx
, file
, &data
, 1, file
->type
);
1763 read
= js_FileRead(cx
, file
, &data2
, 1, file
->type
);
1767 if (read
== 1 && data2
!= '\n') {
1768 /* We read one char too far. Buffer it. */
1769 file
->charBuffer
= data2
;
1770 file
->charBufferUsed
= JS_TRUE
;
1779 tmp
= JS_realloc(cx
, buf
,
1780 (offset
+ MAX_LINE_LENGTH
) * sizeof data
);
1784 room
= MAX_LINE_LENGTH
- 1;
1788 buf
[offset
++] = data
;
1801 tmp
= JS_realloc(cx
, buf
, (offset
+ 1) * sizeof data
);
1805 str
= JS_NewUCString(cx
, tmp
, offset
);
1809 *rval
= STRING_TO_JSVAL(str
);
1820 file_readAll(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1822 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1826 JSBool lineok
= JS_FALSE
;
1828 SECURITY_CHECK(cx
, NULL
, "readAll", file
);
1831 array
= JS_NewArrayObject(cx
, 0, NULL
);
1834 *rval
= OBJECT_TO_JSVAL(array
);
1838 lineok
= file_readln(cx
, obj
, 0, NULL
, &line
);
1839 while (lineok
&& !JSVAL_IS_NULL(line
)) {
1840 JS_SetElement(cx
, array
, len
++, &line
);
1841 lineok
= file_readln(cx
, obj
, 0, NULL
, &line
);
1849 file_seek(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1851 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1855 SECURITY_CHECK(cx
, NULL
, "seek", file
);
1856 JSFILE_CHECK_ONE_ARG("seek");
1857 JSFILE_CHECK_NATIVE("seek");
1860 if (!JS_ValueToInt32(cx
, argv
[0], &toskip
)){
1861 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1862 JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER
, "seek", argv
[0]);
1866 if(!file
->hasRandomAccess
){
1867 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1868 JSFILEMSG_NO_RANDOM_ACCESS
, file
->path
);
1872 if(js_isDirectory(cx
, file
)){
1873 JS_ReportWarning(cx
,"Seek on directories is not supported, proceeding");
1877 pos
= js_FileSeek(cx
, file
, toskip
, file
->type
);
1880 *rval
= INT_TO_JSVAL(pos
);
1889 file_list(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1893 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1898 JSRegExp
*re
= NULL
;
1899 JSFunction
*func
= NULL
;
1904 SECURITY_CHECK(cx
, NULL
, "list", file
);
1905 JSFILE_CHECK_NATIVE("list");
1908 if (VALUE_IS_REGEXP(cx
, argv
[0])) {
1909 re
= JS_GetPrivate(cx
, JSVAL_TO_OBJECT(argv
[0]));
1911 if (VALUE_IS_FUNCTION(cx
, argv
[0])) {
1912 func
= JS_GetPrivate(cx
, JSVAL_TO_OBJECT(argv
[0]));
1914 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1915 JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX
, argv
[0]);
1920 if (!js_isDirectory(cx
, file
)) {
1921 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1922 JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE
, file
->path
);
1926 dir
= PR_OpenDir(file
->path
);
1928 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1929 JSFILEMSG_OP_FAILED
, "open", file
->path
);
1933 /* create JSArray here... */
1934 array
= JS_NewArrayObject(cx
, 0, NULL
);
1937 while ((entry
= PR_ReadDir(dir
, PR_SKIP_BOTH
))!=NULL
) {
1938 /* first, check if we have a regexp */
1942 str
= JS_NewStringCopyZ(cx
, entry
->name
);
1943 if(!js_ExecuteRegExp(cx
, re
, str
, &index
, JS_TRUE
, &v
)){
1944 /* don't report anything here */
1948 if (JSVAL_IS_NULL(v
)) {
1953 str
= JS_NewStringCopyZ(cx
, entry
->name
);
1954 args
[0] = STRING_TO_JSVAL(str
);
1955 if(!JS_CallFunction(cx
, obj
, func
, 1, args
, &v
)){
1959 if (v
==JSVAL_FALSE
) {
1964 filePath
= js_combinePath(cx
, file
->path
, (char*)entry
->name
);
1966 eachFile
= js_NewFileObject(cx
, filePath
);
1967 JS_free(cx
, filePath
);
1969 JS_ReportWarning(cx
, "File %s cannot be retrieved", filePath
);
1972 v
= OBJECT_TO_JSVAL(eachFile
);
1973 JS_SetElement(cx
, array
, len
, &v
);
1974 JS_SetProperty(cx
, array
, entry
->name
, &v
);
1978 if(PR_CloseDir(dir
)!=PR_SUCCESS
){
1979 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
1980 JSFILEMSG_OP_FAILED
, "close", file
->path
);
1983 *rval
= OBJECT_TO_JSVAL(array
);
1991 file_mkdir(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
1993 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
1995 SECURITY_CHECK(cx
, NULL
, "mkdir", file
);
1996 JSFILE_CHECK_ONE_ARG("mkdir");
1997 JSFILE_CHECK_NATIVE("mkdir");
1999 /* if the current file is not a directory, find out the directory name */
2000 if (!js_isDirectory(cx
, file
)) {
2001 char *dir
= js_fileDirectoryName(cx
, file
->path
);
2002 JSObject
*dirObj
= js_NewFileObject(cx
, dir
);
2006 /* call file_mkdir with the right set of parameters if needed */
2007 if (file_mkdir(cx
, dirObj
, argc
, argv
, rval
))
2012 char *dirName
= JS_GetStringBytes(JS_ValueToString(cx
, argv
[0]));
2015 fullName
= js_combinePath(cx
, file
->path
, dirName
);
2016 if (PR_MkDir(fullName
, 0755)==PR_SUCCESS
){
2018 JS_free(cx
, fullName
);
2021 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2022 JSFILEMSG_OP_FAILED
, "mkdir", fullName
);
2023 JS_free(cx
, fullName
);
2028 *rval
= JSVAL_FALSE
;
2033 file_toString(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2035 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
2038 str
= JS_NewStringCopyZ(cx
, file
->path
);
2041 *rval
= STRING_TO_JSVAL(str
);
2046 file_toURL(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
2048 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
2049 char url
[MAX_PATH_LENGTH
];
2054 JSFILE_CHECK_NATIVE("toURL");
2056 sprintf(url
, "file://%s", file
->path
);
2059 urlChars
= js_InflateString(cx
, url
, &len
);
2062 str
= js_NewString(cx
, urlChars
, len
);
2064 JS_free(cx
, urlChars
);
2067 *rval
= STRING_TO_JSVAL(str
);
2069 /* TODO: js_escape in jsstr.h may go away at some point */
2070 return js_str_escape(cx
, obj
, 0, rval
, rval
);
2079 file_finalize(JSContext
*cx
, JSObject
*obj
)
2081 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
2084 /* Close the file before exiting. */
2085 if(file
->isOpen
&& !file
->isNative
) {
2087 file_close(cx
, obj
, 0, NULL
, &vp
);
2091 JS_free(cx
, file
->path
);
2098 Allocates memory for the file object, sets fields to defaults.
2101 file_init(JSContext
*cx
, JSObject
*obj
, char *bytes
)
2105 file
= JS_malloc(cx
, sizeof *file
);
2108 memset(file
, 0 , sizeof *file
);
2110 js_ResetAttributes(file
);
2112 file
->path
= RESOLVE_PATH(cx
, bytes
);
2114 if (!JS_SetPrivate(cx
, obj
, file
)) {
2115 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2116 JSFILEMSG_CANNOT_SET_PRIVATE_FILE
, file
->path
);
2124 /* Returns a JSObject. This function is globally visible */
2125 JS_PUBLIC_API(JSObject
*)
2126 js_NewFileObject(JSContext
*cx
, char *filename
)
2131 obj
= JS_NewObject(cx
, &js_FileClass
, NULL
, NULL
);
2133 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2134 JSFILEMSG_OBJECT_CREATION_FAILED
, "js_NewFileObject");
2137 file
= file_init(cx
, obj
, filename
);
2138 if(!file
) return NULL
;
2142 /* Internal function, used for cases which NSPR file support doesn't cover */
2144 js_NewFileObjectFromFILE(JSContext
*cx
, FILE *nativehandle
, char *filename
,
2145 int32 mode
, JSBool open
, JSBool randomAccess
)
2150 obj
= JS_NewObject(cx
, &js_FileClass
, NULL
, NULL
);
2152 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2153 JSFILEMSG_OBJECT_CREATION_FAILED
, "js_NewFileObjectFromFILE");
2156 file
= file_init(cx
, obj
, filename
);
2157 if(!file
) return NULL
;
2159 file
->nativehandle
= nativehandle
;
2161 /* free result of RESOLVE_PATH from file_init. */
2162 JS_ASSERT(file
->path
!= NULL
);
2163 JS_free(cx
, file
->path
);
2165 file
->path
= strdup(filename
);
2166 file
->isOpen
= open
;
2168 file
->hasRandomAccess
= randomAccess
;
2169 file
->isNative
= JS_TRUE
;
2174 Real file constructor that is called from JavaScript.
2175 Basically, does error processing and calls file_init.
2178 file_constructor(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
,
2184 if (!JS_IsConstructing(cx
)) {
2185 /* Replace obj with a new File object. */
2186 obj
= JS_NewObject(cx
, &js_FileClass
, NULL
, NULL
);
2189 *rval
= OBJECT_TO_JSVAL(obj
);
2193 ? JS_InternString(cx
, "")
2194 : JS_ValueToString(cx
, argv
[0]);
2197 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2198 JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR
,
2203 file
= file_init(cx
, obj
, JS_GetStringBytes(str
));
2207 SECURITY_CHECK(cx
, NULL
, "constructor", file
);
2212 /* -------------------- File methods and properties ------------------------- */
2213 static JSFunctionSpec file_functions
[] = {
2214 { "open", file_open
, 0},
2215 { "close", file_close
, 0},
2216 { "remove", file_remove
, 0},
2217 { "copyTo", file_copyTo
, 0},
2218 { "renameTo", file_renameTo
, 0},
2219 { "flush", file_flush
, 0},
2220 { "seek", file_seek
, 0},
2221 { "read", file_read
, 0},
2222 { "readln", file_readln
, 0},
2223 { "readAll", file_readAll
, 0},
2224 { "write", file_write
, 0},
2225 { "writeln", file_writeln
, 0},
2226 { "writeAll", file_writeAll
, 0},
2227 { "list", file_list
, 0},
2228 { "mkdir", file_mkdir
, 0},
2229 { "toString", file_toString
, 0},
2230 { "toURL", file_toURL
, 0},
2243 FILE_CANWRITE
= -10,
2248 FILE_MODIFIED
= -15,
2250 FILE_RANDOMACCESS
= -17,
2251 FILE_POSITION
= -18,
2254 FILE_AUTOFLUSH
= -21,
2255 FILE_ISNATIVE
= -22,
2258 static JSPropertySpec file_props
[] = {
2259 {"length", FILE_LENGTH
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2260 {"parent", FILE_PARENT
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2261 {"path", FILE_PATH
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2262 {"name", FILE_NAME
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2263 {"isDirectory", FILE_ISDIR
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2264 {"isFile", FILE_ISFILE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2265 {"exists", FILE_EXISTS
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2266 {"canRead", FILE_CANREAD
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2267 {"canWrite", FILE_CANWRITE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2268 {"canAppend", FILE_APPEND
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2269 {"canReplace", FILE_REPLACE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2270 {"isOpen", FILE_OPEN
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2271 {"type", FILE_TYPE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2272 {"mode", FILE_MODE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2273 {"creationTime", FILE_CREATED
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2274 {"lastModified", FILE_MODIFIED
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2275 {"size", FILE_SIZE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2276 {"hasRandomAccess", FILE_RANDOMACCESS
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2277 {"hasAutoFlush", FILE_AUTOFLUSH
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2278 {"position", FILE_POSITION
, JSPROP_ENUMERATE
},
2279 {"isNative", FILE_ISNATIVE
, JSPROP_ENUMERATE
| JSPROP_READONLY
},
2283 /* ------------------------- Property getter/setter ------------------------- */
2285 file_getProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2287 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
2293 PRExplodedTime expandedTime
;
2295 tiny
= JSVAL_TO_INT(id
);
2301 SECURITY_CHECK(cx
, NULL
, "parent", file
);
2302 if (!js_parent(cx
, file
, vp
))
2306 str
= JS_NewStringCopyZ(cx
, file
->path
);
2309 *vp
= STRING_TO_JSVAL(str
);
2312 if (!js_name(cx
, file
, vp
))
2316 SECURITY_CHECK(cx
, NULL
, "isDirectory", file
);
2317 *vp
= BOOLEAN_TO_JSVAL(js_isDirectory(cx
, file
));
2320 SECURITY_CHECK(cx
, NULL
, "isFile", file
);
2321 *vp
= BOOLEAN_TO_JSVAL(js_isFile(cx
, file
));
2324 SECURITY_CHECK(cx
, NULL
, "exists", file
);
2325 *vp
= BOOLEAN_TO_JSVAL(js_exists(cx
, file
));
2328 SECURITY_CHECK(cx
, NULL
, "isNative", file
);
2329 *vp
= BOOLEAN_TO_JSVAL(file
->isNative
);
2332 SECURITY_CHECK(cx
, NULL
, "canRead", file
);
2333 *vp
= BOOLEAN_TO_JSVAL(js_canRead(cx
, file
));
2336 SECURITY_CHECK(cx
, NULL
, "canWrite", file
);
2337 *vp
= BOOLEAN_TO_JSVAL(js_canWrite(cx
, file
));
2340 SECURITY_CHECK(cx
, NULL
, "isOpen", file
);
2341 *vp
= BOOLEAN_TO_JSVAL(file
->isOpen
);
2344 SECURITY_CHECK(cx
, NULL
, "canAppend", file
);
2345 JSFILE_CHECK_OPEN("canAppend");
2346 *vp
= BOOLEAN_TO_JSVAL(!file
->isNative
&&
2347 (file
->mode
&PR_APPEND
)==PR_APPEND
);
2350 SECURITY_CHECK(cx
, NULL
, "canReplace", file
);
2351 JSFILE_CHECK_OPEN("canReplace");
2352 *vp
= BOOLEAN_TO_JSVAL(!file
->isNative
&&
2353 (file
->mode
&PR_TRUNCATE
)==PR_TRUNCATE
);
2355 case FILE_AUTOFLUSH
:
2356 SECURITY_CHECK(cx
, NULL
, "hasAutoFlush", file
);
2357 JSFILE_CHECK_OPEN("hasAutoFlush");
2358 *vp
= BOOLEAN_TO_JSVAL(!file
->isNative
&& file
->hasAutoflush
);
2361 SECURITY_CHECK(cx
, NULL
, "type", file
);
2362 JSFILE_CHECK_OPEN("type");
2363 if(js_isDirectory(cx
, file
)){
2368 switch (file
->type
) {
2370 *vp
= STRING_TO_JSVAL(JS_NewStringCopyZ(cx
, asciistring
));
2373 *vp
= STRING_TO_JSVAL(JS_NewStringCopyZ(cx
, utfstring
));
2376 *vp
= STRING_TO_JSVAL(JS_NewStringCopyZ(cx
, unicodestring
));
2379 JS_ReportWarning(cx
, "Unsupported file type %d, proceeding",
2384 SECURITY_CHECK(cx
, NULL
, "mode", file
);
2385 JSFILE_CHECK_OPEN("mode");
2386 bytes
= JS_malloc(cx
, MODE_SIZE
);
2390 if ((file
->mode
&PR_RDONLY
)==PR_RDONLY
) {
2391 if (flag
) strcat(bytes
, ",");
2392 strcat(bytes
, "read");
2395 if ((file
->mode
&PR_WRONLY
)==PR_WRONLY
) {
2396 if (flag
) strcat(bytes
, ",");
2397 strcat(bytes
, "write");
2400 if ((file
->mode
&PR_RDWR
)==PR_RDWR
) {
2401 if (flag
) strcat(bytes
, ",");
2402 strcat(bytes
, "readWrite");
2405 if ((file
->mode
&PR_APPEND
)==PR_APPEND
) {
2406 if (flag
) strcat(bytes
, ",");
2407 strcat(bytes
, "append");
2410 if ((file
->mode
&PR_CREATE_FILE
)==PR_CREATE_FILE
) {
2411 if (flag
) strcat(bytes
, ",");
2412 strcat(bytes
, "create");
2415 if ((file
->mode
&PR_TRUNCATE
)==PR_TRUNCATE
) {
2416 if (flag
) strcat(bytes
, ",");
2417 strcat(bytes
, "replace");
2420 if (file
->hasAutoflush
) {
2421 if (flag
) strcat(bytes
, ",");
2422 strcat(bytes
, "hasAutoFlush");
2425 *vp
= STRING_TO_JSVAL(JS_NewStringCopyZ(cx
, bytes
));
2429 SECURITY_CHECK(cx
, NULL
, "creationTime", file
);
2430 JSFILE_CHECK_NATIVE("creationTime");
2432 PR_GetOpenFileInfo(file
->handle
, &info
):
2433 PR_GetFileInfo(file
->path
, &info
))!=PR_SUCCESS
){
2434 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2435 JSFILEMSG_CANNOT_ACCESS_FILE_STATUS
, file
->path
);
2439 PR_ExplodeTime(info
.creationTime
, PR_LocalTimeParameters
,&expandedTime
);
2440 *vp
= OBJECT_TO_JSVAL(js_NewDateObject(cx
, expandedTime
.tm_year
,
2441 expandedTime
.tm_month
,
2442 expandedTime
.tm_mday
,
2443 expandedTime
.tm_hour
,
2444 expandedTime
.tm_min
,
2445 expandedTime
.tm_sec
));
2448 SECURITY_CHECK(cx
, NULL
, "lastModified", file
);
2449 JSFILE_CHECK_NATIVE("lastModified");
2451 PR_GetOpenFileInfo(file
->handle
, &info
):
2452 PR_GetFileInfo(file
->path
, &info
))!=PR_SUCCESS
){
2453 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2454 JSFILEMSG_CANNOT_ACCESS_FILE_STATUS
, file
->path
);
2458 PR_ExplodeTime(info
.modifyTime
, PR_LocalTimeParameters
, &expandedTime
);
2459 *vp
= OBJECT_TO_JSVAL(js_NewDateObject(cx
, expandedTime
.tm_year
,
2460 expandedTime
.tm_month
,
2461 expandedTime
.tm_mday
,
2462 expandedTime
.tm_hour
,
2463 expandedTime
.tm_min
,
2464 expandedTime
.tm_sec
));
2467 SECURITY_CHECK(cx
, NULL
, "size", file
);
2468 *vp
= js_size(cx
, file
);
2471 SECURITY_CHECK(cx
, NULL
, "length", file
);
2472 JSFILE_CHECK_NATIVE("length");
2474 if (js_isDirectory(cx
, file
)) { /* XXX debug me */
2479 if(!(dir
= PR_OpenDir(file
->path
))){
2480 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2481 JSFILEMSG_CANNOT_OPEN_DIR
, file
->path
);
2485 while ((entry
= PR_ReadDir(dir
, PR_SKIP_BOTH
))) {
2489 if(!PR_CloseDir(dir
)){
2490 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2491 JSFILEMSG_OP_FAILED
, "close", file
->path
);
2496 *vp
= INT_TO_JSVAL(count
);
2499 /* return file size */
2500 *vp
= js_size(cx
, file
);
2503 case FILE_RANDOMACCESS
:
2504 SECURITY_CHECK(cx
, NULL
, "hasRandomAccess", file
);
2505 JSFILE_CHECK_OPEN("hasRandomAccess");
2506 *vp
= BOOLEAN_TO_JSVAL(file
->hasRandomAccess
);
2509 SECURITY_CHECK(cx
, NULL
, "position", file
);
2510 JSFILE_CHECK_NATIVE("position");
2511 JSFILE_CHECK_OPEN("position");
2513 if(!file
->hasRandomAccess
){
2514 JS_ReportWarning(cx
, "File %s doesn't support random access, can't report the position, proceeding");
2519 if (file
->isOpen
&& js_isFile(cx
, file
)) {
2520 int pos
= PR_Seek(file
->handle
, 0, PR_SEEK_CUR
);
2522 *vp
= INT_TO_JSVAL(pos
);
2524 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2525 JSFILEMSG_CANNOT_REPORT_POSITION
, file
->path
);
2529 JS_ReportWarning(cx
, "File %s is closed or not a plain file,"
2530 " can't report position, proceeding");
2535 SECURITY_CHECK(cx
, NULL
, "file_access", file
);
2537 /* this is some other property -- try to use the dir["file"] syntax */
2538 if (js_isDirectory(cx
, file
)) {
2540 PRDirEntry
*entry
= NULL
;
2543 str
= JS_ValueToString(cx
, id
);
2547 prop_name
= JS_GetStringBytes(str
);
2549 /* no native files past this point */
2550 dir
= PR_OpenDir(file
->path
);
2552 /* This is probably not a directory */
2553 JS_ReportWarning(cx
, "Can't open directory %s", file
->path
);
2557 while ((entry
= PR_ReadDir(dir
, PR_SKIP_NONE
)) != NULL
) {
2558 if (!strcmp(entry
->name
, prop_name
)){
2559 bytes
= js_combinePath(cx
, file
->path
, prop_name
);
2560 *vp
= OBJECT_TO_JSVAL(js_NewFileObject(cx
, bytes
));
2563 return !JSVAL_IS_NULL(*vp
);
2576 file_setProperty(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2578 JSFile
*file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
2581 if (JSVAL_IS_STRING(id
)){
2585 slot
= JSVAL_TO_INT(id
);
2588 /* File.position = 10 */
2590 SECURITY_CHECK(cx
, NULL
, "set_position", file
);
2591 JSFILE_CHECK_NATIVE("set_position");
2593 if(!file
->hasRandomAccess
){
2594 JS_ReportWarning(cx
, "File %s doesn't support random access, can't "
2595 "report the position, proceeding");
2599 if (file
->isOpen
&& js_isFile(cx
, file
)) {
2603 if (!JS_ValueToInt32(cx
, *vp
, &offset
)){
2604 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2605 JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER
, "position", *vp
);
2609 pos
= PR_Seek(file
->handle
, offset
, PR_SEEK_SET
);
2612 *vp
= INT_TO_JSVAL(pos
);
2614 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2615 JSFILEMSG_CANNOT_SET_POSITION
, file
->path
);
2619 JS_ReportWarning(cx
, "File %s is closed or not a file, can't set "
2620 "position, proceeding", file
->path
);
2631 File.currentDir = new File("D:\") or File.currentDir = "D:\"
2634 file_currentDirSetter(JSContext
*cx
, JSObject
*obj
, jsval id
, jsval
*vp
)
2638 file
= JS_GetInstancePrivate(cx
, obj
, &js_FileClass
, NULL
);
2640 /* Look at the rhs and extract a file object from it */
2641 if (JSVAL_IS_OBJECT(*vp
)) {
2642 if (JS_InstanceOf(cx
, obj
, &js_FileClass
, NULL
)) {
2643 /* Braindamaged rhs -- just return the old value */
2644 if (file
&& (!js_exists(cx
, file
) || !js_isDirectory(cx
, file
))) {
2645 JS_GetProperty(cx
, obj
, CURRENTDIR_PROPERTY
, vp
);
2655 JSObject
*rhsObject
;
2658 path
= JS_GetStringBytes(JS_ValueToString(cx
, *vp
));
2659 rhsObject
= js_NewFileObject(cx
, path
);
2663 if (!file
|| !js_exists(cx
, file
) || !js_isDirectory(cx
, file
)){
2664 JS_GetProperty(cx
, obj
, CURRENTDIR_PROPERTY
, vp
);
2666 *vp
= OBJECT_TO_JSVAL(rhsObject
);
2675 JSClass js_FileClass
= {
2676 "File", JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_CACHED_PROTO(JSProto_File
),
2677 JS_PropertyStub
, JS_PropertyStub
, file_getProperty
, file_setProperty
,
2678 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, file_finalize
2681 /* -------------------- Functions exposed to the outside -------------------- */
2682 JS_PUBLIC_API(JSObject
*)
2683 js_InitFileClass(JSContext
*cx
, JSObject
* obj
)
2685 JSObject
*file
, *ctor
, *afile
;
2690 file
= JS_InitClass(cx
, obj
, NULL
, &js_FileClass
, file_constructor
, 1,
2691 file_props
, file_functions
, NULL
, NULL
);
2693 JS_ReportErrorNumber(cx
, JSFile_GetErrorMessage
, NULL
,
2694 JSFILEMSG_INIT_FAILED
);
2698 ctor
= JS_GetConstructor(cx
, file
);
2699 if (!ctor
) return NULL
;
2701 /* Define CURRENTDIR property. We are doing this to get a
2702 slash at the end of the current dir */
2703 afile
= js_NewFileObject(cx
, CURRENT_DIR
);
2704 currentdir
= JS_malloc(cx
, MAX_PATH_LENGTH
);
2705 currentdir
= getcwd(currentdir
, MAX_PATH_LENGTH
);
2706 afile
= js_NewFileObject(cx
, currentdir
);
2707 JS_free(cx
, currentdir
);
2708 vp
= OBJECT_TO_JSVAL(afile
);
2709 JS_DefinePropertyWithTinyId(cx
, ctor
, CURRENTDIR_PROPERTY
, 0, vp
,
2710 JS_PropertyStub
, file_currentDirSetter
,
2711 JSPROP_ENUMERATE
| JSPROP_READONLY
);
2714 vp
= OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx
, stdin
,
2715 STDINPUT_NAME
, PR_RDONLY
, JS_TRUE
, JS_FALSE
));
2716 JS_SetProperty(cx
, ctor
, "input", &vp
);
2719 vp
= OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx
, stdout
,
2720 STDOUTPUT_NAME
, PR_WRONLY
, JS_TRUE
, JS_FALSE
));
2721 JS_SetProperty(cx
, ctor
, "output", &vp
);
2724 vp
= OBJECT_TO_JSVAL(js_NewFileObjectFromFILE(cx
, stderr
,
2725 STDERROR_NAME
, PR_WRONLY
, JS_TRUE
, JS_FALSE
));
2726 JS_SetProperty(cx
, ctor
, "error", &vp
);
2728 separator
[0] = FILESEPARATOR
;
2729 separator
[1] = '\0';
2730 vp
= STRING_TO_JSVAL(JS_NewStringCopyZ(cx
, separator
));
2731 JS_DefinePropertyWithTinyId(cx
, ctor
, SEPARATOR_PROPERTY
, 0, vp
,
2732 JS_PropertyStub
, JS_PropertyStub
,
2733 JSPROP_ENUMERATE
| JSPROP_READONLY
);
2736 #endif /* JS_HAS_FILE_OBJECT */