js_file.c 29.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* js_file.c */

/* Synchronet JavaScript "File" Object */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright 2001 Rob Swindell - http://www.synchro.net/copyright.html		*
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
39
40
#include "md5.h"
#include "base64.h"
41
#include "uucode.h"
42
43
44
45
46

#ifdef JAVASCRIPT

typedef struct
{
47
	FILE*	fp;
48
49
	char	name[MAX_PATH+1];
	char	mode[4];
50
	uchar	etx;
51
52
	BOOL	external;	/* externally created, don't close */
	BOOL	debug;
53
	BOOL	uuencoded;
54
55
	BOOL	b64encoded;
	BOOL	network_byte_order;
56
57
58

} private_t;

59
static const char* getprivate_failure = "line %d %s JS_GetPrivate failed";
60
61
62
63
64
65
66
67
68
69

static void dbprintf(BOOL error, private_t* p, char* fmt, ...)
{
	va_list argptr;
	char sbuf[1024];

	if(p==NULL || (!p->debug && !error))
		return;

    va_start(argptr,fmt);
70
71
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
72
73
    va_end(argptr);
	
74
	lprintf("%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
75
76
}

77
78
79
80
81
82
83
84
/* Converts fopen() style 'mode' string into open() style 'flags' integer */

static int fopenflags(char *mode)
{
	int flags=0;

	if(strchr(mode,'b'))
		flags|=O_BINARY;
85
86
	else
		flags|=O_TEXT;
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

	if(strchr(mode,'w')) {
		flags|=O_CREAT|O_TRUNC;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'a')) {
		flags|=O_CREAT|O_APPEND;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'r')) {
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_RDONLY;
	}

	return(flags);
}
115
116
117
118
119
120
121

/* File Object Methods */

static JSBool
js_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		mode="w+";	/* default mode */
122
123
	BOOL		shareable=FALSE;
	int			file;
124
	uintN		i;
125
	jsint		bufsize=2*1024;
126
127
128
	JSString*	str;
	private_t*	p;

129
	*rval = JSVAL_FALSE;
130

131
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
132
		JS_ReportError(cx,getprivate_failure,WHERE);
133
		return(JS_FALSE);
134
	}
135
136
137

	if(p->fp!=NULL)  
		return(JS_TRUE);
138
139
140
141

	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
142
143
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
144
145
			}
			mode=JS_GetStringBytes(str);
146
147
148
		} else if(JSVAL_IS_BOOLEAN(argv[i]))	/* shareable */
			shareable=JSVAL_TO_BOOLEAN(argv[i]);
		else	/* bufsize */
149
			JS_ValueToInt32(cx,argv[i],&bufsize);
150
	}
151
	SAFECOPY(p->mode,mode);
152

153
154
155
156
157
158
159
160
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
			if((p->fp=fdopen(file,p->mode))==NULL)
				close(file);
		}
	}
161
	if(p->fp!=NULL) {
162
		*rval = JSVAL_TRUE;
163
		dbprintf(FALSE, p, "opened: %s",p->name);
164
165
166
167
168
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
169
170
171
172
173
174
175
176
177
178

	return(JS_TRUE);
}


static JSBool
js_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

179
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
180
		JS_ReportError(cx,getprivate_failure,WHERE);
181
		return(JS_FALSE);
182
	}
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

	*rval = JSVAL_VOID;

	if(p->fp==NULL)
		return(JS_TRUE);

	fclose(p->fp);

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 

	return(JS_TRUE);
}

static JSBool
199
js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
200
201
{
	char*		cp;
202
	char*		buf;
203
	char*		uubuf;
204
205
	int32		len;
	int32		offset;
206
	int32		uulen;
207
208
209
	JSString*	str;
	private_t*	p;

210
211
	*rval = JSVAL_NULL;

212
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
213
		JS_ReportError(cx,getprivate_failure,WHERE);
214
		return(JS_FALSE);
215
	}
216

217
218
	if(p->fp==NULL)
		return(JS_TRUE);
219

220
	if(argc)
221
		JS_ValueToInt32(cx,argv[0],&len);
222
223
224
225
226
227
228
229
	else {
		len=filelength(fileno(p->fp));
		offset=ftell(p->fp);
		if(offset>0)
			len-=offset;
	}
	if(len<0)
		len=512;
230

