js_file.c 28.2 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
56

} private_t;

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

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);
68
69
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
70
71
    va_end(argptr);
	
72
	lprintf("%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
73
74
}

75
76
77
78
79
80
81
82
/* 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;
83
84
	else
		flags|=O_TEXT;
85
86
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

	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);
}
113
114
115
116
117
118
119

/* File Object Methods */

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

127
	*rval = JSVAL_FALSE;
128

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

	if(p->fp!=NULL)  
		return(JS_TRUE);
136
137
138
139

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

151
152
153
154
155
156
157
158
	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);
		}
	}
159
	if(p->fp!=NULL) {
160
		*rval = JSVAL_TRUE;
161
		dbprintf(FALSE, p, "opened: %s",p->name);
162
163
164
165
166
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
167
168
169
170
171
172
173
174
175
176

	return(JS_TRUE);
}


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

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

	*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
197
js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
198
199
{
	char*		cp;
200
	char*		buf;
201
	char*		uubuf;
202
	int32		len=512;
203
	int32		uulen;
204
205
206
	JSString*	str;
	private_t*	p;

207
208
	*rval = JSVAL_NULL;

209
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
210
		JS_ReportError(cx,getprivate_failure,WHERE);
211
		return(JS_FALSE);
212
	}
213

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

217
	if(argc)
218
		JS_ValueToInt32(cx,argv[0],&len);
219

220
221
222
223
224
225
226
227
228
229
230
231
232
	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; 
	}

233
234
235
236
237
238
239
240
241
242
243
244
	if(p->uuencoded) {
		uulen=len*2;
		if((uubuf=malloc(uulen))==NULL)
			return(JS_TRUE);
		uulen=uuencode(uubuf,uulen,buf,len);
		if(uulen>=0) {
			free(buf);
			buf=uubuf;
		} else
			free(uubuf);
	}

245
246
247
248
	str = JS_NewStringCopyZ(cx, buf);

	free(buf);

249
250
251
	if(str==NULL)
		return(JS_FALSE);

252
253
254
	*rval = STRING_TO_JSVAL(str);

	dbprintf(FALSE, p, "read %u bytes",len);
255
256
257
258
259
		
	return(JS_TRUE);
}

static JSBool
260
js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
261
{
262
263
	char*		cp;
	char*		buf;
264
	int32		len=512;
265
	JSString*	js_str;
266
267
	private_t*	p;

268
	*rval = JSVAL_NULL;
269

270
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
271
		JS_ReportError(cx,getprivate_failure,WHERE);
272
		return(JS_FALSE);
273
	}
274
275
276

	if(p->fp==NULL)
		return(JS_TRUE);
277
278
	
	if(argc)
279
		JS_ValueToInt32(cx,argv[0],&len);
280

281
282
283
284
	if((buf=malloc(len))==NULL)
		return(JS_TRUE);

	if(fgets(buf,len,p->fp)!=NULL) {
285
286
287
288
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
289
290
291
292
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
293
294
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)
			*rval = STRING_TO_JSVAL(js_str);
295
296
	}

297
298
	free(buf);

299
300
301
302
	return(JS_TRUE);
}

static JSBool
303
js_readbin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
304
305
306
307
308
309
310
{
	BYTE		b;
	WORD		w;
	DWORD		l;
	size_t		size=sizeof(DWORD);
	private_t*	p;

311
	*rval = INT_TO_JSVAL(-1);
312

313
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
314
		JS_ReportError(cx,getprivate_failure,WHERE);
315
		return(JS_FALSE);
316
	}
317
318
319
320

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

321
	if(argc) 
322
		JS_ValueToInt32(cx,argv[0],(int32*)&size);
323
324
325

	switch(size) {
		case sizeof(BYTE):
326
327
			if(fread(&b,1,size,p->fp)==size)
				*rval = INT_TO_JSVAL(b);
328
329
			break;
		case sizeof(WORD):
330
331
			if(fread(&w,1,size,p->fp)==size)
				*rval = INT_TO_JSVAL(w);
332
333
			break;
		case sizeof(DWORD):
334
			if(fread(&l,1,size,p->fp)==size)
335
				JS_NewNumberValue(cx,l,rval);
336
337
338
339
340
341
342
			break;
	}
		
	return(JS_TRUE);
}

