js_file.c 81.3 KB
Newer Older
1 2 3 4 5 6
/* Synchronet JavaScript "File" Object */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *																			*
 * 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										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
23
#include "xpendian.h"
24 25
#include "md5.h"
#include "base64.h"
26
#include "uucode.h"
27
#include "yenc.h"
28
#include "ini_file.h"
29
#include <stdbool.h>
30

31 32 33 34
#if !defined(__unix__)
	#include <conio.h>		/* for kbhit() */
#endif

35 36
#ifdef JAVASCRIPT

37
#include "js_request.h"
38

39 40
typedef struct
{
41
	FILE*	fp;
42 43
	char	name[MAX_PATH+1];
	char	mode[4];
44
	uchar	etx;
45
	BOOL	debug;
46
	BOOL	rot13;
47
	BOOL	yencoded;
48
	BOOL	uuencoded;
49 50
	BOOL	b64encoded;
	BOOL	network_byte_order;
51
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
52
	ini_style_t ini_style;
53 54 55 56 57 58 59 60 61 62 63 64

} private_t;

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);
65 66
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
67
    va_end(argptr);
68

69
	lprintf(LOG_DEBUG,"%04d File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
70 71
}

72 73 74 75 76 77 78
/* 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;
79 80
	else
		flags|=O_TEXT;
81

82 83 84
	if(strchr(mode,'x'))
		flags|=O_EXCL;

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
	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);
}
112 113 114

/* File Object Methods */

115
extern JSClass js_file_class;
116
static JSBool
117
js_open(JSContext *cx, uintN argc, jsval *arglist)
118
{
119 120
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
121
	BOOL		shareable=FALSE;
122
	int			file = -1;
123
	uintN		i;
124
	jsint		bufsize=2*1024;
125 126
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
127
	jsrefcount	rc;
128

129
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
130
		return(JS_FALSE);
131
	}
132

133 134
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

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

138
	SAFECOPY(p->mode,"w+");		/* default mode */
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 146 147
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
		}
		else if(JSVAL_IS_BOOLEAN(argv[i]))	/* shareable */
148
			shareable=JSVAL_TO_BOOLEAN(argv[i]);
149 150 151 152
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
153 154
	}

155
	rc=JS_SUSPENDREQUEST(cx);
156 157 158 159
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
160 161 162 163
			char *fdomode=strdup(p->mode);
			char *e=fdomode;

			if(fdomode && e) {
164 165
				/* Remove deprecated (never-worked, non-standard) 'e'xclusive mode char (and warn): */
				for(e=strchr(fdomode, 'e'); e ; e=strchr(e, 'e')) {
166
					JS_ReportWarning(cx, "Deprecated file open mode: 'e'");
167 168 169 170
					memmove(e, e+1, strlen(e));
				}
				/* Remove (C11 standard) 'x'clusive mode char to avoid MSVC assertion: */
				for(e=strchr(fdomode, 'x'); e ; e=strchr(e, 'x'))
171
					memmove(e, e+1, strlen(e));
172 173 174
				if((p->fp=fdopen(file,fdomode)) == NULL) {
					JS_ReportWarning(cx, "fdopen(%s, %s) ERROR %d: %s", p->name, fdomode, errno, strerror(errno));
				}
175 176
			}
			free(fdomode);
177 178
		}
	}
179
	if(p->fp!=NULL) {
180
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
181
		dbprintf(FALSE, p, "opened: %s",p->name);
182 183
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
184 185 186 187 188
		else {
#ifdef _WIN32
			if(bufsize < 2)
				bufsize = 2;
#endif
189
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
190
		}
191 192
	} else if(file >= 0)
		close(file);
193
	JS_RESUMEREQUEST(cx, rc);
194 195 196 197

	return(JS_TRUE);
}

198
static JSBool
199
js_popen(JSContext *cx, uintN argc, jsval *arglist)
200
{
201 202
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
203 204 205 206
	uintN		i;
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
207
	jsrefcount	rc;
208

209
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
210

211 212
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
213 214 215
		return(JS_FALSE);
	}

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

219
	SAFECOPY(p->mode,"r+");	/* default mode */
220 221 222 223 224 225
	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
			}
226
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
227 228 229 230 231 232 233
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}

234
	rc=JS_SUSPENDREQUEST(cx);
235 236 237
	p->fp=popen(p->name,p->mode);
	if(p->fp!=NULL) {
		p->pipe=TRUE;
238
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
239 240 241 242 243 244
		dbprintf(FALSE, p, "popened: %s",p->name);
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
245
	JS_RESUMEREQUEST(cx, rc);
246 247 248

	return(JS_TRUE);
}
249 250

static JSBool
251
js_close(JSContext *cx, uintN argc, jsval *arglist)
252
{
253
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
254
	private_t*	p;
deuce's avatar
deuce committed
255
	jsrefcount	rc;
256

257
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
258
		return(JS_FALSE);
259
	}