231
232
233
234
235
236
237
238
239
240
241
242
243
	if((buf=malloc(len+1))==NULL)
		return(JS_TRUE);

	len = fread(buf,1,len,p->fp);
	if(len<0) 
		len=0;
	buf[len]=0;

	if(p->etx) {
		cp=strchr(buf,p->etx);
		if(cp) *cp=0; 
	}

244
	if(p->uuencoded || p->b64encoded) {
245
246
247
		uulen=len*2;
		if((uubuf=malloc(uulen))==NULL)
			return(JS_TRUE);
248
249
250
251
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
252
253
254
255
256
257
258
		if(uulen>=0) {
			free(buf);
			buf=uubuf;
		} else
			free(uubuf);
	}

259
260
261
262
	str = JS_NewStringCopyZ(cx, buf);

	free(buf);

263
264
265
	if(str==NULL)
		return(JS_FALSE);

266
267
268
	*rval = STRING_TO_JSVAL(str);

	dbprintf(FALSE, p, "read %u bytes",len);
269
270
271
272
273
		
	return(JS_TRUE);
}

static JSBool
274
js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
275
{
276
277
	char*		cp;
	char*		buf;
278
	int32		len=512;
279
	JSString*	js_str;
280
281
	private_t*	p;

282
	*rval = JSVAL_NULL;
283

284
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
285
		JS_ReportError(cx,getprivate_failure,WHERE);
286
		return(JS_FALSE);
287
	}
288
289
290

	if(p->fp==NULL)
		return(JS_TRUE);
291
292
	
	if(argc)
293
		JS_ValueToInt32(cx,argv[0],&len);
294

295
296
297
298
	if((buf=malloc(len))==NULL)
		return(JS_TRUE);

	if(fgets(buf,len,p->fp)!=NULL) {
299
300
301
302
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
303
304
305
306
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
307
308
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)
			*rval = STRING_TO_JSVAL(js_str);
309
310
	}

311
312
	free(buf);

313
314
315
316
	return(JS_TRUE);
}

static JSBool
317
js_readbin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
318
319
320
321
322
323
324
{
	BYTE		b;
	WORD		w;
	DWORD		l;
	size_t		size=sizeof(DWORD);
	private_t*	p;

325
	*rval = INT_TO_JSVAL(-1);
326

327
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
328
		JS_ReportError(cx,getprivate_failure,WHERE);
329
		return(JS_FALSE);
330
	}
331
332
333
334

	if(p->fp==NULL)
		return(JS_TRUE);

335
	if(argc) 
336
		JS_ValueToInt32(cx,argv[0],(int32*)&size);
337
338
339

	switch(size) {
		case sizeof(BYTE):
340
341
			if(fread(&b,1,size,p->fp)==size)
				*rval = INT_TO_JSVAL(b);
342
343
			break;
		case sizeof(WORD):
344
345
346
			if(fread(&w,1,size,p->fp)==size) {
				if(p->network_byte_order)
					w=ntohs(w);
347
				*rval = INT_TO_JSVAL(w);
348
			}
349
350
			break;
		case sizeof(DWORD):
351
352
353
			if(fread(&l,1,size,p->fp)==size) {
				if(p->network_byte_order)
					l=ntohl(l);
354
				JS_NewNumberValue(cx,l,rval);
355
			}
356
357
358
359
360
361
362
			break;
	}
		
	return(JS_TRUE);
}

static JSBool
363
js_readall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
364
{
365
366
367
    jsint       len=0;
    jsval       line;
    JSObject*	array;
368
369
	private_t*	p;

370
371
	*rval = JSVAL_NULL;

372
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
373
		JS_ReportError(cx,getprivate_failure,WHERE);
374
		return(JS_FALSE);
375
	}
376

377
378
	if(p->fp==NULL)
		return(JS_TRUE);
379

380
    array = JS_NewArrayObject(cx, 0, NULL);
381

382
383
384
385
    while(!feof(p->fp)) {
		js_readln(cx, obj, 0, NULL, &line); 
		if(line==JSVAL_NULL)
			break;
386
387
        if(!JS_SetElement(cx, array, len++, &line))
			break;
388
	}
389
    *rval = OBJECT_TO_JSVAL(array);
390

391
392
    return(JS_TRUE);
}
393

394
395
396
397
static JSBool
js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		cp;
398
399
400
	char*		uubuf=NULL;
	int			len;	/* string length */
	int			tlen;	/* total length to write (may be greater than len) */