static JSBool
343
js_readall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
344
{
345
346
347
    jsint       len=0;
    jsval       line;
    JSObject*	array;
348
349
	private_t*	p;

350
351
	*rval = JSVAL_NULL;

352
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
353
		JS_ReportError(cx,getprivate_failure,WHERE);
354
		return(JS_FALSE);
355
	}
356

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

360
    array = JS_NewArrayObject(cx, 0, NULL);
361

362
363
364
365
    while(!feof(p->fp)) {
		js_readln(cx, obj, 0, NULL, &line); 
		if(line==JSVAL_NULL)
			break;
366
367
        if(!JS_SetElement(cx, array, len++, &line))
			break;
368
	}
369
    *rval = OBJECT_TO_JSVAL(array);
370

371
372
    return(JS_TRUE);
}
373

374
375
376
377
static JSBool
js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		cp;
378
379
380
	char*		uubuf=NULL;
	int			len;	/* string length */
	int			tlen;	/* total length to write (may be greater than len) */
381
	private_t*	p;
382

383
	*rval = JSVAL_FALSE;
384

385
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
386
		JS_ReportError(cx,getprivate_failure,WHERE);
387
		return(JS_FALSE);
388
	}
389
390
391
392

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

393
394
395
396
397
398
399
400
401
402
403
404
405
	cp=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
	len=strlen(cp);

	if(p->uuencoded && len && (uubuf=malloc(len))!=NULL) {
		len=uudecode(uubuf,len,cp,len);
		if(len<0) {
			free(uubuf);
			return(JS_TRUE);
		}
		cp=uubuf;
	}

	tlen=len;
406
	if(argc>1) {
407
		JS_ValueToInt32(cx,argv[1],(int32*)&tlen);
408
409
410
		if(len>tlen)
			len=tlen;
	}
411
412

	if(fwrite(cp,1,len,p->fp)==(size_t)len) {
413
414
415
416
417
418
419
420
421
422
423
		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);
424
		*rval = JSVAL_TRUE;
425
426
	} else 
		dbprintf(TRUE, p, "write of %u bytes failed",len);
427
		
428
429
430
	if(uubuf!=NULL)
		free(uubuf);

431
432
433
434
	return(JS_TRUE);
}

static JSBool
435
js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
436
{
437
438
439
440
	char*		cp="";
	JSString*	str;
	private_t*	p;

441
	*rval = JSVAL_FALSE;
442

443
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
444
		JS_ReportError(cx,getprivate_failure,WHERE);
445
		return(JS_FALSE);
446
	}
447
448
449
450
451

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

	if(argc) {
452
453
		if((str = JS_ValueToString(cx, argv[0]))==NULL) {
			JS_ReportError(cx,"JS_ValueToString failed");
454
			return(JS_FALSE);
455
		}
456
457
458
459
		cp = JS_GetStringBytes(str);
	}

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

462
463
	return(JS_TRUE);
}
464

465
static JSBool
466
js_writebin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
467
{
468
469
470
	BYTE		b;
	WORD		w;
	DWORD		l;
471
	int32		val=0;
472
	size_t		wr=0;
473
	size_t		size=sizeof(DWORD);
474
475
	private_t*	p;

476
	*rval = JSVAL_FALSE;
477

478
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
479
		JS_ReportError(cx,getprivate_failure,WHERE);
480
		return(JS_FALSE);
481
	}
482

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

486
	if(argc>1) 
487
		JS_ValueToInt32(cx,argv[1],(int32*)&size);
488