260

261 262
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

266
	rc=JS_SUSPENDREQUEST(cx);
267 268 269 270 271 272
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
273

274
	p->fp=NULL;
275 276
	dbprintf(FALSE, p, "closed: %s", p->name);

277
	JS_RESUMEREQUEST(cx, rc);
278 279 280 281

	return(JS_TRUE);
}

282 283 284 285 286 287 288 289 290
static JSBool
js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	private_t*	p;
	jsrefcount	rc;
	int32		timeout = -1;

291
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
292 293 294 295 296 297
		return(JS_FALSE);
	}

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

298
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
299 300 301 302 303 304 305
		if(!JS_ValueToInt32(cx,argv[0],&timeout))
			return(JS_FALSE);
	}

	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(FALSE));
	rc=JS_SUSPENDREQUEST(cx);
#ifdef __unix__
Deucе's avatar
Deucе committed
306 307 308 309 310
	/*
	 * TODO: macOS poll() page has the ominous statement that "The poll() system call currently does not support devices."
	 *       But, since we don't support OS X in Synchronet that's likely OK?
	 */
	if (socket_readable(fileno(p->fp), timeout))
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
#else
	while(timeout) {
		if (isatty(fileno(p->fp))) {
			if (kbhit()) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
		else {
			if (!eof(fileno(p->fp))) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
	}
#endif
	JS_RESUMEREQUEST(cx, rc);
	return JS_TRUE;
}

342 343 344 345 346 347 348 349 350 351
static JSBool
js_raw_read(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	char*		buf;
	int32		len;
	JSString*	str;
	private_t*	p;
	jsrefcount	rc;
352 353
	int		fd;
	off_t		pos;
354 355 356

	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

357 358
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
359 360 361 362 363 364
		return(JS_FALSE);
	}

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

365
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
366 367 368 369 370 371 372 373 374 375 376
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else
		len = 1;
	if(len<0)
		len=1;

	if((buf=malloc(len))==NULL)
		return(JS_TRUE);

	rc=JS_SUSPENDREQUEST(cx);
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
	// https://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_05.html#tag_02_05_01
	/* For the first handle, the first applicable condition below applies. After the actions
	 * required below are taken, if the handle is still open, the application can close it.
	 *   If it is a file descriptor, no action is required.
	 *   If the only further action to be performed on any handle to this open file descriptor
         *      is to close it, no action need be taken.
	 *   If it is a stream which is unbuffered, no action need be taken.
	 *   If it is a stream which is line buffered, and the last byte written to the stream was a
	 *      <newline> (that is, as if a: putc('\n') was the most recent operation on that stream),
	 *      no action need be taken.
	 *   If it is a stream which is open for writing or appending (but not also open for reading),
	 *      the application shall either perform an fflush(), or the stream shall be closed.
	 *   If the stream is open for reading and it is at the end of the file ( feof() is true), no
	 *      action need be taken.
	 *   If the stream is open with a mode that allows reading and the underlying open file
	 *      description refers to a device that is capable of seeking, the application shall
	 *      either perform an fflush(), or the stream shall be closed.
	 * Otherwise, the result is undefined.
	 * For the second handle:
	 *   If any previous active handle has been used by a function that explicitly changed the file
	 *      offset, except as required above for the first handle, the application shall perform an
	 *      lseek() or fseek() (as appropriate to the type of handle) to an appropriate location.
	 */
	/*
	 * Since we don't want to overcomplicate this, it basically boils down to:
	 * Call fflush() on the stream, lseek() on the descriptor, diddle the descriptor, then fseek() the
	 * stream.
	 *
	 * The only option bit is the fflush() on the stream, but it never hurts and is sometimes
	 * required by POSIX.
	 */
	fflush(p->fp);
	pos = ftell(p->fp);
	fd = fileno(p->fp);
	lseek(fd, pos, SEEK_SET);
412
	len = read(fileno(p->fp),buf,len);
413
	fseeko(p->fp, pos + (len >= 0 ? len : 0), SEEK_SET);
414
	dbprintf(FALSE, p, "read %u raw bytes",len);
415
	if(len<0)
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
		len=0;

	JS_RESUMEREQUEST(cx, rc);

	str = JS_NewStringCopyN(cx, buf, len);
	free(buf);

	if(str==NULL)
		return(JS_FALSE);

	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));

	return(JS_TRUE);
}


432
static JSBool
433
js_read(JSContext *cx, uintN argc, jsval *arglist)
434
{
435 436
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
437
	char*		cp;
438
	char*		buf;
439
	char*		uubuf;
440 441
	int32		len;
	int32		offset;
442
	int32		uulen;
443 444
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
445
	jsrefcount	rc;
446

447
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
448

449
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
450
		return(JS_FALSE);
451
	}