401
	private_t*	p;
402

403
	*rval = JSVAL_FALSE;
404

405
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
406
		JS_ReportError(cx,getprivate_failure,WHERE);
407
		return(JS_FALSE);
408
	}
409
410
411
412

	if(p->fp==NULL)
		return(JS_TRUE);

413
414
415
	cp=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
	len=strlen(cp);

416
417
418
419
420
421
	if((p->uuencoded || p->b64encoded)
		&& len && (uubuf=malloc(len))!=NULL) {
		if(p->uuencoded)
			len=uudecode(uubuf,len,cp,len);
		else
			len=b64_decode(uubuf,len,cp,len);
422
423
424
425
426
427
428
429
		if(len<0) {
			free(uubuf);
			return(JS_TRUE);
		}
		cp=uubuf;
	}

	tlen=len;
430
	if(argc>1) {
431
		JS_ValueToInt32(cx,argv[1],(int32*)&tlen);
432
433
434
		if(len>tlen)
			len=tlen;
	}
435
436

	if(fwrite(cp,1,len,p->fp)==(size_t)len) {
437
438
439
440
441
442
443
444
445
446
447
		if(tlen>len) {
			len=tlen-len;
			if((cp=malloc(len))==NULL) {
				dbprintf(TRUE, p, "malloc failure of %u bytes", len);
				return(JS_TRUE);
			}
			memset(cp,p->etx,len);
			fwrite(cp,1,len,p->fp);
			free(cp);
		}
		dbprintf(FALSE, p, "wrote %u bytes",tlen);
448
		*rval = JSVAL_TRUE;
449
450
	} else 
		dbprintf(TRUE, p, "write of %u bytes failed",len);
451
		
452
453
454
	if(uubuf!=NULL)
		free(uubuf);

455
456
457
458
	return(JS_TRUE);
}

static JSBool
459
js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
460
{
461
462
463
464
	char*		cp="";
	JSString*	str;
	private_t*	p;

465
	*rval = JSVAL_FALSE;
466

467
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
468
		JS_ReportError(cx,getprivate_failure,WHERE);
469
		return(JS_FALSE);
470
	}
471
472
473
474
475

	if(p->fp==NULL)
		return(JS_TRUE);

	if(argc) {
476
477
		if((str = JS_ValueToString(cx, argv[0]))==NULL) {
			JS_ReportError(cx,"JS_ValueToString failed");
478
			return(JS_FALSE);
479
		}
480
481
482
483
		cp = JS_GetStringBytes(str);
	}

	if(fprintf(p->fp,"%s\n",cp)!=0)
484
		*rval = JSVAL_TRUE;
485

486
487
	return(JS_TRUE);
}
488

489
static JSBool
490
js_writebin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
491
{
492
493
494
	BYTE		b;
	WORD		w;
	DWORD		l;
495
	int32		val=0;
496
	size_t		wr=0;
497
	size_t		size=sizeof(DWORD);
498
499
	private_t*	p;

500
	*rval = JSVAL_FALSE;
501

502
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
503
		JS_ReportError(cx,getprivate_failure,WHERE);
504
		return(JS_FALSE);
505
	}
506

507
508
	if(p->fp==NULL)
		return(JS_TRUE);
509

510
	JS_ValueToInt32(cx,argv[0],&val);
511
	if(argc>1) 
512
		JS_ValueToInt32(cx,argv[1],(int32*)&size);
513

514
515
	switch(size) {
		case sizeof(BYTE):
516
			b = (BYTE)val;
517
			wr=fwrite(&b,1,size,p->fp);
518
519
			break;
		case sizeof(WORD):
520
			w = (WORD)val;
521
522
			if(p->network_byte_order)
				w=htons(w);
523
			wr=fwrite(&w,1,size,p->fp);
524
525
			break;
		case sizeof(DWORD):
526
			l = val;
527
528
			if(p->network_byte_order)
				l=htonl(l);
529
530
531
532
533
			wr=fwrite(&l,1,size,p->fp);
			break;
		default:	
			/* unknown size */
			dbprintf(TRUE, p, "unsupported binary write size: %d",size);
534
535
			break;
	}
536
	if(wr==size)
537
		*rval = JSVAL_TRUE;
538
		
539
540
541
	return(JS_TRUE);
}