489
490
	switch(size) {
		case sizeof(BYTE):
491
492
			JS_ValueToInt32(cx,argv[0],&val);
			b = (BYTE)val;
493
			wr=fwrite(&b,1,size,p->fp);
494
495
			break;
		case sizeof(WORD):
496
497
			JS_ValueToInt32(cx,argv[0],&val);
			w = (WORD)val;
498
			wr=fwrite(&w,1,size,p->fp);
499
500
			break;
		case sizeof(DWORD):
501
502
			JS_ValueToInt32(cx,argv[0],&val);
			l = val;
503
504
505
506
507
			wr=fwrite(&l,1,size,p->fp);
			break;
		default:	
			/* unknown size */
			dbprintf(TRUE, p, "unsupported binary write size: %d",size);
508
509
			break;
	}
510
	if(wr==size)
511
		*rval = JSVAL_TRUE;
512
		
513
514
515
	return(JS_TRUE);
}

516
517
518
519
520
521
522
523
524
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;

525
	*rval = JSVAL_FALSE;
526

527
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
528
		JS_ReportError(cx,getprivate_failure,WHERE);
529
		return(JS_FALSE);
530
	}
531
532
533
534

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

535
	if(!JSVAL_IS_OBJECT(argv[0]))
536
537
538
539
		return(JS_TRUE);

    array = JSVAL_TO_OBJECT(argv[0]);

540
541
542
    if(!JS_IsArrayObject(cx, array))
		return(JS_TRUE);

543
544
    if(!JS_GetArrayLength(cx, array, &limit))
		return(JS_FALSE);
545

546
    *rval = JSVAL_TRUE;
547

548
549
550
551
    for(i=0;i<limit;i++) {
        if(!JS_GetElement(cx, array, i, &elemval))
			break;
        js_writeln(cx, obj, 1, &elemval, rval);
552
		if(*rval!=JSVAL_TRUE)
553
			break;
554
555
556
557
558
    }

    return(JS_TRUE);
}

559
static JSBool
560
js_lock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
561
{
562
563
	int32		offset=0;
	int32		len=0;
564
565
	private_t*	p;

566
	*rval = JSVAL_FALSE;
567

568
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
569
		JS_ReportError(cx,getprivate_failure,WHERE);
570
		return(JS_FALSE);
571
	}
572
573
574
575

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

576
577
578
579
580
581
582
583
584
585
586
587
	/* 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)
588
		*rval = JSVAL_TRUE;
589

590
591
	return(JS_TRUE);
}
592

593
static JSBool
594
js_unlock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
595
{
596
597
	int32		offset=0;
	int32		len=0;
598
599
	private_t*	p;

600
	*rval = JSVAL_FALSE;
601

602
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
603
		JS_ReportError(cx,getprivate_failure,WHERE);
604
		return(JS_FALSE);
605
	}
606
607
608
609

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

610
611
612
613
614
615
616
617
618
619
620
	/* 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;

621
	if(unlock(fileno(p->fp),offset,len)==0)
622
		*rval = JSVAL_TRUE;
623

624
625
626
	return(JS_TRUE);
}

627
628
629
630
631
static JSBool
js_delete(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

632
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
633
		JS_ReportError(cx,getprivate_failure,WHERE);
634
		return(JS_FALSE);
635
	}
636
637
638
639
640
641
642
643
644
645

	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);
}
646
647
648
649
650
651

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

652
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
653
		JS_ReportError(cx,getprivate_failure,WHERE);
654
		return(JS_FALSE);
655
	}
656
657

	if(p->fp==NULL)
658
		*rval = JSVAL_FALSE;
659
660
661
662
663
664
665
666
667
668
669
	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;

670
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
671
		JS_ReportError(cx,getprivate_failure,WHERE);
672
		return(JS_FALSE);
673
	}
674
675

	if(p->fp==NULL)
676
		*rval = JSVAL_FALSE;
677
678
	else  {
		clearerr(p->fp);
679
		*rval = JSVAL_TRUE;
680
681
682
683
684
	}

	return(JS_TRUE);
}

685
686
687
688
689
690
691
692
693
694
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;

695
	*rval = JSVAL_FALSE;
696

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

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

705
706
	if((fmt=JS_ValueToString(cx, argv[0]))==NULL) {
		JS_ReportError(cx,"JS_ValueToString failed");
707
		return(JS_FALSE);
708
	}
709
710
711
712
713

	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])) {
714
715
			if((str=JS_ValueToString(cx, argv[i]))==NULL) {
				JS_ReportError(cx,"JS_ValueToString failed");
716
			    return(JS_FALSE);
717
			}
718
719
720
721
722
723
724
725
726
727
			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;
	}

728
729
	if((cp=JS_vsmprintf(JS_GetStringBytes(fmt),(char*)arglist))==NULL) {
		JS_ReportError(cx,"JS_vsmprintf failed");
730
		return(JS_FALSE);
731
	}
732
733
734
735
736
737
738

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

739
740
741
742

/* File Object Properites */
enum {
	 FILE_PROP_NAME		
743
744
	,FILE_PROP_MODE
	,FILE_PROP_ETX
745
746
747
748
749
750
751
752
753
754
	,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
755
	,FILE_PROP_UUENCODED
756
757
758
759
760
761
762
	/* dynamically calculated */
	,FILE_PROP_CHKSUM
	,FILE_PROP_CRC16
	,FILE_PROP_CRC32
	,FILE_PROP_BASE64
	,FILE_PROP_MD5_HEX
	,FILE_PROP_MD5_BASE64
763
764
};