452

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

456
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
457 458 459
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
460
		rc=JS_SUSPENDREQUEST(cx);
461 462
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
463 464
		if(offset>0)
			len-=offset;
465
		JS_RESUMEREQUEST(cx, rc);
466 467 468
	}
	if(len<0)
		len=512;
469

470
	if((buf=malloc(len+1))==NULL)
471 472
		return(JS_TRUE);

473
	rc=JS_SUSPENDREQUEST(cx);
474
	len = fread(buf,1,len,p->fp);
475
	dbprintf(FALSE, p, "read %u bytes",len);
476
	if(len<0)
477 478 479 480 481
		len=0;
	buf[len]=0;

	if(p->etx) {
		cp=strchr(buf,p->etx);
482
		if(cp) *cp=0;
483
		len=strlen(buf);
484 485
	}

486 487 488
	if(p->rot13)
		rot13(buf);

489
	if(p->uuencoded || p->b64encoded || p->yencoded) {
490
		uulen=len*2;
deuce's avatar
deuce committed
491
		if((uubuf=malloc(uulen))==NULL) {
492
			free(buf);
493
			JS_RESUMEREQUEST(cx, rc);
494
			return(JS_TRUE);
495
		}
496 497
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
498 499
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
500 501
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
502
		if(uulen>=0) {
503
			free(buf);
504
			buf=uubuf;
505
			len=uulen;
deuce's avatar
deuce committed
506
		}
507 508
		else
			free(uubuf);
509
	}
510
	JS_RESUMEREQUEST(cx, rc);
511

512
	str = JS_NewStringCopyN(cx, buf, len);
513
	free(buf);
514

515 516 517
	if(str==NULL)
		return(JS_FALSE);

518
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
519

520 521 522 523
	return(JS_TRUE);
}

static JSBool
524
js_readln(JSContext *cx, uintN argc, jsval *arglist)
525
{
526 527
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
528 529
	char*		cp;
	char*		buf;
530
	int32		len=512;
531
	JSString*	js_str;
532
	private_t*	p;
deuce's avatar
deuce committed
533
	jsrefcount	rc;
534

535
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
536

537
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
538
		return(JS_FALSE);
539
	}
540 541 542

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

544
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
545 546 547
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
548

549
	if((buf=malloc(len + 1))==NULL)
deuce's avatar
deuce committed
550
		return(JS_FALSE);
551

552
	rc=JS_SUSPENDREQUEST(cx);
553
	if(fgets(buf,len + 1,p->fp)!=NULL) {
554 555 556 557
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
558 559
		if(p->etx) {
			cp=strchr(buf,p->etx);
560
			if(cp) *cp=0;
561
		}
562 563
		if(p->rot13)
			rot13(buf);
564
		JS_RESUMEREQUEST(cx, rc);
565
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
566
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
567 568
	} else {
		JS_RESUMEREQUEST(cx, rc);
569
	}
deuce's avatar
deuce committed
570
	free(buf);
571 572 573 574 575

	return(JS_TRUE);
}

static JSBool
576
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
577
{
578 579
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
580 581 582
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
583
	int32		size=sizeof(DWORD);
584
	private_t*	p;
585
	int32		count=1;
586 587
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
588
	size_t		i;
589 590
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
591
	jsrefcount	rc;
592

593
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
594

595
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
596
		return(JS_FALSE);
597
	}
598 599 600 601

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

602
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
603
		if(!JS_ValueToInt32(cx,argv[0],&size))
604
			return(JS_FALSE);
605
		if(argc>1 && !JSVAL_NULL_OR_VOID(argv[1])) {
606
			if(!JS_ValueToInt32(cx,argv[1],&count))
607 608
				return(JS_FALSE);
		}
609
	}
610

611
	rc=JS_SUSPENDREQUEST(cx);
612 613 614
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
615
		JS_RESUMEREQUEST(cx, rc);
616 617 618 619 620 621
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
622
		JS_RESUMEREQUEST(cx, rc);
623 624 625 626 627 628 629 630 631 632
		return(JS_FALSE);
	}
	b=buffer;
	w=buffer;
	l=buffer;
	retlen=fread(buffer, size, count, p->fp);
	if(count==1) {
		if(retlen==1) {
			switch(size) {
				case sizeof(BYTE):
633
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
634 635
					break;
				case sizeof(WORD):
636 637 638 639
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
640
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
641 642
					break;
				case sizeof(DWORD):
643 644 645 646
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
647
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
648
					break;
649
			}
650 651 652
		}
	}
	else {
653
		JS_RESUMEREQUEST(cx, rc);
654 655 656 657 658 659 660 661
    	array = JS_NewArrayObject(cx, 0, NULL);

		for(i=0; i<retlen; i++) {
			switch(size) {
				case sizeof(BYTE):
					v = INT_TO_JSVAL(*(b++));
					break;
				case sizeof(WORD):
662 663 664 665
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
666 667 668
					v = INT_TO_JSVAL(*(w++));
					break;
				case sizeof(DWORD):
669 670 671 672
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
673
					v=UINT_TO_JSVAL(*(l++));
674
					break;
675
			}
deuce's avatar
deuce committed
676
        	if(!JS_SetElement(cx, array, i, &v)) {
677
				rc=JS_SUSPENDREQUEST(cx);
678
				goto end;
deuce's avatar
deuce committed
679
			}
680
		}
681
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
682
	}