542
543
544
545
546
547
548
549
550
static JSBool
js_writeall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    jsuint      i;
    jsuint      limit;
    JSObject*	array;
    jsval       elemval;
	private_t*	p;

551
	*rval = JSVAL_FALSE;
552

553
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
554
		JS_ReportError(cx,getprivate_failure,WHERE);
555
		return(JS_FALSE);
556
	}
557
558
559
560

	if(p->fp==NULL)
		return(JS_TRUE);

561
	if(!JSVAL_IS_OBJECT(argv[0]))
562
563
564
565
		return(JS_TRUE);

    array = JSVAL_TO_OBJECT(argv[0]);

566
567
568
    if(!JS_IsArrayObject(cx, array))
		return(JS_TRUE);

569
570
    if(!JS_GetArrayLength(cx, array, &limit))
		return(JS_FALSE);
571

572
    *rval = JSVAL_TRUE;
573

574
575
576
577
    for(i=0;i<limit;i++) {
        if(!JS_GetElement(cx, array, i, &elemval))
			break;
        js_writeln(cx, obj, 1, &elemval, rval);
578
		if(*rval!=JSVAL_TRUE)
579
			break;
580
581
582
583
584
    }

    return(JS_TRUE);
}

585
static JSBool
586
js_lock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
587
{
588
589
	int32		offset=0;
	int32		len=0;
590
591
	private_t*	p;

592
	*rval = JSVAL_FALSE;
593

594
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
595
		JS_ReportError(cx,getprivate_failure,WHERE);
596
		return(JS_FALSE);
597
	}
598
599
600
601

	if(p->fp==NULL)
		return(JS_TRUE);

602
603
604
605
606
607
608
609
610
611
612
613
	/* offset */
	if(argc)
		JS_ValueToInt32(cx,argv[0],&offset);

	/* length */
	if(argc>1)
		JS_ValueToInt32(cx,argv[1],&len);

	if(len==0)
		len=filelength(fileno(p->fp))-offset;

	if(lock(fileno(p->fp),offset,len)==0)
614
		*rval = JSVAL_TRUE;
615

616
617
	return(JS_TRUE);
}
618

619
static JSBool
620
js_unlock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
621
{
622
623
	int32		offset=0;
	int32		len=0;
624
625
	private_t*	p;

626
	*rval = JSVAL_FALSE;
627

628
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
629
		JS_ReportError(cx,getprivate_failure,WHERE);
630
		return(JS_FALSE);
631
	}
632
633
634
635

	if(p->fp==NULL)
		return(JS_TRUE);

636
637
638
639
640
641
642
643
644
645
646
	/* offset */
	if(argc)
		JS_ValueToInt32(cx,argv[0],&offset);

	/* length */
	if(argc>1)
		JS_ValueToInt32(cx,argv[1],&len);

	if(len==0)
		len=filelength(fileno(p->fp))-offset;

647
	if(unlock(fileno(p->fp),offset,len)==0)
648
		*rval = JSVAL_TRUE;
649

650
651
652
	return(JS_TRUE);
}

653
654
655
656
657
static JSBool
js_delete(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

658
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
659
		JS_ReportError(cx,getprivate_failure,WHERE);
660
		return(JS_FALSE);
661
	}
662
663
664
665
666
667
668
669
670
671

	if(p->fp!=NULL) {	/* close it if it's open */
		fclose(p->fp);
		p->fp=NULL;
	}

	*rval = BOOLEAN_TO_JSVAL(remove(p->name)==0);

	return(JS_TRUE);
}
672
673
674
675
676
677

static JSBool
js_flush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

678
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
679
		JS_ReportError(cx,getprivate_failure,WHERE);
680
		return(JS_FALSE);
681
	}
682
683

	if(p->fp==NULL)
684
		*rval = JSVAL_FALSE;
685
686
687
688
689
690
691
692
693
694
695
	else 
		*rval = BOOLEAN_TO_JSVAL(fflush(p->fp)==0);

	return(JS_TRUE);
}

static JSBool
js_clear_error(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

696
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
697
		JS_ReportError(cx,getprivate_failure,WHERE);
698
		return(JS_FALSE);
699
	}
700
701

	if(p->fp==NULL)
702
		*rval = JSVAL_FALSE;
