1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Mozilla JavaScript Shell project.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
23 * Alex Fritze <alex@croczilla.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 #include "nsIJSRuntimeService.h"
41 #include "nsIServiceManager.h"
42 #include "nsIXPConnect.h"
43 #include "nsIProxyObjectManager.h"
44 #include "nsIScriptSecurityManager.h"
45 #include "nsIIOService.h"
47 #include "nsIChannel.h"
48 #include "nsThreadUtils.h"
49 #include "nsServiceManagerUtils.h"
50 #include "nsXPCOMCIDInternal.h"
52 #include "nsAutoPtr.h"
55 PRLogModuleInfo
*gJSShLog
= PR_NewLogModule("jssh");
58 //**********************************************************************
59 // Javascript Environment
61 const char *gWelcome
= "Welcome to the Mozilla JavaScript Shell!\n";
62 const char *gGoodbye
= "Goodbye!\n";
64 // GetJSShGlobal: helper for native js functions to obtain the global
66 PRBool
GetJSShGlobal(JSContext
*cx
, JSObject
*obj
, nsJSSh
** shell
)
71 // printf("GetJSShGlobal(cx=%p, obj=%p)\n", cx, obj);
73 JSObject
*parent
, *global
= obj
;
75 NS_ERROR("need a non-null obj to find script global");
79 // in most of our cases, 'global' is already the correct obj, since
80 // we use bound methods. For cases where we call
81 // GetJSShGlobal from an unbound method, we need to walk the
83 // XXX I think the comment above is obsolete. We only call
84 // GetJSShGlobal from bound methods, in which case the
85 // parent is the global obj. For non-bound methods, walking the
86 // parent chain to obtain the global object will only work when the
87 // method is rooted in the current script context, so it is not
88 // reliable (???). ASSERTION below to test the assumption. Once proven,
90 while ((parent
= JS_GetParent(cx
, global
))) {
91 NS_ERROR("Parent chain weirdness. Probably benign, but we should not reach this.");
93 // printf(" obj's parent = %p\n", parent);
98 // JSClass* clazz = JS_GET_CLASS(cx, global);
99 // if (!IS_WRAPPER_CLASS(clazz)) {
100 // NS_ERROR("the script global's class is not of the right type");
104 // XXX use GetWrappedNativeOfJSObject
105 nsIXPConnectWrappedNative
*wrapper
= static_cast<nsIXPConnectWrappedNative
*>(JS_GetPrivate(cx
, global
));
106 nsCOMPtr
<nsISupports
> native
;
107 wrapper
->GetNative(getter_AddRefs(native
));
108 nsCOMPtr
<nsIJSSh
> jssh
= do_QueryInterface(native
);
109 NS_ASSERTION(jssh
, "no jssh global");
110 *shell
= static_cast<nsJSSh
*>((nsIJSSh
*)(jssh
.get()));
115 my_ErrorReporter(JSContext
*cx
, const char *message
, JSErrorReport
*report
)
117 // xxx getting the global obj from the cx. will that give us grief?
118 JSObject
* obj
= JS_GetGlobalObject(cx
);
120 if (!GetJSShGlobal(cx
, obj
, &shell
)) return;
122 // XXX use JSErrorReport for better info
124 PRUint32 bytesWritten
;
125 if (shell
->mOutput
) {
126 if (shell
->mEmitHeader
) {
128 sprintf(buf
, "[%d]", strlen(message
));
129 shell
->mOutput
->Write(buf
, strlen(buf
), &bytesWritten
);
131 shell
->mOutput
->Write(message
, strlen(message
), &bytesWritten
);
136 Print(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
139 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
141 JSAutoRequest
ar(cx
);
143 PRUint32 bytesWritten
;
146 // nsCOMPtr<nsIThread> thread;
147 // nsIThread::GetCurrent(getter_AddRefs(thread));
148 // printf("printing on thread %p, shell %p, output %p, cx=%p, obj=%p\n", thread.get(), shell, shell->mOutput, cx, obj);
151 for (unsigned int i
=0; i
<argc
; ++i
) {
152 JSString
*str
= JS_ValueToString(cx
, argv
[i
]);
153 if (!str
) return JS_FALSE
;
154 if (shell
->mOutput
) {
155 if (shell
->mEmitHeader
) {
157 sprintf(buf
, "[%d]", JS_GetStringLength(str
));
158 shell
->mOutput
->Write(buf
, strlen(buf
), &bytesWritten
);
160 shell
->mOutput
->Write(JS_GetStringBytes(str
), JS_GetStringLength(str
), &bytesWritten
);
163 printf("%s", JS_GetStringBytes(str
)); // use cout if no output stream given.
165 // printf("%s", JS_GetStringBytes(str));
172 Quit(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
175 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
177 PRUint32 bytesWritten
;
180 shell
->mOutput
->Write(gGoodbye
, strlen(gGoodbye
), &bytesWritten
);
181 shell
->mQuit
= PR_TRUE
;
187 Load(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
191 JSAutoRequest
ar(cx
);
193 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
195 for (unsigned int i
=0; i
<argc
; ++i
) {
196 JSString
*str
= JS_ValueToString(cx
, argv
[i
]);
197 if (!str
) return JS_FALSE
;
198 //argv[i] = STRING_TO_JSVAL(str);
199 const char *url
= JS_GetStringBytes(str
);
200 if (!shell
->LoadURL(url
, rval
))
207 FlushEventQueue(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
210 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
212 NS_ProcessPendingEvents(nsnull
);
218 Suspend(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
221 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
223 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
225 PR_AtomicIncrement(&shell
->mSuspendCount
);
227 while (shell
->mSuspendCount
) {
229 NS_ProcessNextEvent(thread
);
236 Resume(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
239 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
241 PR_AtomicDecrement(&shell
->mSuspendCount
);
247 AddressOf(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
249 if (argc
!=1) return JS_FALSE
;
251 JSAutoRequest
ar(cx
);
253 // xxx If argv[0] is not an obj already, we'll get a transient
254 // address from JS_ValueToObject. Maybe we should throw an exception
258 if (!JS_ValueToObject(cx
, argv
[0], &arg_obj
)) {
263 sprintf(buf
, "%p", arg_obj
);
264 JSString
*str
= JS_NewStringCopyZ(cx
, buf
);
265 *rval
= STRING_TO_JSVAL(str
);
270 SetProtocol(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
272 if (argc
!=1) return JS_FALSE
;
274 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
276 JSAutoRequest
ar(cx
);
278 JSString
*str
= JS_ValueToString(cx
, argv
[0]);
279 if (!str
) return JS_FALSE
;
280 char *protocol
= JS_GetStringBytes(str
);
282 if (!strcmp(protocol
, "interactive")) {
283 shell
->mEmitHeader
= PR_FALSE
;
284 shell
->mPrompt
= NS_LITERAL_CSTRING("\n> ");
285 shell
->mProtocol
= protocol
;
287 else if (!strcmp(protocol
, "synchronous")) {
288 shell
->mEmitHeader
= PR_TRUE
;
289 shell
->mPrompt
= NS_LITERAL_CSTRING("\n> ");
290 shell
->mProtocol
= protocol
;
292 else if (!strcmp(protocol
, "plain")) {
293 shell
->mEmitHeader
= PR_FALSE
;
294 shell
->mPrompt
= NS_LITERAL_CSTRING("\n");
295 shell
->mProtocol
= protocol
;
297 else return JS_FALSE
;
303 GetProtocol(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
306 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
308 JSAutoRequest
ar(cx
);
310 JSString
*str
= JS_NewStringCopyZ(cx
, shell
->mProtocol
.get());
311 *rval
= STRING_TO_JSVAL(str
);
316 SetContextObj(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
319 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
321 JSAutoRequest
ar(cx
);
323 if (argc
!=1) return JS_FALSE
;
326 if (!JS_ValueToObject(cx
, argv
[0], &arg_obj
)) {
330 if (shell
->mContextObj
!= shell
->mGlobal
)
331 JS_RemoveRoot(cx
, &(shell
->mContextObj
));
333 shell
->mContextObj
= arg_obj
;
335 if (shell
->mContextObj
!= shell
->mGlobal
)
336 JS_AddRoot(cx
, &(shell
->mContextObj
));
342 DebugBreak(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
345 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
353 GetInputStream(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
356 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
358 JSAutoRequest
ar(cx
);
360 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID());
362 NS_ERROR("failed to get xpconnect service");
366 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
367 xpc
->WrapNative(cx
, shell
->mGlobal
, shell
->mInput
,
368 NS_GET_IID(nsIInputStream
),
369 getter_AddRefs(wrapper
));
371 NS_ERROR("could not wrap input stream object");
375 JSObject
* wrapper_jsobj
= nsnull
;
376 wrapper
->GetJSObject(&wrapper_jsobj
);
377 NS_ASSERTION(wrapper_jsobj
, "could not get jsobject of wrapped native");
379 *rval
= OBJECT_TO_JSVAL(wrapper_jsobj
);
385 GetOutputStream(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
388 if (!GetJSShGlobal(cx
, obj
, &shell
)) return JS_FALSE
;
390 JSAutoRequest
ar(cx
);
392 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID());
394 NS_ERROR("failed to get xpconnect service");
398 nsCOMPtr
<nsIXPConnectJSObjectHolder
> wrapper
;
399 xpc
->WrapNative(cx
, shell
->mGlobal
, shell
->mOutput
,
400 NS_GET_IID(nsIOutputStream
),
401 getter_AddRefs(wrapper
));
403 NS_ERROR("could not wrap output stream object");
407 JSObject
* wrapper_jsobj
= nsnull
;
408 wrapper
->GetJSObject(&wrapper_jsobj
);
409 NS_ASSERTION(wrapper_jsobj
, "could not get jsobject of wrapped native");
411 *rval
= OBJECT_TO_JSVAL(wrapper_jsobj
);
416 // these all need JSFUN_BOUND_METHOD flags, so that we can do
418 // win.p = print, where win is rooted in some other global
420 static JSFunctionSpec global_functions
[] = {
421 {"print", Print
, 1, JSFUN_BOUND_METHOD
, 0},
422 {"dump", Print
, 1, JSFUN_BOUND_METHOD
, 0},
423 {"quit", Quit
, 0, JSFUN_BOUND_METHOD
, 0},
424 {"exit", Quit
, 0, JSFUN_BOUND_METHOD
, 0},
425 {"load", Load
, 1, JSFUN_BOUND_METHOD
, 0},
426 {"suspend", Suspend
, 0, JSFUN_BOUND_METHOD
, 0},
427 {"resume", Resume
, 0, JSFUN_BOUND_METHOD
, 0},
428 {"flushEventQueue", FlushEventQueue
,0, JSFUN_BOUND_METHOD
, 0},
429 {"addressOf", AddressOf
, 1, 0, 0},
430 {"setProtocol", SetProtocol
, 1, JSFUN_BOUND_METHOD
, 0},
431 {"getProtocol", GetProtocol
, 0, JSFUN_BOUND_METHOD
, 0},
432 {"setContextObj", SetContextObj
, 1, JSFUN_BOUND_METHOD
, 0},
433 {"debugBreak", DebugBreak
, 0, JSFUN_BOUND_METHOD
, 0},
434 {"getInputStream", GetInputStream
, 0, JSFUN_BOUND_METHOD
, 0},
435 {"getOutputStream", GetOutputStream
,0, JSFUN_BOUND_METHOD
, 0},
436 {nsnull
, nsnull
, 0, 0, 0}
440 //**********************************************************************
441 // nsJSSh Implementation
443 nsJSSh::nsJSSh(nsIInputStream
* input
,
444 nsIOutputStream
*output
,
445 const nsACString
&startupURI
) :
446 mInput(input
), mOutput(output
), mQuit(PR_FALSE
), mStartupURI(startupURI
),
447 mSuspendCount(0), mPrompt("\n> "),
448 mEmitHeader(PR_FALSE
), mProtocol("interactive")
454 LOG(("JSSh: ~connection!\n"));
457 already_AddRefed
<nsIRunnable
>
458 CreateJSSh(nsIInputStream
* input
, nsIOutputStream
*output
,
459 const nsACString
&startupURI
)
461 nsIRunnable
* obj
= new nsJSSh(input
, output
, startupURI
);
466 //----------------------------------------------------------------------
467 // nsISupports methods:
469 NS_IMPL_THREADSAFE_ADDREF(nsJSSh
)
470 NS_IMPL_THREADSAFE_RELEASE(nsJSSh
)
472 NS_INTERFACE_MAP_BEGIN(nsJSSh
)
473 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIJSSh
)
474 NS_INTERFACE_MAP_ENTRY(nsIRunnable
)
475 NS_INTERFACE_MAP_ENTRY(nsIJSSh
)
476 NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal
)
477 NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable
)
481 //----------------------------------------------------------------------
482 // nsIRunnable methods:
484 NS_IMETHODIMP
nsJSSh::Run()
486 nsCOMPtr
<nsIJSSh
> proxied_shell
;
487 if (!NS_IsMainThread()) {
488 nsCOMPtr
<nsIProxyObjectManager
> pom
= do_GetService(NS_XPCOMPROXY_CONTRACTID
);
489 NS_ASSERTION(pom
, "uh-oh, no proxy object manager!");
490 pom
->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD
,
494 getter_AddRefs(proxied_shell
));
497 LOG(("jssh shell will block main thread!\n"));
498 proxied_shell
= this;
500 proxied_shell
->Init();
503 // read-eval-print loop
504 PRUint32 bytesWritten
;
505 if (mOutput
&& !mProtocol
.Equals(NS_LITERAL_CSTRING("plain")))
506 mOutput
->Write(gWelcome
, strlen(gWelcome
), &bytesWritten
);
510 mOutput
->Write(mPrompt
.get(), mPrompt
.Length(), &bytesWritten
);
512 // accumulate input until we get a compilable unit:
516 // nsCOMPtr<nsIThread> thread;
517 // nsIThread::GetCurrent(getter_AddRefs(thread));
518 // printf("blocking on thread %p\n", thread.get());
521 PRUint32 bytesRead
= 0;
522 mInput
->Read(mBuffer
+mBufferPtr
, 1, &bytesRead
);
527 // connection was terminated by the client
531 // XXX signal buffer overflow ??
532 // XXX ideally we want a dynamically resizing buffer.
533 }while (mBufferPtr
<cBufferSize
&&
534 (mBuffer
[mBufferPtr
-1]!=10 || (NS_SUCCEEDED(proxied_shell
->IsBufferCompilable(&iscompilable
)) && !iscompilable
)));
535 NS_ASSERTION(mBufferPtr
<cBufferSize
, "buffer overflow");
537 proxied_shell
->ExecuteBuffer();
541 proxied_shell
->Cleanup();
543 if (!NS_IsMainThread()) {
544 // Shutdown the current thread, which must be done from the main thread.
545 nsCOMPtr
<nsIThread
> thread
= do_GetCurrentThread();
546 nsCOMPtr
<nsIThread
> proxied_thread
;
547 nsCOMPtr
<nsIProxyObjectManager
> pom
= do_GetService(NS_XPCOMPROXY_CONTRACTID
);
548 NS_ASSERTION(pom
, "uh-oh, no proxy object manager!");
549 pom
->GetProxyForObject(NS_PROXY_TO_MAIN_THREAD
,
550 NS_GET_IID(nsIThread
),
553 getter_AddRefs(proxied_thread
));
555 proxied_thread
->Shutdown();
560 //----------------------------------------------------------------------
563 NS_IMETHODIMP
nsJSSh::Init()
565 nsCOMPtr
<nsIScriptSecurityManager
> ssm
= do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
);
567 NS_ERROR("failed to get script security manager");
568 return NS_ERROR_FAILURE
;
571 ssm
->GetSystemPrincipal(getter_AddRefs(mPrincipal
));
573 NS_ERROR("failed to get system principal");
574 return NS_ERROR_FAILURE
;
577 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID());
579 NS_ERROR("failed to get xpconnect service");
580 return NS_ERROR_FAILURE
;
583 // Let xpconnect resync its JSContext tracker. We do this before creating
584 // a new JSContext just in case the heap manager recycles the JSContext
586 xpc
->SyncJSContexts();
588 nsCOMPtr
<nsIJSRuntimeService
> rtsvc
= do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
589 // get the JSRuntime from the runtime svc
591 NS_ERROR("failed to get nsJSRuntimeService");
592 return NS_ERROR_FAILURE
;
595 JSRuntime
*rt
= nsnull
;
596 if (NS_FAILED(rtsvc
->GetRuntime(&rt
)) || !rt
) {
597 NS_ERROR("failed to get JSRuntime from nsJSRuntimeService");
598 return NS_ERROR_FAILURE
;
601 mJSContext
= JS_NewContext(rt
, 8192);
603 NS_ERROR("JS_NewContext failed");
604 return NS_ERROR_FAILURE
;
607 JSAutoRequest
ar(mJSContext
);
610 JS_SetOptions(mJSContext
, JS_GetOptions(mJSContext
) | JSOPTION_XML
);
612 // Always use the latest js version
613 JS_SetVersion(mJSContext
, JSVERSION_LATEST
);
615 mContextStack
= do_GetService("@mozilla.org/js/xpc/ContextStack;1");
616 if (!mContextStack
) {
617 NS_ERROR("failed to get the nsThreadJSContextStack service");
618 return NS_ERROR_FAILURE
;
621 JS_SetErrorReporter(mJSContext
, my_ErrorReporter
);
623 nsCOMPtr
<nsIXPConnectJSObjectHolder
> holder
;
624 xpc
->InitClassesWithNewWrappedGlobal(mJSContext
, (nsIJSSh
*)this,
625 NS_GET_IID(nsISupports
),
627 getter_AddRefs(holder
));
629 NS_ERROR("global initialization failed");
630 return NS_ERROR_FAILURE
;
633 holder
->GetJSObject(&mGlobal
);
635 NS_ERROR("bad global object");
636 return NS_ERROR_FAILURE
;
638 mContextObj
= mGlobal
;
640 if (!JS_DefineFunctions(mJSContext
, mGlobal
, global_functions
)) {
641 NS_ERROR("failed to initialise global functions");
642 return NS_ERROR_FAILURE
;
645 if (!mStartupURI
.IsEmpty())
646 LoadURL(mStartupURI
.get());
651 NS_IMETHODIMP
nsJSSh::Cleanup()
653 nsCOMPtr
<nsIXPConnect
> xpc
= do_GetService(nsIXPConnect::GetCID());
655 NS_ERROR("failed to get xpconnect service");
656 return NS_ERROR_FAILURE
;
660 JSAutoRequest
ar(mJSContext
);
662 if (mContextObj
!= mGlobal
)
663 JS_RemoveRoot(mJSContext
, &(mContextObj
));
665 JS_ClearScope(mJSContext
, mGlobal
);
669 JS_DestroyContext(mJSContext
);
670 xpc
->SyncJSContexts();
674 NS_IMETHODIMP
nsJSSh::ExecuteBuffer()
677 // nsCOMPtr<nsIThread> thread;
678 // nsIThread::GetCurrent(getter_AddRefs(thread));
679 // printf("executing on thread %p\n", thread.get());
682 JS_BeginRequest(mJSContext
);
683 JS_ClearPendingException(mJSContext
);
684 JSPrincipals
*jsprincipals
;
685 mPrincipal
->GetJSPrincipals(mJSContext
, &jsprincipals
);
687 if(NS_FAILED(mContextStack
->Push(mJSContext
))) {
688 NS_ERROR("failed to push the current JSContext on the nsThreadJSContextStack");
689 return NS_ERROR_FAILURE
;
692 JSScript
*script
= JS_CompileScriptForPrincipals(mJSContext
, mContextObj
, jsprincipals
, mBuffer
, mBufferPtr
, "interactive", 0);
696 if (JS_ExecuteScript(mJSContext
, mContextObj
, script
, &result
) && result
!=JSVAL_VOID
&& mOutput
) {
697 // XXX for some wrapped native objects the following code will crash; probably because the
698 // native object is getting released before we reach this:
699 JSString
*str
= JS_ValueToString(mJSContext
, result
);
701 nsDependentString
chars(reinterpret_cast<const PRUnichar
*>
702 (JS_GetStringChars(str
)),
703 JS_GetStringLength(str
));
704 NS_ConvertUTF16toUTF8
cstr(chars
);
705 PRUint32 bytesWritten
;
706 mOutput
->Write(cstr
.get(), cstr
.Length(), &bytesWritten
);
709 JS_DestroyScript(mJSContext
, script
);
713 mContextStack
->Pop(&oldcx
);
714 NS_ASSERTION(oldcx
== mJSContext
, "JS thread context push/pop mismatch");
716 JSPRINCIPALS_DROP(mJSContext
, jsprincipals
);
718 JS_EndRequest(mJSContext
);
723 NS_IMETHODIMP
nsJSSh::IsBufferCompilable(PRBool
*_retval
)
725 JSAutoRequest
ar(mJSContext
);
726 *_retval
= JS_BufferIsCompilableUnit(mJSContext
, mContextObj
, mBuffer
, mBufferPtr
);
730 //----------------------------------------------------------------------
731 // nsIScriptObjectPrincipal methods:
734 nsJSSh::GetPrincipal()
739 //----------------------------------------------------------------------
740 // nsIXPCScriptable methods:
742 #define XPC_MAP_CLASSNAME nsJSSh
743 #define XPC_MAP_QUOTED_CLASSNAME "JSSh"
744 #define XPC_MAP_WANT_NEWRESOLVE
745 #define XPC_MAP_FLAGS nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY | \
746 nsIXPCScriptable::USE_JSSTUB_FOR_DELPROPERTY | \
747 nsIXPCScriptable::USE_JSSTUB_FOR_SETPROPERTY | \
748 nsIXPCScriptable::DONT_ENUM_STATIC_PROPS | \
749 nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE | \
750 nsIXPCScriptable::DONT_REFLECT_INTERFACE_NAMES
751 #include "xpc_map_end.h" /* This will #undef the above */
753 /* PRBool newResolve (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx,
754 in JSObjectPtr obj, in JSVal id, in PRUint32 flags, out JSObjectPtr objp); */
756 nsJSSh::NewResolve(nsIXPConnectWrappedNative
*wrapper
,
757 JSContext
* cx
, JSObject
* obj
,
758 jsval id
, PRUint32 flags
,
759 JSObject
* *objp
, PRBool
*_retval
)
763 JSAutoRequest
ar(cx
);
765 *_retval
= JS_ResolveStandardClass(cx
, obj
, id
, &resolved
);
766 if (*_retval
&& resolved
)
771 //----------------------------------------------------------------------
772 // Implementation helpers:
774 PRBool
nsJSSh::LoadURL(const char *url
, jsval
* retval
)
776 nsCOMPtr
<nsIIOService
> ioserv
= do_GetService(NS_IOSERVICE_CONTRACTID
);
778 NS_ERROR("could not get io service");
782 nsCOMPtr
<nsIChannel
> channel
;
783 ioserv
->NewChannel(nsDependentCString(url
), nsnull
, nsnull
, getter_AddRefs(channel
));
785 NS_ERROR("could not create channel");
789 nsCOMPtr
<nsIInputStream
> instream
;
790 channel
->Open(getter_AddRefs(instream
));
792 NS_ERROR("could not open stream");
797 nsAutoArrayPtr
<char> buf(new char[1024]);
799 NS_ERROR("could not alloc buffer");
803 PRUint32 bytesRead
= 0;
806 if (NS_FAILED(instream
->Read(buf
, 1024, &bytesRead
))) {
807 NS_ERROR("stream read error");
810 buffer
.Append(buf
, bytesRead
);
811 LOG(("appended %d bytes:\n%s", bytesRead
, buffer
.get()));
812 } while (bytesRead
> 0);
814 LOG(("loaded %d bytes:\n%s", buffer
.Length(), buffer
.get()));
816 JS_BeginRequest(mJSContext
);
817 JSPrincipals
*jsprincipals
;
818 mPrincipal
->GetJSPrincipals(mJSContext
, &jsprincipals
);
820 if(NS_FAILED(mContextStack
->Push(mJSContext
))) {
821 NS_ERROR("failed to push the current JSContext on the nsThreadJSContextStack");
822 return NS_ERROR_FAILURE
;
826 JSBool ok
= JS_EvaluateScriptForPrincipals(mJSContext
, mContextObj
,
827 jsprincipals
, buffer
.get(),
830 JSPRINCIPALS_DROP(mJSContext
, jsprincipals
);
833 mContextStack
->Pop(&oldcx
);
834 NS_ASSERTION(oldcx
== mJSContext
, "JS thread context push/pop mismatch");
836 if (ok
&& retval
) *retval
=result
;
838 JS_EndRequest(mJSContext
);