rswindell's avatar
rswindell committed
765

766
767
768
769
770
static JSBool js_file_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
    jsint       tiny;
	private_t*	p;

771
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
772
		JS_ReportError(cx,getprivate_failure,WHERE);
773
		return(JS_FALSE);
774
	}
775
776
777
778
779
780
781
782
783

    tiny = JSVAL_TO_INT(id);

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

	switch(tiny) {
		case FILE_PROP_DEBUG:
			p->debug = JSVAL_TO_BOOLEAN(*vp);
			break;
784
785
786
		case FILE_PROP_UUENCODED:
			p->uuencoded = JSVAL_TO_BOOLEAN(*vp);
			break;
787
788
789
790
791
792
793
794
795
796
797
		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;
798
799
800
		case FILE_PROP_ETX:
			p->etx = (uchar)JSVAL_TO_INT(*vp);
			break;
801
802
803
804
805
806
807
	}

	return(JS_TRUE);
}

static JSBool js_file_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
808
809
810
811
812
813
	BYTE*		buf;
	long		l;
	long		len;
	long		offset;
	ulong		sum;
	BYTE		digest[MD5_DIGEST_SIZE];
814
    jsint       tiny;
815
	JSString*	js_str=NULL;
816
817
	private_t*	p;

818
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
819
		JS_ReportError(cx,getprivate_failure,WHERE);
820
		return(JS_FALSE);
821
	}