703
704
	else  {
		clearerr(p->fp);
705
		*rval = JSVAL_TRUE;
706
707
708
709
710
	}

	return(JS_TRUE);
}

711
712
713
714
715
716
717
718
719
720
static JSBool
js_fprintf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		cp;
    uintN		i;
	JSString *	fmt;
    JSString *	str;
	va_list		arglist[64];
	private_t*	p;

721
	*rval = JSVAL_FALSE;
722

723
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
724
		JS_ReportError(cx,getprivate_failure,WHERE);
725
		return(JS_FALSE);
726
	}
727
728
729
730

	if(p->fp==NULL)
		return(JS_TRUE);

731
732
	if((fmt=JS_ValueToString(cx, argv[0]))==NULL) {
		JS_ReportError(cx,"JS_ValueToString failed");
733
		return(JS_FALSE);
734
	}
735
736
737
738
739

	memset(arglist,0,sizeof(arglist));	/* Initialize arglist to NULLs */

    for (i = 1; i < argc && i<sizeof(arglist)/sizeof(arglist[0]); i++) {
		if(JSVAL_IS_STRING(argv[i])) {
740
741
			if((str=JS_ValueToString(cx, argv[i]))==NULL) {
				JS_ReportError(cx,"JS_ValueToString failed");
742
			    return(JS_FALSE);
743
			}
744
745
746
747
748
749
750
751
752
753
			arglist[i-1]=JS_GetStringBytes(str);	/* exception here July-29-2002 */
		}
		else if(JSVAL_IS_DOUBLE(argv[i]))
			arglist[i-1]=(char*)(unsigned long)*JSVAL_TO_DOUBLE(argv[i]);
		else if(JSVAL_IS_INT(argv[i]) || JSVAL_IS_BOOLEAN(argv[i]))
			arglist[i-1]=(char *)JSVAL_TO_INT(argv[i]);
		else
			arglist[i-1]=NULL;
	}

754
755
	if((cp=JS_vsmprintf(JS_GetStringBytes(fmt),(char*)arglist))==NULL) {
		JS_ReportError(cx,"JS_vsmprintf failed");
756
		return(JS_FALSE);
757
	}
758
759
760
761
762
763
764

	*rval = INT_TO_JSVAL(fwrite(cp,1,strlen(cp),p->fp));
	JS_smprintf_free(cp);
	
    return(JS_TRUE);
}

765
766
767
768

/* File Object Properites */
enum {
	 FILE_PROP_NAME		
769
770
	,FILE_PROP_MODE
	,FILE_PROP_ETX
771
772
773
774
775
776
777
778
779
780
	,FILE_PROP_EXISTS	
	,FILE_PROP_DATE		
	,FILE_PROP_IS_OPEN	
	,FILE_PROP_EOF		
	,FILE_PROP_ERROR	
	,FILE_PROP_DESCRIPTOR
	,FILE_PROP_DEBUG	
	,FILE_PROP_POSITION	
	,FILE_PROP_LENGTH	
	,FILE_PROP_ATTRIBUTES
781
	,FILE_PROP_UUENCODED
782
783
	,FILE_PROP_B64ENCODED
	,FILE_PROP_NETWORK_ORDER
784
785
786
787
788
	/* dynamically calculated */
	,FILE_PROP_CHKSUM
	,FILE_PROP_CRC16
	,FILE_PROP_CRC32
	,FILE_PROP_MD5_HEX
789
	,FILE_PROP_MD5_B64
790
791
};

rswindell's avatar
rswindell committed
792

793
794
795
796
797
static JSBool js_file_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
    jsint       tiny;
	private_t*	p;

798
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
799
		JS_ReportError(cx,getprivate_failure,WHERE);
800
		return(JS_FALSE);
801
	}