683 684 685

end:
	free(buffer);
686
	JS_RESUMEREQUEST(cx, rc);
687 688 689 690
	return(JS_TRUE);
}

static JSBool
691
js_readall(JSContext *cx, uintN argc, jsval *arglist)
692
{
693
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
694 695
    jsint       len=0;
    JSObject*	array;
696 697
	private_t*	p;

698
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
699

700
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
701
		return(JS_FALSE);
702
	}
703

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

707
    array = JS_NewArrayObject(cx, 0, NULL);
708

709
    while(!feof(p->fp)) {
710 711
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
712
			break;
713
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
714
			break;
715
	}
716
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
717

718 719
    return(JS_TRUE);
}
720

721
static jsval get_value(JSContext *cx, char* value, bool blanks)
722 723 724 725 726
{
	char*	p;
	BOOL	f=FALSE;
	jsval	val;

727
	if(value==NULL || (*value==0 && !blanks))
728 729 730 731
		return(JSVAL_VOID);

	/* integer or float? */
	for(p=value;*p;p++) {
732
		if(*p=='.' && !f)
733
			f=TRUE;
734
		else if(!IS_DIGIT(*p))
735 736
			break;
	}
737
	if(p!=value && *p==0) {
738 739 740 741
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
742 743 744
		return(val);
	}
	/* hexadecimal number? */
745
	if(!strncmp(value,"0x",2)) {
746
		for(p=value+2;*p;p++)
747
			if(!isxdigit((uchar)*p))
748
				break;
749
		if(*p==0) {
750
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
751 752 753 754 755 756 757 758 759 760 761 762 763
			return(val);
		}
	}
	/* Boolean? */
	if(!stricmp(value,"true"))
		return(JSVAL_TRUE);
	if(!stricmp(value,"false"))
		return(JSVAL_FALSE);

	/* String */
	return(STRING_TO_JSVAL(JS_NewStringCopyZ(cx,value)));
}

deuce's avatar
deuce committed
764 765 766 767
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

deuce's avatar
deuce committed
768
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
769
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
770
	}
deuce's avatar
deuce committed
771 772 773
	return JSVAL_TO_DOUBLE(rval);
}

774
static JSBool
775
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
776
{
777 778
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
779
	char*	section=ROOT_SECTION;
780
	char*	key;
781
	char**	list;
782
	char	buf[INI_MAX_VALUE_LEN];
783 784
	int32	i;
	jsval	val;
785 786
	jsval	dflt=argv[2];
	private_t*	p;
787
	JSObject*	array;
788 789
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
790 791 792
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
793
	char*		cstr=NULL;
deuce's avatar
deuce committed
794
	char*		cstr2;
795

796 797
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

798
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
799 800 801
		return(JS_FALSE);
	}

802
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
803 804
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
805
	if(JS_IsExceptionPending(cx)) {
806 807
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
deuce's avatar
deuce committed
808
		return JS_FALSE;
809
	}
810 811 812 813 814 815
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
816
		FREE_AND_NULL(section);
817 818
		return JS_FALSE;
	}
819

820
	str_list_t ini = iniReadFile(p->fp);
821
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
822
		rc=JS_SUSPENDREQUEST(cx);
823
		cstr=iniGetString(ini,section,key,NULL,buf);
824 825
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
826
		strListFree(&ini);
827
		JS_RESUMEREQUEST(cx, rc);
828
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr, /* blanks */false));
829 830 831
		return(JS_TRUE);
	}

deuce's avatar
deuce committed
832 833
	if(JSVAL_IS_BOOLEAN(dflt)) {
		JS_SET_RVAL(cx,arglist,BOOLEAN_TO_JSVAL(
834
			iniGetBool(ini,section,key,JSVAL_TO_BOOLEAN(dflt))));
deuce's avatar
deuce committed
835 836 837 838
	}
	else if(JSVAL_IS_OBJECT(dflt)) {
		if((dflt_obj = JSVAL_TO_OBJECT(dflt))!=NULL && (strcmp("Date",JS_GetClass(cx, dflt_obj)->name)==0)) {
			tt=(time_t)(js_DateGetMsecSinceEpoch(cx,dflt_obj)/1000.0);
839
			rc=JS_SUSPENDREQUEST(cx);