822
823
824
825
826
827
828
829
830

    tiny = JSVAL_TO_INT(id);

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

	switch(tiny) {
		case FILE_PROP_NAME:
831
832
833
			if((js_str=JS_NewStringCopyZ(cx, p->name))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
834
835
			break;
		case FILE_PROP_MODE:
836
837
838
			if((js_str=JS_NewStringCopyZ(cx, p->mode))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
839
840
841
			break;
		case FILE_PROP_EXISTS:
			if(p->fp)	/* open? */
842
				*vp = JSVAL_TRUE;
843
844
845
846
			else
				*vp = BOOLEAN_TO_JSVAL(fexist(p->name));
			break;
		case FILE_PROP_DATE:
847
			JS_NewNumberValue(cx,fdate(p->name),vp);
848
849
850
851
852
			break;
		case FILE_PROP_IS_OPEN:
			*vp = BOOLEAN_TO_JSVAL(p->fp!=NULL);
			break;
		case FILE_PROP_EOF:
853
854
855
			if(p->fp)
				*vp = BOOLEAN_TO_JSVAL(feof(p->fp)!=0);
			else
856
				*vp = JSVAL_TRUE;
857
858
			break;
		case FILE_PROP_ERROR:
859
860
861
			if(p->fp)
				*vp = INT_TO_JSVAL(ferror(p->fp));
			else
862
				*vp = INT_TO_JSVAL(errno);
863
864
			break;
		case FILE_PROP_POSITION:
865
			if(p->fp)
866
				JS_NewNumberValue(cx,ftell(p->fp),vp);
867
868
			else
				*vp = INT_TO_JSVAL(-1);
869
870
871
			break;
		case FILE_PROP_LENGTH:
			if(p->fp)	/* open? */
872
				JS_NewNumberValue(cx,filelength(fileno(p->fp)),vp);
873
874
875
876
			else
				*vp = INT_TO_JSVAL(flength(p->name));
			break;
		case FILE_PROP_ATTRIBUTES:
877
			JS_NewNumberValue(cx,getfattr(p->name),vp);
878
879
			break;
		case FILE_PROP_DEBUG:
880
881
882
883
			*vp = BOOLEAN_TO_JSVAL(p->debug);
			break;
		case FILE_PROP_UUENCODED:
			*vp = BOOLEAN_TO_JSVAL(p->uuencoded);
884
885
			break;
		case FILE_PROP_DESCRIPTOR:
886
887
888
889
			if(p->fp)
				*vp = INT_TO_JSVAL(fileno(p->fp));
			else
				*vp = INT_TO_JSVAL(-1);
890
			break;
891
892
893
		case FILE_PROP_ETX:
			*vp = INT_TO_JSVAL(p->etx);
			break;
894
895
896
		case FILE_PROP_CHKSUM:
		case FILE_PROP_CRC16:
		case FILE_PROP_CRC32:
897
898
899
900
			*vp = JSVAL_ZERO;
			if(p->fp==NULL)
				break;
			/* fall-through */
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
		case FILE_PROP_BASE64:
		case FILE_PROP_MD5_HEX:
		case FILE_PROP_MD5_BASE64:
			*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);
			if(len<1)
				break;

			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:
925
					JS_NewNumberValue(cx,crc16(buf,len),vp);
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
					break;
				case FILE_PROP_CRC32:
					JS_NewNumberValue(cx,crc32(buf,len),vp);
					break;
				case FILE_PROP_BASE64:
					b64_encode(buf,len*2,buf,len);
					js_str=JS_NewStringCopyZ(cx, buf);
					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_BASE64:
					MD5_calc(digest,buf,len);
					b64_encode(buf,len*2,digest,sizeof(digest));
					js_str=JS_NewStringCopyZ(cx, buf);
					break;
			}
			free(buf);
			fseek(p->fp,offset,SEEK_SET);	/* restore saved file position */
			if(js_str!=NULL)
				*vp = STRING_TO_JSVAL(js_str);
			break;
950
951
	}

952
	return(JS_TRUE);
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
}

#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 */
968
	{	"etx"				,FILE_PROP_ETX			,JSPROP_ENUMERATE,  NULL,NULL},
969
970
971
972
	{	"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},
973
	{	"uuencoded"			,FILE_PROP_UUENCODED	,JSPROP_ENUMERATE,	NULL,NULL},
974
975
976
977
978
979
980
	/* dynamically calculated */
	{	"chksum"			,FILE_PROP_CHKSUM		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"crc16"				,FILE_PROP_CRC16		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"crc32"				,FILE_PROP_CRC32		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"base64"			,FILE_PROP_BASE64		,FILE_PROP_FLAGS,	NULL,NULL},
	{	"md5_base64"		,FILE_PROP_MD5_BASE64	,FILE_PROP_FLAGS,	NULL,NULL},
	{	"md5_hex"			,FILE_PROP_MD5_HEX		,FILE_PROP_FLAGS,	NULL,NULL},
981
982
983
	{0}
};

rswindell's avatar
rswindell committed
984
985
986
987
988
989
990
#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>"
991
	,"<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
992
993
994
995
996
997
998
	,"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>"
	,"<i>true</i> if debug output is enabled"
	,"the current file position (offset in bytes), change value to seek within file"
	,"the current length of the file (in bytes)"
	,"file mode/attributes"
999
	,"<i>true</i> if read/write operations perform Unix-to-Unix encode/decode automatically"