802
803
804
805
806
807
808

    tiny = JSVAL_TO_INT(id);

	dbprintf(FALSE, p, "setting property %d",tiny);

	switch(tiny) {
		case FILE_PROP_DEBUG:
809
			JS_ValueToBoolean(cx,*vp,&(p->debug));
810
			break;
811
		case FILE_PROP_UUENCODED:
812
813
814
815
816
817
818
			JS_ValueToBoolean(cx,*vp,&(p->uuencoded));
			break;
		case FILE_PROP_B64ENCODED:
			JS_ValueToBoolean(cx,*vp,&(p->b64encoded));
			break;
		case FILE_PROP_NETWORK_ORDER:
			JS_ValueToBoolean(cx,*vp,&(p->network_byte_order));
819
			break;
820
821
822
823
824
825
826
827
828
829
830
		case FILE_PROP_POSITION:
			if(p->fp!=NULL)
				fseek(p->fp,JSVAL_TO_INT(*vp),SEEK_SET);
			break;
		case FILE_PROP_LENGTH:
			if(p->fp!=NULL)
				chsize(fileno(p->fp),JSVAL_TO_INT(*vp));
			break;
		case FILE_PROP_ATTRIBUTES:
			CHMOD(p->name,JSVAL_TO_INT(*vp));
			break;
831
832
833
		case FILE_PROP_ETX:
			p->etx = (uchar)JSVAL_TO_INT(*vp);
			break;
834
835
836
837
838
839
840
	}

	return(JS_TRUE);
}

static JSBool js_file_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
841
842
843
844
845
846
	BYTE*		buf;
	long		l;
	long		len;
	long		offset;
	ulong		sum;
	BYTE		digest[MD5_DIGEST_SIZE];
847
    jsint       tiny;
848
	JSString*	js_str=NULL;
849
850
	private_t*	p;

851
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
852
		JS_ReportError(cx,getprivate_failure,WHERE);
853
		return(JS_FALSE);
854
	}
855
856
857
858
859
860
861
862
863

    tiny = JSVAL_TO_INT(id);

#if 0 /* just too much */
	dbprintf(FALSE, sock, "getting property %d",tiny);
