nscliveconnect.cpp
来自「一个基于alice开发的机器人」· C++ 代码 · 共 828 行 · 第 1/2 页
CPP
828 行
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the implementation providing nsIFactory XP-COM interface.
*
*/
#include <stdlib.h>
#include <string.h>
#include "prtypes.h"
#include "prprf.h"
#include "prlog.h"
#include "jsj_private.h"
#include "jsjava.h"
#include "jscntxt.h" /* For js_ReportErrorAgain().*/
#include "netscape_javascript_JSObject.h" /* javah-generated headers */
#include "nsISecurityContext.h"
#include "nsIServiceManager.h"
#include "nsIJSContextStack.h"
PR_BEGIN_EXTERN_C
/* A captured JavaScript error, created when JS_ReportError() is called while
running JavaScript code that is itself called from Java. */
struct CapturedJSError {
char * message;
JSErrorReport report; /* Line # of error, etc. */
jthrowable java_exception; /* Java exception, error, or null */
CapturedJSError * next; /* Next oldest captured JS error */
};
PR_END_EXTERN_C
#include "nsCLiveconnect.h"
#include "jsinterp.h" // XXX private API so we can auto-push a JSStackFrame
#include "nsIScriptSecurityManager.h"
#include "nsIPrincipal.h"
#include "nsNetUtil.h"
#include "nsISecurityContext.h"
#include "prmem.h"
static nsresult
CreatePrincipal(nsISupports* aSecuritySupports,
nsIScriptSecurityManager* aSecMan,
nsIPrincipal ** aOutPrincipal)
{
nsresult rv;
nsCOMPtr<nsISecurityContext> securityContext(
do_QueryInterface(aSecuritySupports, &rv));
if (NS_FAILED(rv)) return rv;
char originBuf1[512];
char* origin = originBuf1;
size_t originSize = sizeof(originBuf1);
rv = securityContext->GetOrigin(origin, originSize);
while (NS_FAILED(rv) && originSize < 65536U)
{ // Try allocating a larger buffer on the heap
if (origin != originBuf1)
PR_Free(origin);
originSize *= 2;
origin = (char*)PR_Malloc(originSize);
if (!origin)
return NS_ERROR_OUT_OF_MEMORY;
rv = securityContext->GetOrigin(origin, originSize);
}
if (NS_FAILED(rv))
{
if (origin != originBuf1)
PR_Free(origin);
return rv;
}
nsCOMPtr<nsIURI> originURI;
rv = NS_NewURI(getter_AddRefs(originURI), origin);
if (origin != originBuf1)
PR_Free(origin);
if (NS_FAILED(rv)) return rv;
return aSecMan->GetCodebasePrincipal(originURI, aOutPrincipal);
}
/***************************************************************************/
// A class to put on the stack to manage JS contexts when we are entering JS.
// This pushes and pops the given context
// with the nsThreadJSContextStack service as this object goes into and out
// of scope. It is optimized to not push/pop the cx if it is already on top
// of the stack. We need to push the JSContext when we enter JS because the
// JS security manager looks on the context stack for permissions information.
class AutoPushJSContext
{
public:
AutoPushJSContext(nsISupports* aSecuritySupports,
JSContext *cx);
~AutoPushJSContext();
nsresult ResultOfPush() { return mPushResult; };
private:
nsCOMPtr<nsIJSContextStack> mContextStack;
JSContext* mContext;
JSStackFrame mFrame;
nsresult mPushResult;
};
AutoPushJSContext::AutoPushJSContext(nsISupports* aSecuritySupports,
JSContext *cx)
: mContext(cx), mPushResult(NS_OK)
{
mContextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if(mContextStack)
{
JSContext* currentCX;
if(NS_SUCCEEDED(mContextStack->Peek(¤tCX)))
{
// Is the current context already on the stack?
if(cx == currentCX)
mContextStack = nsnull;
else
{
mContextStack->Push(cx);
// Leave the reference to the mContextStack to
// indicate that we need to pop it in our dtor.
}
}
}
nsCOMPtr<nsIScriptSecurityManager> secMan(
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &mPushResult));
if (NS_FAILED(mPushResult))
return;
nsCOMPtr<nsIPrincipal> principal;
if (aSecuritySupports)
mPushResult = CreatePrincipal(aSecuritySupports, secMan, getter_AddRefs(principal));
else
mPushResult = secMan->GetPrincipalFromContext(cx, getter_AddRefs(principal));
if (NS_FAILED(mPushResult))
{
JS_ReportError(cx, "failed to get a principal");
return;
}
// See if Javascript is enabled for the current window
PRBool jsEnabled = PR_FALSE;
mPushResult = secMan->CanExecuteScripts(cx, principal, &jsEnabled);
if (!jsEnabled)
mPushResult = NS_ERROR_FAILURE;
memset(&mFrame, 0, sizeof(mFrame));
if (NS_SUCCEEDED(mPushResult))
{
// See if there are any scripts on the stack.
// If not, we need to add a dummy frame with a principal.
PRBool hasScript = PR_FALSE;
JSStackFrame* tempFP = cx->fp;
while (tempFP)
{
if (tempFP->script)
{
hasScript = PR_TRUE;
break;
}
tempFP = tempFP->down;
};
if (!hasScript)
{
JSPrincipals* jsprinc;
principal->GetJSPrincipals(cx, &jsprinc);
mFrame.script = JS_CompileScriptForPrincipals(cx, JS_GetGlobalObject(cx),
jsprinc, "", 0, "", 1);
JSPRINCIPALS_DROP(cx, jsprinc);
if (mFrame.script)
{
mFrame.down = cx->fp;
cx->fp = &mFrame;
}
else
mPushResult = NS_ERROR_OUT_OF_MEMORY;
}
}
}
AutoPushJSContext::~AutoPushJSContext()
{
if (mContextStack)
mContextStack->Pop(nsnull);
if (mFrame.script)
mContext->fp = mFrame.down;
}
////////////////////////////////////////////////////////////////////////////
// from nsISupports and AggregatedQueryInterface:
// Thes macro expands to the aggregated query interface scheme.
NS_IMPL_AGGREGATED(nsCLiveconnect)
NS_METHOD
nsCLiveconnect::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
if (aIID.Equals(NS_GET_IID(nsISupports))) {
*aInstancePtr = GetInner();
}
else if (aIID.Equals(NS_GET_IID(nsILiveconnect))) {
*aInstancePtr = NS_STATIC_CAST(nsILiveconnect*, this);
}
else {
*aInstancePtr = nsnull;
return NS_NOINTERFACE;
}
NS_ADDREF((nsISupports*) *aInstancePtr);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////
// from nsILiveconnect:
/**
* get member of a Native JSObject for a given name.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
* @param name - Name of a member.
* @param pjobj - return parameter as a java object representing
* the member. If it is a basic data type it is converted to
* a corresponding java type. If it is a NJSObject, then it is
* wrapped up as java wrapper netscape.javascript.JSObject.
*/
NS_METHOD
nsCLiveconnect::GetMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize length, void* principalsArray[],
int numPrincipals, nsISupports *securitySupports, jobject *pjobj)
{
if(jEnv == NULL || obj == 0)
{
return NS_ERROR_FAILURE;
}
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = NULL;
jobject member = NULL;
jsval js_val;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
JSErrorReporter saved_state = NULL;
jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
if (!jsj_env)
return NS_ERROR_FAILURE;
AutoPushJSContext autopush(securitySupports, cx);
if (NS_FAILED(autopush.ResultOfPush()))
goto done;
if (!name) {
JS_ReportError(cx, "illegal null member name");
member = NULL;
goto done;
}
if (!JS_GetUCProperty(cx, js_obj, name, length, &js_val))
goto done;
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
&dummy_cost, &member, &dummy_bool);
done:
if (!jsj_exit_js(cx, jsj_env, saved_state))
return NS_ERROR_FAILURE;
*pjobj = member;
return NS_OK;
}
/**
* get member of a Native JSObject for a given index.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
* @param index - Index of a member.
* @param pjobj - return parameter as a java object representing
* the member.
*/
NS_METHOD
nsCLiveconnect::GetSlot(JNIEnv *jEnv, jsobject obj, jint slot, void* principalsArray[],
int numPrincipals, nsISupports *securitySupports, jobject *pjobj)
{
if(jEnv == NULL || obj == 0)
{
return NS_ERROR_FAILURE;
}
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = NULL;
jobject member = NULL;
jsval js_val;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
JSErrorReporter saved_state = NULL;
jsj_env = jsj_enter_js(jEnv, mJavaClient, NULL, &cx, NULL, &saved_state, principalsArray, numPrincipals, securitySupports);
if (!jsj_env)
return NS_ERROR_FAILURE;
AutoPushJSContext autopush(securitySupports, cx);
if (NS_FAILED(autopush.ResultOfPush()))
goto done;
// =-= sudu: check to see if slot can be passed in as is.
// Should it be converted to a jsint?
if (!JS_GetElement(cx, js_obj, slot, &js_val))
goto done;
if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
&dummy_cost, &member, &dummy_bool))
goto done;
done:
if (!jsj_exit_js(cx, jsj_env, saved_state))
return NS_ERROR_FAILURE;
*pjobj = member;
return NS_OK;
}
/**
* set member of a Native JSObject for a given name.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
* @param name - Name of a member.
* @param jobj - Value to set. If this is a basic data type, it is converted
* using standard JNI calls but if it is a wrapper to a JSObject
* then a internal mapping is consulted to convert to a NJSObject.
*/
NS_METHOD
nsCLiveconnect::SetMember(JNIEnv *jEnv, jsobject obj, const jchar *name, jsize length, jobject java_obj, void* principalsArray[],
int numPrincipals, nsISupports *securitySupports)
{
if(jEnv == NULL || obj == 0)
{
return NS_ERROR_FAILURE;
}
JSJavaThreadState *jsj_env = NULL;
JSObjectHandle *handle = (JSObjectHandle*)obj;
JSObject *js_obj = handle->js_obj;
JSContext *cx = NULL;
jsval js_val;
JSErrorReporter saved_state = NULL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?