1000
1001
1002
1003
1004
1005
	,"calculated 32-bit checksum of file contents - <small>READ ONLY</small>"
	,"calculated 16-bit CRC of file contents - <small>READ ONLY</small>"
	,"calculated 32-bit CRC of file contents - <small>READ ONLY</small>"
	,"base64-encoded file contents (string) - <small>READ ONLY</small>"
	,"base64-encoded calculated MD5 digest of file contents (string) - <small>READ ONLY</small>"
	,"hexadecimal-encoded calculated MD5 digest of file contents (string) - <small>READ ONLY</small>"
rswindell's avatar
rswindell committed
1006
1007
1008
1009
1010
	,NULL
};
#endif


1011
static jsMethodSpec js_file_functions[] = {
1012
	{"open",			js_open,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[string mode, boolean shareable, number buflen]")
rswindell's avatar
rswindell committed
1013
1014
1015
1016
1017
1018
1019
1020
1021
	,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
1022
		)
1023
1024
	},		
	{"close",			js_close,			0,	JSTYPE_VOID,	""
1025
	,JSDOCSTR("close file")
1026
	},		
1027
1028
	{"remove",			js_delete,			0,	JSTYPE_BOOLEAN, ""
	,JSDOCSTR("remove the file from the disk")
1029
	},
1030
	{"clearError",		js_clear_error,		0,	JSTYPE_ALIAS },
1031
	{"clear_error",		js_clear_error,		0,	JSTYPE_BOOLEAN, ""
rswindell's avatar
rswindell committed
1032
	,JSDOCSTR("clears the current error value (AKA clearError)")
1033
1034
	},
	{"flush",			js_flush,			0,	JSTYPE_BOOLEAN,	""
rswindell's avatar
rswindell committed
1035
	,JSDOCSTR("flush/commit buffers to disk")
1036
	},
1037
	{"lock",			js_lock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset, length]")
rswindell's avatar
rswindell committed
1038
	,JSDOCSTR("lock file record for exclusive access (file must be opened <i>shareable</i>)")
1039
	},		
1040
	{"unlock",			js_unlock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset, length]")
rswindell's avatar
rswindell committed
1041
	,JSDOCSTR("unlock file record for exclusive access")
1042
	},		
1043
1044
	{"read",			js_read,			0,	JSTYPE_STRING,	JSDOCSTR("[number maxlen]")
	,JSDOCSTR("read a string from file, maxlen defaults to 512 characters")
1045
	},
1046
1047
	{"readln",			js_readln,			0,	JSTYPE_STRING,	JSDOCSTR("[number maxlen]")
	,JSDOCSTR("read a line-feed terminated string, maxlen defaults 512 characters")
1048
	},		
1049
1050
	{"readBin",			js_readbin,			0,	JSTYPE_NUMBER,	JSDOCSTR("[number bytes]")
	,JSDOCSTR("read a binary integer from the file, default number of bytes is 4 (32-bits)")
1051
1052
	},
	{"readAll",			js_readall,			0,	JSTYPE_ARRAY,	""
1053
	,JSDOCSTR("read all lines into an array of strings")
1054
	},
1055
1056
	{"write",			js_write,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("string text [,number len]")
	,JSDOCSTR("write a string to the file")
1057
	},
1058
1059
	{"writeln",			js_writeln,			0,	JSTYPE_BOOLEAN, JSDOCSTR("[string text]")
	,JSDOCSTR("write a line-feed terminated string to the file")
1060
	},
1061
1062
	{"writeBin",		js_writebin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("number value [,number bytes]")
	,JSDOCSTR("write a binary integer to the file, default number of bytes is 4 (32-bits)")
1063
	},
1064
1065
	{"writeAll",		js_writeall,		0,	JSTYPE_BOOLEAN,	JSDOCSTR("array lines")
	,JSDOCSTR("write an array of strings to file")
1066
	},		
1067
	{"printf",			js_fprintf,			0,	JSTYPE_NUMBER,	JSDOCSTR("string format [,args]")
rswindell's avatar
rswindell committed
1068
	,JSDOCSTR("write a formatted string to the file (ala fprintf)")
1069
	},		
1070
1071
1072
	{0}
};