#endif

	switch(tiny) {
		case FILE_PROP_NAME:
864
865
866
			if((js_str=JS_NewStringCopyZ(cx, p->name))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
867
868
			break;
		case FILE_PROP_MODE:
869
870
871
			if((js_str=JS_NewStringCopyZ(cx, p->mode))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
872
873
874
			break;
		case FILE_PROP_EXISTS:
			if(p->fp)	/* open? */
875
				*vp = JSVAL_TRUE;
876
877
878
879
			else
				*vp = BOOLEAN_TO_JSVAL(fexist(p->name));
			break;
		case FILE_PROP_DATE:
880
			JS_NewNumberValue(cx,fdate(p->name),vp);
881
882
883
884
885
			break;
		case FILE_PROP_IS_OPEN:
			*vp = BOOLEAN_TO_JSVAL(p->fp!=NULL);
			break;
		case FILE_PROP_EOF:
886
887
888
			if(p->fp)
				*vp = BOOLEAN_TO_JSVAL(feof(p->fp)!=0);
			else
889
				*vp = JSVAL_TRUE;
890
891
			break;
		case FILE_PROP_ERROR:
892
893
894
			if(p->fp)
				*vp = INT_TO_JSVAL(ferror(p->fp));
			else
895
				*vp = INT_TO_JSVAL(errno);
896
897
			break;
		case FILE_PROP_POSITION:
898
			if(p->fp)
899
				JS_NewNumberValue(cx,ftell(p->fp),vp);
900
901
			else
				*vp = INT_TO_JSVAL(-1);
902
903
904
			break;
		case FILE_PROP_LENGTH:
			if(p->fp)	/* open? */
905
				JS_NewNumberValue(cx,filelength(fileno(p->fp)),vp);
906
			else
907
				JS_NewNumberValue(cx,flength(p->name),vp);
908
909
			break;
		case FILE_PROP_ATTRIBUTES:
910
			JS_NewNumberValue(cx,getfattr(p->name),vp);
911
912
			break;
		case FILE_PROP_DEBUG:
913
914
915
916
			*vp = BOOLEAN_TO_JSVAL(p->debug);
			break;
		case FILE_PROP_UUENCODED:
			*vp = BOOLEAN_TO_JSVAL(p->uuencoded);
917
			break;
918
919
920
921
922
923
		case FILE_PROP_B64ENCODED:
			*vp = BOOLEAN_TO_JSVAL(p->b64encoded);
			break;
		case FILE_PROP_NETWORK_ORDER:
			*vp = BOOLEAN_TO_JSVAL(p->network_byte_order);
			break;
924
		case FILE_PROP_DESCRIPTOR:
925
926
927
928
			if(p->fp)
				*vp = INT_TO_JSVAL(fileno(p->fp));
			else
				*vp = INT_TO_JSVAL(-1);
929
			break;
930
931
932
		case FILE_PROP_ETX:
			*vp = INT_TO_JSVAL(p->etx);
			break;
933
934
935
		case FILE_PROP_CHKSUM:
		case FILE_PROP_CRC16:
		case FILE_PROP_CRC32:
936
937
938
939
			*vp = JSVAL_ZERO;
			if(p->fp==NULL)
				break;
			/* fall-through */
940
		case FILE_PROP_MD5_HEX:
941
		case FILE_PROP_MD5_B64:
942
943
944
945
946
947
948
949
950
951
952
			*vp = JSVAL_VOID;
			if(p->fp==NULL)
				break;
			offset=ftell(p->fp);			/* save current file position */
			fseek(p->fp,0,SEEK_SET);
			len=filelength(fileno(p->fp));
			if(len<1)
				break;
			if((buf=malloc(len*2))==NULL)
				break;
			len=fread(buf,sizeof(BYTE),len,p->fp);
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
			if(len>0) 
				switch(tiny) {
					case FILE_PROP_CHKSUM:
						for(sum=l=0;l<len;l++)
							sum+=buf[l];
						JS_NewNumberValue(cx,sum,vp);
						break;
					case FILE_PROP_CRC16:
						JS_NewNumberValue(cx,crc16(buf,len),vp);
						break;
					case FILE_PROP_CRC32:
						JS_NewNumberValue(cx,crc32(buf,len),vp);
						break;
					case FILE_PROP_MD5_HEX:
						MD5_calc(digest,buf,len);
						MD5_hex(buf,digest);
						js_str=JS_NewStringCopyZ(cx, buf);
						break;
					case FILE_PROP_MD5_B64:
						MD5_calc(digest,buf,len);
						b64_encode(buf,len*2,digest,sizeof(digest));
						js_str=JS_NewStringCopyZ(cx, buf);
						break;
				}
977
978
979
980
981
			free(buf);
			fseek(p->fp,offset,SEEK_SET);	/* restore saved file position */
			if(js_str!=NULL)
				*vp = STRING_TO_JSVAL(js_str);
			break;
982
983
	}

984
	return(JS_TRUE);
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
}

#define FILE_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY

static struct JSPropertySpec js_file_properties[] = {
/*		 name				,tinyid					,flags,				getter,	setter	*/
	{	"name"				,FILE_PROP_NAME			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"mode"				,FILE_PROP_MODE			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"exists"			,FILE_PROP_EXISTS		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"date"				,FILE_PROP_DATE			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"is_open"			,FILE_PROP_IS_OPEN		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"eof"				,FILE_PROP_EOF			,FILE_PROP_FLAGS,	NULL,NULL},
	{	"error"				,FILE_PROP_ERROR		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"descriptor"		,FILE_PROP_DESCRIPTOR	,FILE_PROP_FLAGS,	NULL,NULL},
	/* writeable */
1000
	{	"etx"				,FILE_PROP_ETX			,JSPROP_ENUMERATE,  NULL,NULL},
1001
1002
1003
1004
	{	"debug"				,FILE_PROP_DEBUG		,JSPROP_ENUMERATE,	NULL,NULL},
	{	"position"			,FILE_PROP_POSITION		,JSPROP_ENUMERATE,	NULL,NULL},
	{	"length"			,FILE_PROP_LENGTH		,JSPROP_ENUMERATE,	NULL,NULL},
	{	"attributes"		,FILE_PROP_ATTRIBUTES	,JSPROP_ENUMERATE,	NULL,NULL},
1005
1006
1007
	{	"network_byte_order",FILE_PROP_NETWORK_ORDER,JSPROP_ENUMERATE,	NULL,NULL},
	{	"uue"				,FILE_PROP_UUENCODED	,JSPROP_ENUMERATE,	NULL,NULL},
	{	"base64"			,FILE_PROP_B64ENCODED	,JSPROP_ENUMERATE,	NULL,NULL},
1008
1009
1010
	/* dynamically calculated */
	{	"crc16"				,FILE_PROP_CRC16		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"crc32"				,FILE_PROP_CRC32		,FILE_PROP_FLAGS,	NULL,NULL},
1011
	{	"chksum"			,FILE_PROP_CHKSUM		,FILE_PROP_FLAGS,	NULL,NULL},
1012
	{	"md5_hex"			,FILE_PROP_MD5_HEX		,FILE_PROP_FLAGS,	NULL,NULL},
1013
	{	"md5_base64"		,FILE_PROP_MD5_B64		,FILE_PROP_FLAGS,	NULL,NULL},
1014
1015
1016
	{0}
};

rswindell's avatar
rswindell committed
1017
1018
1019
1020
1021
1022
1023
#ifdef _DEBUG
static char* file_prop_desc[] = {
	 "filename specified in constructor - <small>READ ONLY</small>"
	,"mode string specified in <i>open</i> call - <small>READ ONLY</small>"
	,"<i>true</i> if the file exists - <small>READ ONLY</small>"
	,"last modified date/time (time_t format) - <small>READ ONLY</small>"
	,"<i>true</i> if the file has been opened successfully - <small>READ ONLY</small>"
1024
	,"<i>true</i> if the current file position is at the <i>end of file</i> - <small>READ ONLY</small>"
rswindell's avatar
rswindell committed
1025
1026
1027
	,"the last occurred error value (use clear_error to clear) - <small>READ ONLY</small>"
	,"the open file descriptor (advanced use only) - <small>READ ONLY</small>"
	,"end-of-text character (advanced use only), if non-zero used by <i>read</i>, <i>readln</i>, and <i>write</i>"
1028
	,"set to <i>true</i> to enabel debug log output"
rswindell's avatar
rswindell committed
1029
1030
1031
	,"the current file position (offset in bytes), change value to seek within file"
	,"the current length of the file (in bytes)"
	,"file mode/attributes"
1032
1033
1034
	,"set to <i>true</i> if binary data is to be written and read in Network Byte Order (big end first)"
	,"set to <i>true</i> to enable automatic unix-to-unix encode and decode on <tt>read</tt> and <tt>write</tt> calls"
	,"set to <i>true</i> to enable automatic base64 encode and decode on <tt>read</tt> and <tt>write</tt> calls"
1035
1036
	,"calculated 16-bit CRC of file contents - <small>READ ONLY</small>"
	,"calculated 32-bit CRC of file contents - <small>READ ONLY</small>"
1037
1038
1039
	,"calculated 32-bit checksum of file contents - <small>READ ONLY</small>"
	,"calculated 128-bit MD5 digest of file contents as hexadecimal string - <small>READ ONLY</small>"
	,"calculated 128-bit MD5 digest of file contents as base64-encoded string - <small>READ ONLY</small>"
rswindell's avatar
rswindell committed
1040
1041
1042
1043
1044
	,NULL
};
#endif


1045
static jsMethodSpec js_file_functions[] = {
1046
	{"open",			js_open,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[string mode, boolean shareable, number buflen]")
rswindell's avatar
rswindell committed
1047
1048
1049
1050
1051
1052
1053
1054
1055
	,JSDOCSTR("open file, <i>shareable</i> defaults to <i>false</i>, <i>buflen</i> defaults to 2048 bytes, "
		"mode (default: <tt>w+</tt>) specifies the type of access requested for the file, as follows:<br>"
		"<tt>r&nbsp</tt> open for reading; if the file does not exist or cannot be found, the open call fails<br>"
		"<tt>w&nbsp</tt> open an empty file for writing; if the given file exists, its contents are destroyed<br>"
		"<tt>a&nbsp</tt> open for writing at the end of the file (appending); creates the file first if it doesnt exist<br>"
		"<tt>r+</tt> open for both reading and writing (the file must exist)<br>"
		"<tt>w+</tt> open an empty file for both reading and writing; if the given file exists, its contents are destroyed<br>"
		"<tt>a+</tt> open for reading and appending<br>"
		"<tt>b&nbsp</tt> open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed (e.g. <tt>r+b</tt>)<br>"
rswindell's avatar
rswindell committed
1056
		)
1057
1058
	},		
	{"close",			js_close,			0,	JSTYPE_VOID,	""
1059
	,JSDOCSTR("close file")
1060
	},		
1061
1062
	{"remove",			js_delete,			0,	JSTYPE_BOOLEAN, ""
	,JSDOCSTR("remove the file from the disk")
1063
	},
1064
	{"clearError",		js_clear_error,		0,	JSTYPE_ALIAS },
1065
	{"clear_error",		js_clear_error,		0,	JSTYPE_BOOLEAN, ""
rswindell's avatar
rswindell committed