Compare commits

..

1 Commits

Author SHA1 Message Date
(no author)
973a54719f This commit was manufactured by cvs2svn to create tag 'Last140MergeSource'.
git-svn-id: svn://10.0.0.236/tags/Last140MergeSource@10343 18797224-902f-48f8-a5cc-f745e15eee43
1998-09-18 02:28:51 +00:00
67 changed files with 11682 additions and 12368 deletions

View File

@@ -0,0 +1,5 @@
# This is a list of local files which get copied to the mozilla:dist directory
#
jsjava.h
nsILiveconnect.h

View File

@@ -0,0 +1,89 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../..
include $(DEPTH)/config/config.mk
ifdef NSJVM
DIRS = classes
endif
MODULE = java
LIBRARY_NAME = jsj
REQUIRES = java js applet nspr img util layer xpcom
CSRCS = jsj.c \
jsj_JSObject.c \
jsj_JavaArray.c \
jsj_JavaClass.c \
jsj_JavaMember.c \
jsj_JavaObject.c \
jsj_JavaPackage.c \
jsj_array.c \
jsj_class.c \
jsj_convert.c \
jsj_field.c \
jsj_hash.c \
jsj_method.c \
jsj_utils.c \
nsCLiveconnect.c \
nsCLiveconnectFactory.c
LLIBS=$(LIBNSPR) $(DIST)/lib/js$(MOZ_BITS)$(VERSION_NUMBER).lib \
$(DIST)/lib/xpcom32.lib
ifdef NSJVM
JNI_GEN = netscape.javascript.JSObject netscape.javascript.JSException
endif
EXPORTS = jsjava.h \
$(JNI_GEN_DIR)/netscape_javascript_JSObject.h \
$(JNI_GEN_DIR)/netscape_javascript_JSException.h \
nsILiveconnect.h \
$(NULL)
include $(DEPTH)/config/rules.mk
######################################################################
# Generate jsj_nodl.c (so that you can check it in)
# These make rules only works on IRIX...sigh
ifeq ($(OS_ARCH),IRIX)
jsj_nodl.c: $(OBJDIR)/stubs.o Makefile $(DEPTH)/config/nodl.pl
rm -f $@
$(PERL) $(DEPTH)/config/nodl.pl "jsj_nodl_tab" \
`nm -Bn $(OBJDIR)/stubs.o | egrep Java_.*_stub | awk '{print $$3;}'` > $@
endif
ifdef JAVA_OR_OJI
$(OBJDIR)/stubs.o: \
$(JNI_GEN_DIR)/netscape_javascript_JSObject.c \
$(JNI_GEN_DIR)/netscape_javascript_JSException.c \
$(NULL)
else
$(OBJDIR)/stubs.o:
endif

View File

@@ -0,0 +1,90 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/config.mk
ifdef NSJVM
DIRS = classes
endif
MODULE = java
LIBRARY_NAME = jsj
REQUIRES = java js applet nspr img util layer xpcom caps oji plugin
CSRCS = jsj.c \
jsj_JSObject.c \
jsj_JavaArray.c \
jsj_JavaClass.c \
jsj_JavaMember.c \
jsj_JavaObject.c \
jsj_JavaPackage.c \
jsj_array.c \
jsj_class.c \
jsj_convert.c \
jsj_field.c \
jsj_hash.c \
jsj_method.c \
jsj_utils.c
nsCLiveconnect.c \
nsCLiveconnectFactory.c
ifdef NSJVM
JNI_GEN = netscape.javascript.JSObject netscape.javascript.JSException
endif
EXPORTS = $(srcdir)/jsjava.h \
$(srcdir)/$(JNI_GEN_DIR)/netscape_javascript_JSObject.h \
$(srcdir)/$(JNI_GEN_DIR)/netscape_javascript_JSException.h \
$(NULL)
include $(topsrcdir)/config/rules.mk
######################################################################
# Generate jsj_nodl.c (so that you can check it in)
# These make rules only works on IRIX...sigh
ifeq ($(OS_ARCH),IRIX)
jsj_nodl.c: $(OBJDIR)/stubs.o Makefile $(topsrcdir)/config/nodl.pl
rm -f $@
$(PERL) $(topsrcdir)/config/nodl.pl "jsj_nodl_tab" \
`nm -Bn $(OBJDIR)/stubs.o | egrep Java_.*_stub | awk '{print $$3;}'` > $@
endif
ifdef JAVA_OR_OJI
$(OBJDIR)/stubs.o: \
$(JRI_GEN_DIR)/netscape_javascript_JSObject.c \
$(JRI_GEN_DIR)/netscape_javascript_JSException.c \
$(NULL)
else
$(OBJDIR)/stubs.o:
endif

View File

@@ -0,0 +1,14 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class netscape_javascript_JSException */
#ifndef _Included_netscape_javascript_JSException
#define _Included_netscape_javascript_JSException
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,102 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class netscape_javascript_JSObject */
#ifndef _Included_netscape_javascript_JSObject
#define _Included_netscape_javascript_JSObject
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: netscape_javascript_JSObject
* Method: initClass
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_initClass
(JNIEnv *, jclass);
/*
* Class: netscape_javascript_JSObject
* Method: getMember
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getMember
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: getSlot
* Signature: (I)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getSlot
(JNIEnv *, jobject, jint);
/*
* Class: netscape_javascript_JSObject
* Method: setMember
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setMember
(JNIEnv *, jobject, jstring, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: setSlot
* Signature: (ILjava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setSlot
(JNIEnv *, jobject, jint, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: removeMember
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_removeMember
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: call
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_call
(JNIEnv *, jobject, jstring, jobjectArray);
/*
* Class: netscape_javascript_JSObject
* Method: eval
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_eval
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: toString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_netscape_javascript_JSObject_toString
(JNIEnv *, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: getWindow
* Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getWindow
(JNIEnv *, jclass, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: finalize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_finalize
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,65 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../../..
MODULE = java
#
# the idea is that the install phase for those modules will
# make their own signed jar files
# there are some exceptions here that we deal with
# stuff in modules and in ns/js/jsj
#
JMODS = netscape/javascript netscape/javascript/adapters
#
# JDIRS is dependant on JAVA_DESTPATH in config/rules.m[a]k.
# Be sure to touch that directory if you add a new directory to
# JDIRS, or else it will not build. FIXME
#
JDIRS = $(JMODS)
JAR_JSJ = jsj10.jar
JAR_JSJ_CLASSES = $(JMODS)
#
# jars to build at install time
#
JARS = $(JAR_JSJ)
include $(DEPTH)/config/rules.mk
JAVA_SOURCEPATH = $(DEPTH)/js/src/liveconnect/classes
doc::
$(JAVADOC) -d $(DIST)/doc netscape.javascript
natives_list:: FORCE
rm -rf $@
find . -name "*.class" -print | sed 's@\./\(.*\)\.class$$@\1@' | \
sed 's@/@.@g' | xargs $(JVH) -natives | sort > $@
check_natives:: natives_list
rm -f found_natives
nm -B ../$(OBJDIR)/*.o \
| egrep "Java.*_stub" | awk '{ print $$3; }' | sort > found_natives
diff found_natives natives_list
FORCE:

View File

@@ -0,0 +1,70 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = java
#
# the idea is that the install phase for those modules will
# make their own signed jar files
# there are some exceptions here that we deal with
# stuff in modules and in ns/js/jsj
#
JMODS = netscape/javascript netscape/javascript/adapters
#
# JDIRS is dependant on JAVA_DESTPATH in config/rules.m[a]k.
# Be sure to touch that directory if you add a new directory to
# JDIRS, or else it will not build. FIXME
#
JDIRS = $(JMODS)
JAR_JSJ = jsj10.jar
JAR_JSJ_CLASSES = $(JMODS)
#
# jars to build at install time
#
JARS = $(JAR_JSJ)
include $(topsrcdir)/config/rules.mk
JAVA_SOURCEPATH = $(topsrcdir)/js/src/liveconnect/classes
doc::
$(JAVADOC) -d $(DIST)/doc netscape.javascript
natives_list:: FORCE
rm -rf $@
find . -name "*.class" -print | sed 's@\./\(.*\)\.class$$@\1@' | \
sed 's@/@.@g' | xargs $(JVH) -natives | sort > $@
check_natives:: natives_list
rm -f found_natives
nm -B ../$(OBJDIR)/*.o \
| egrep "Java.*_stub" | awk '{ print $$3; }' | sort > found_natives
diff found_natives natives_list
FORCE:

View File

@@ -0,0 +1,78 @@
#!gmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
IGNORE_MANIFEST=1
#
#//------------------------------------------------------------------------
#//
#// Makefile to build the JavaScript-Java tree
#//
#//------------------------------------------------------------------------
DEPTH = ..\..\..\..
JAVA_SOURCEPATH=$(DEPTH)\js\src\liveconnect\classes
#//------------------------------------------------------------------------
#//
#// Define the files necessary to build the target (ie. OBJS)
#//
#//------------------------------------------------------------------------
include <$(DEPTH)\config\config.mak>
JMOZ = \
netscape/javascript \
$(NULL)
all::
MODULE=java
JMODS=netscape/javascript
!ifdef JAVA_OR_NSJVM
JDIRS=$(JMODS)
JAR_JSJ_CLASSES=$(JMODS)
JAR_NAME = jsj10.jar
!endif
include <$(DEPTH)\config\rules.mak>
!ifdef JAVA_OR_NSJVM
install::
cd $(JAVA_DESTPATH)
@echo +++ building/updating $(JAR_NAME)
-for %i in ($(JAR_JSJ_CLASSES:/=\)) do @$(ZIP_PROG) $(ZIP_FLAGS) $(JAR_NAME) %i\*.class
cd $(MAKEDIR)
!ifdef REGENERATE
install::
cd $(JAVA_DESTPATH)
@echo +++ updating $(DEPTH)\nav-java\stubs\classes\$(JAR_NAME) for checkin
-for %i in ($(JAR_JSJ_CLASSES:/=\)) do @$(ZIP_PROG) $(ZIP_FLAGS) ..\..\nav-java\stubs\classes\$(JAR_NAME) %i\*.class
cd $(MAKEDIR)
!endif
!endif
javadoc:
-mkdir $(XPDIST)\javadoc 2> NUL
echo $(JAVADOC) -sourcepath . -d $(XPDIST)\javadoc $(JDIRS:/=.)
$(JAVADOC) -sourcepath . -d $(XPDIST)\javadoc $(JDIRS:/=.)

View File

@@ -0,0 +1,56 @@
/* Insert copyright and license here 19** */
package netscape.javascript;
/**
* JSException is an exception which is thrown when JavaScript code
* returns an error.
*/
public
class JSException extends Exception {
String filename;
int lineno;
String source;
int tokenIndex;
/**
* Constructs a JSException without a detail message.
* A detail message is a String that describes this particular exception.
*/
public JSException() {
super();
filename = "unknown";
lineno = 0;
source = "";
tokenIndex = 0;
}
/**
* Constructs a JSException with a detail message.
* A detail message is a String that describes this particular exception.
* @param s the detail message
*/
public JSException(String s) {
super(s);
filename = "unknown";
lineno = 0;
source = "";
tokenIndex = 0;
}
/**
* Constructs a JSException with a detail message and all the
* other info that usually comes with a JavaScript error.
* @param s the detail message
*/
public JSException(String s, String filename, int lineno,
String source, int tokenIndex) {
super(s);
this.filename = filename;
this.lineno = lineno;
this.source = source;
this.tokenIndex = tokenIndex;
}
}

View File

@@ -0,0 +1,150 @@
/* -*- Mode: C; tab-width: 4; -*- */
/* Insert copyright and license here 19** */
/* more doc todo:
* threads
* gc
*
*
*/
package netscape.javascript;
import java.applet.Applet;
/**
* JSObject allows Java to manipulate objects that are
* defined in JavaScript.
* Values passed from Java to JavaScript are converted as
* follows:<ul>
* <li>JSObject is converted to the original JavaScript object
* <li>Any other Java object is converted to a JavaScript wrapper,
* which can be used to access methods and fields of the java object.
* Converting this wrapper to a string will call the toString method
* on the original object, converting to a number will call the
* floatValue method if possible and fail otherwise. Converting
* to a boolean will try to call the booleanValue method in the
* same way.
* <li>Java arrays are wrapped with a JavaScript object that understands
* array.length and array[index]
* <li>A Java boolean is converted to a JavaScript boolean
* <li>Java byte, char, short, int, long, float, and double are converted
* to JavaScript numbers
* </ul>
* Values passed from JavaScript to Java are converted as follows:<ul>
* <li>objects which are wrappers around java objects are unwrapped
* <li>other objects are wrapped with a JSObject
* <li>strings, numbers and booleans are converted to String, Float,
* and Boolean objects respectively
* </ul>
* This means that all JavaScript values show up as some kind
* of java.lang.Object in Java. In order to make much use of them,
* you will have to cast them to the appropriate subclass of Object,
* e.g. <code>(String) window.getMember("name");</code> or
* <code>(JSObject) window.getMember("document");</code>.
*/
public final class JSObject {
/* the internal object data */
private int internal;
/**
* initialize
*/
private static native void initClass();
static {
// On MRJ, this property won't exist, because the library is preloaded.
String liveConnectLibrary = System.getProperty("netscape.jsj.dll", null);
if (liveConnectLibrary != null) {
System.loadLibrary(liveConnectLibrary);
initClass();
}
}
/**
* it is illegal to construct a JSObject manually
*/
private JSObject(int jsobj_addr) {
internal = jsobj_addr;
}
/**
* Retrieves a named member of a JavaScript object.
* Equivalent to "this.<i>name</i>" in JavaScript.
*/
public native Object getMember(String name);
/**
* Retrieves an indexed member of a JavaScript object.
* Equivalent to "this[<i>index</i>]" in JavaScript.
*/
// public Object getMember(int index) { return getSlot(index); }
public native Object getSlot(int index);
/**
* Sets a named member of a JavaScript object.
* Equivalent to "this.<i>name</i> = <i>value</i>" in JavaScript.
*/
public native void setMember(String name, Object value);
/**
* Sets an indexed member of a JavaScript object.
* Equivalent to "this[<i>index</i>] = <i>value</i>" in JavaScript.
*/
// public void setMember(int index, Object value) {
// setSlot(index, value);
// }
public native void setSlot(int index, Object value);
/**
* Removes a named member of a JavaScript object.
*/
public native void removeMember(String name);
/**
* Calls a JavaScript method.
* Equivalent to "this.<i>methodName</i>(<i>args</i>[0], <i>args</i>[1], ...)" in JavaScript.
*/
public native Object call(String methodName, Object args[]);
/**
* Evaluates a JavaScript expression. The expression is a string
* of JavaScript source code which will be evaluated in the context
* given by "this".
*/
public native Object eval(String s);
/**
* Converts a JSObject to a String.
*/
public native String toString();
// should use some sort of identifier rather than String
// is "property" the right word?
// native String[] listProperties();
/**
* get a JSObject for the window containing the given applet
*/
public static native JSObject getWindow(Applet applet);
/**
* Finalization decrements the reference count on the corresponding
* JavaScript object.
*/
protected native void finalize();
/**
* Override java.lang.Object.equals() because identity is not preserved
* with instances of JSObject.
*/
public boolean equals(Object obj) {
JSObject jsobj;
if (!(obj instanceof JSObject))
return false;
jsobj = (JSObject)obj;
return (internal == jsobj.internal);
}
}

View File

@@ -0,0 +1,37 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* ** */
/**
* The JSProxy interface allows applets and plugins to
* share javascript contexts.
*/
package netscape.javascript;
import java.applet.Applet;
public interface JSProxy {
Object getMember(JSObject jso, String name);
Object getSlot(JSObject jso, int index);
void setMember(JSObject jso, String name, Object value);
void setSlot(JSObject jso, int index, Object value);
void removeMember(JSObject jso, String name);
Object call(JSObject jso, String methodName, Object args[]);
Object eval(JSObject jso, String s);
String toString(JSObject jso);
JSObject getWindow(Applet applet);
}

View File

@@ -0,0 +1,31 @@
package netscape.javascript;
/**
* Runs a JavaScript object with a run() method in a separate thread.
*/
public class JSRunnable implements Runnable {
private JSObject runnable;
public JSRunnable(JSObject runnable) {
this.runnable = runnable;
synchronized(this) {
new Thread(this).start();
try {
this.wait();
} catch (InterruptedException ie) {
}
}
}
public void run() {
try {
runnable.call("run", null);
synchronized(this) {
notifyAll();
}
} catch (Throwable t) {
System.err.println(t);
t.printStackTrace(System.err);
}
}
}

View File

@@ -0,0 +1,38 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* ** */
package netscape.javascript;
import java.io.*;
public class JSUtil {
/* Return the stack trace of an exception or error as a String */
public static String getStackTrace(Throwable t) {
ByteArrayOutputStream captureStream;
PrintStream p;
captureStream = new ByteArrayOutputStream();
p = new PrintStream(captureStream);
t.printStackTrace(p);
p.flush();
return captureStream.toString();
}
}

View File

@@ -0,0 +1,876 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the top-level initialization code and the implementation of the
* public API.
*
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
#include "jsjava.h" /* LiveConnect external API */
/*
* At certain times during initialization, there may be no JavaScript context
* available to direct error reports to, in which case the error messages
* are sent to this function. The caller is responsible for free'ing
* the js_error_msg argument.
*/
static void
report_java_initialization_error(JNIEnv *jEnv, const char *js_error_msg)
{
const char *error_msg, *java_error_msg;
java_error_msg = NULL;
#if 0 /* This can never work here, because jsj_GetJavaErrorMessage relies on
jlThrowable_toString which is set up by the initialization that calls
this function. */
if (jEnv) {
java_error_msg = jsj_GetJavaErrorMessage(jEnv);
(*jEnv)->ExceptionClear(jEnv);
}
#endif
if (java_error_msg) {
error_msg = PR_smprintf("initialization error: %s (%s)\n",
js_error_msg, java_error_msg);
free((void*)java_error_msg);
} else {
error_msg = PR_smprintf("initialization error: %s\n",
js_error_msg);
}
jsj_LogError(error_msg);
}
/*
* Opaque JVM handles to Java classes and methods required for Java reflection.
* These are computed and cached during initialization.
*/
jclass jlObject; /* java.lang.Object */
jclass jlrMethod; /* java.lang.reflect.Method */
jclass jlrField; /* java.lang.reflect.Field */
jclass jlVoid; /* java.lang.Void */
jclass jlrConstructor; /* java.lang.reflect.Constructor */
jclass jlThrowable; /* java.lang.Throwable */
jclass jlSystem; /* java.lang.System */
jclass jlClass; /* java.lang.Class */
jclass jlBoolean; /* java.lang.Boolean */
jclass jlDouble; /* java.lang.Double */
jclass jlString; /* java.lang.String */
jclass njJSObject; /* netscape.javascript.JSObject */
jclass njJSException; /* netscape.javascript.JSException */
jclass njJSUtil; /* netscape.javascript.JSUtil */
jmethodID jlClass_getMethods; /* java.lang.Class.getMethods() */
jmethodID jlClass_getConstructors; /* java.lang.Class.getConstructors() */
jmethodID jlClass_getFields; /* java.lang.Class.getFields() */
jmethodID jlClass_getName; /* java.lang.Class.getName() */
jmethodID jlClass_getComponentType; /* java.lang.Class.getComponentType() */
jmethodID jlClass_getModifiers; /* java.lang.Class.getModifiers() */
jmethodID jlClass_isArray; /* java.lang.Class.isArray() */
jmethodID jlrMethod_getName; /* java.lang.reflect.Method.getName() */
jmethodID jlrMethod_getParameterTypes; /* java.lang.reflect.Method.getParameterTypes() */
jmethodID jlrMethod_getReturnType; /* java.lang.reflect.Method.getReturnType() */
jmethodID jlrMethod_getModifiers; /* java.lang.reflect.Method.getModifiers() */
jmethodID jlrConstructor_getParameterTypes; /* java.lang.reflect.Constructor.getParameterTypes() */
jmethodID jlrConstructor_getModifiers; /* java.lang.reflect.Constructor.getModifiers() */
jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
jmethodID jlDouble_Double; /* java.lang.Double constructor */
jmethodID jlDouble_doubleValue; /* java.lang.Double.doubleValue() */
jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */
jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
jmethodID jlSystem_identityHashCode; /* java.lang.System.identityHashCode() */
jobject jlVoid_TYPE; /* java.lang.Void.TYPE value */
jmethodID njJSException_JSException; /* netscape.javascript.JSexception constructor */
jmethodID njJSObject_JSObject; /* netscape.javascript.JSObject constructor */
jmethodID njJSUtil_getStackTrace; /* netscape.javascript.JSUtil.getStackTrace() */
jfieldID njJSObject_internal; /* netscape.javascript.JSObject.internal */
jfieldID njJSException_lineno; /* netscape.javascript.JSException.lineno */
jfieldID njJSException_tokenIndex; /* netscape.javascript.JSException.tokenIndex */
jfieldID njJSException_source; /* netscape.javascript.JSException.source */
jfieldID njJSException_filename; /* netscape.javascript.JSException.filename */
/* Obtain a reference to a Java class */
#define LOAD_CLASS(qualified_name, class) \
{ \
jclass _##class = (*jEnv)->FindClass(jEnv, #qualified_name); \
if (_##class == 0) { \
(*jEnv)->ExceptionClear(jEnv); \
report_java_initialization_error(jEnv, \
"Can't load class " #qualified_name); \
return JS_FALSE; \
} \
class = (*jEnv)->NewGlobalRef(jEnv, _##class); \
}
/* Obtain a methodID reference to a Java method or constructor */
#define _LOAD_METHOD(qualified_class, method, mvar, signature, class, is_static)\
if (is_static) { \
class##_##mvar = \
(*jEnv)->GetStaticMethodID(jEnv, class, #method, signature); \
} else { \
class##_##mvar = \
(*jEnv)->GetMethodID(jEnv, class, #method, signature); \
} \
if (class##_##mvar == 0) { \
report_java_initialization_error(jEnv, \
"Can't get mid for " #qualified_class "." #method "()"); \
return JS_FALSE; \
}
/* Obtain a methodID reference to a Java instance method */
#define LOAD_METHOD(qualified_class, method, signature, class) \
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_FALSE)
/* Obtain a methodID reference to a Java static method */
#define LOAD_STATIC_METHOD(qualified_class, method, signature, class) \
_LOAD_METHOD(qualified_class, method, method, signature, class, JS_TRUE)
/* Obtain a methodID reference to a Java constructor */
#define LOAD_CONSTRUCTOR(qualified_class, method, signature, class) \
_LOAD_METHOD(qualified_class,<init>, method, signature, class, JS_FALSE)
/* Obtain a fieldID reference to a Java instance or static field */
#define _LOAD_FIELDID(qualified_class, field, signature, class, is_static) \
if (is_static) { \
class##_##field = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
} else { \
class##_##field = (*jEnv)->GetFieldID(jEnv, class, #field, signature);\
} \
if (class##_##field == 0) { \
report_java_initialization_error(jEnv, \
"Can't get fid for " #qualified_class "." #field); \
return JS_FALSE; \
}
/* Obtain a fieldID reference to a Java instance field */
#define LOAD_FIELDID(qualified_class, field, signature, class) \
_LOAD_FIELDID(qualified_class, field, signature, class, JS_FALSE)
/* Obtain the value of a static field in a Java class */
#define LOAD_FIELD_VAL(qualified_class, field, signature, class, type) \
{ \
jfieldID field_id; \
field_id = (*jEnv)->GetStaticFieldID(jEnv, class, #field, signature);\
if (field_id == 0) { \
report_java_initialization_error(jEnv, \
"Can't get fid for " #qualified_class "." #field); \
return JS_FALSE; \
} \
class##_##field = \
(*jEnv)->GetStatic##type##Field(jEnv, class, field_id); \
if (class##_##field == 0) { \
report_java_initialization_error(jEnv, \
"Can't read static field " #qualified_class "." #field); \
return JS_FALSE; \
} \
}
/* Obtain the value of a static field in a Java class, which is known to
contain an object value. */
#define LOAD_FIELD_OBJ(qualified_class, field, signature, class) \
LOAD_FIELD_VAL(qualified_class, field, signature, class, Object); \
class##_##field = (*jEnv)->NewGlobalRef(jEnv, class##_##field);
/*
* Load the Java classes, and the method and field descriptors required for Java reflection.
* Returns JS_TRUE on success, JS_FALSE on failure.
*/
static JSBool
init_java_VM_reflection(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
{
/* Load Java system classes and method, including java.lang.reflect classes */
LOAD_CLASS(java/lang/Object, jlObject);
LOAD_CLASS(java/lang/Class, jlClass);
LOAD_CLASS(java/lang/reflect/Method, jlrMethod);
LOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
LOAD_CLASS(java/lang/reflect/Field, jlrField);
LOAD_CLASS(java/lang/Throwable, jlThrowable);
LOAD_CLASS(java/lang/System, jlSystem);
LOAD_CLASS(java/lang/Boolean, jlBoolean);
LOAD_CLASS(java/lang/Double, jlDouble);
LOAD_CLASS(java/lang/String, jlString);
LOAD_CLASS(java/lang/Void, jlVoid);
LOAD_METHOD(java.lang.Class, getMethods, "()[Ljava/lang/reflect/Method;",jlClass);
LOAD_METHOD(java.lang.Class, getConstructors, "()[Ljava/lang/reflect/Constructor;",jlClass);
LOAD_METHOD(java.lang.Class, getFields, "()[Ljava/lang/reflect/Field;", jlClass);
LOAD_METHOD(java.lang.Class, getName, "()Ljava/lang/String;", jlClass);
LOAD_METHOD(java.lang.Class, isArray, "()Z", jlClass);
LOAD_METHOD(java.lang.Class, getComponentType, "()Ljava/lang/Class;", jlClass);
LOAD_METHOD(java.lang.Class, getModifiers, "()I", jlClass);
LOAD_METHOD(java.lang.reflect.Method, getName, "()Ljava/lang/String;", jlrMethod);
LOAD_METHOD(java.lang.reflect.Method, getParameterTypes, "()[Ljava/lang/Class;", jlrMethod);
LOAD_METHOD(java.lang.reflect.Method, getReturnType, "()Ljava/lang/Class;", jlrMethod);
LOAD_METHOD(java.lang.reflect.Method, getModifiers, "()I", jlrMethod);
LOAD_METHOD(java.lang.reflect.Constructor, getParameterTypes, "()[Ljava/lang/Class;", jlrConstructor);
LOAD_METHOD(java.lang.reflect.Constructor, getModifiers, "()I", jlrConstructor);
LOAD_METHOD(java.lang.reflect.Field, getName, "()Ljava/lang/String;", jlrField);
LOAD_METHOD(java.lang.reflect.Field, getType, "()Ljava/lang/Class;", jlrField);
LOAD_METHOD(java.lang.reflect.Field, getModifiers, "()I", jlrField);
LOAD_METHOD(java.lang.Throwable, toString, "()Ljava/lang/String;", jlThrowable);
LOAD_METHOD(java.lang.Throwable, getMessage, "()Ljava/lang/String;", jlThrowable);
LOAD_METHOD(java.lang.Double, doubleValue, "()D", jlDouble);
LOAD_METHOD(java.lang.Boolean, booleanValue, "()Z", jlBoolean);
LOAD_STATIC_METHOD(java.lang.System, identityHashCode, "(Ljava/lang/Object;)I", jlSystem);
LOAD_CONSTRUCTOR(java.lang.Boolean, Boolean, "(Z)V", jlBoolean);
LOAD_CONSTRUCTOR(java.lang.Double, Double, "(D)V", jlDouble);
LOAD_FIELD_OBJ(java.lang.Void, TYPE, "Ljava/lang/Class;", jlVoid);
return JS_TRUE;
}
#if XP_MAC
/**
* Workaround for the fact that MRJ loads a different instance of the shared library.
*/
#include "netscape_javascript_JSObject.h"
static JSObject_RegisterNativeMethods(JNIEnv* jEnv)
{
// Manually load the required native methods.
static JNINativeMethod nativeMethods[] = {
"initClass", "()V", (void*)&Java_netscape_javascript_JSObject_initClass,
"getMember", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getMember,
"getSlot", "(I)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_getSlot,
"setMember", "(Ljava/lang/String;Ljava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setMember,
"setSlot", "(ILjava/lang/Object;)V", (void*)&Java_netscape_javascript_JSObject_setSlot,
"removeMember", "(Ljava/lang/String;)V", (void*)&Java_netscape_javascript_JSObject_removeMember,
"call", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_call,
"eval", "(Ljava/lang/String;)Ljava/lang/Object;", (void*)&Java_netscape_javascript_JSObject_eval,
"toString", "()Ljava/lang/String;", (void*)&Java_netscape_javascript_JSObject_toString,
"getWindow", "(Ljava/applet/Applet;)Lnetscape/javascript/JSObject;", (void*)&Java_netscape_javascript_JSObject_getWindow,
"finalize", "()V", (void*)&Java_netscape_javascript_JSObject_finalize,
/* "equals", "(Ljava/lang/Object;)Z", (void*)&Java_netscape_javascript_JSObject_equals */
};
(*jEnv)->RegisterNatives(jEnv, njJSObject, nativeMethods, sizeof(nativeMethods) / sizeof(JNINativeMethod));
if ((*jEnv)->ExceptionOccurred(jEnv)) {
report_java_initialization_error(jEnv, "Couldn't initialize JSObject native methods.");
(*jEnv)->ExceptionClear(jEnv);
}
/* call the initClass method, since we nailed the static initializer for testing. */
Java_netscape_javascript_JSObject_initClass(jEnv, njJSObject);
}
#endif
/* Load Netscape-specific Java extension classes, methods, and fields */
static JSBool
init_netscape_java_classes(JSJavaVM *jsjava_vm, JNIEnv *jEnv)
{
LOAD_CLASS(netscape/javascript/JSObject, njJSObject);
LOAD_CLASS(netscape/javascript/JSException, njJSException);
LOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
#if XP_MAC
JSObject_RegisterNativeMethods(jEnv);
#endif
LOAD_CONSTRUCTOR(netscape.javascript.JSObject,
JSObject, "(I)V", njJSObject);
LOAD_CONSTRUCTOR(netscape.javascript.JSException,
JSException, "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)V",
njJSException);
LOAD_FIELDID(netscape.javascript.JSObject,
internal, "I", njJSObject);
LOAD_FIELDID(netscape.javascript.JSException,
lineno, "I", njJSException);
LOAD_FIELDID(netscape.javascript.JSException,
tokenIndex, "I", njJSException);
LOAD_FIELDID(netscape.javascript.JSException,
source, "Ljava/lang/String;", njJSException);
LOAD_FIELDID(netscape.javascript.JSException,
filename, "Ljava/lang/String;", njJSException);
LOAD_STATIC_METHOD(netscape.javascript.JSUtil,
getStackTrace, "(Ljava/lang/Throwable;)Ljava/lang/String;",
njJSUtil);
return JS_TRUE;
}
JSJavaVM *jsjava_vm_list = NULL;
/*
* Called once per Java VM, this function initializes the classes, fields, and
* methods required for Java reflection. If java_vm is NULL, a new Java VM is
* created, using the provided classpath in addition to any default classpath.
* The classpath argument is ignored, however, if java_vm_arg is non-NULL.
*/
JSJavaVM *
JSJ_ConnectToJavaVM(SystemJavaVM *java_vm_arg, void* initargs)
{
SystemJavaVM* java_vm;
JSJavaVM *jsjava_vm;
JNIEnv *jEnv;
PR_ASSERT(JSJ_callbacks);
PR_ASSERT(JSJ_callbacks->attach_current_thread);
PR_ASSERT(JSJ_callbacks->detach_current_thread);
PR_ASSERT(JSJ_callbacks->get_java_vm);
jsjava_vm = (JSJavaVM*)malloc(sizeof(JSJavaVM));
if (!jsjava_vm)
return NULL;
memset(jsjava_vm, 0, sizeof(JSJavaVM));
java_vm = java_vm_arg;
/* If a Java VM was passed in, try to attach to it on the current thread. */
if (java_vm) {
jEnv = JSJ_callbacks->attach_current_thread(java_vm);
if (jEnv == NULL) {
jsj_LogError("Failed to attach to Java VM thread\n");
free(jsjava_vm);
return NULL;
}
}
else {
PRBool ok;
PR_ASSERT(JSJ_callbacks->create_java_vm);
PR_ASSERT(JSJ_callbacks->destroy_java_vm);
ok = JSJ_callbacks->create_java_vm(&java_vm, &jEnv, initargs);
if (!ok || java_vm == NULL) {
jsj_LogError("Failed to create Java VM\n");
free(jsjava_vm);
return NULL;
}
/* Remember that we created the VM so that we know to destroy it later */
jsjava_vm->jsj_created_java_vm = JS_TRUE;
}
jsjava_vm->java_vm = java_vm;
jsjava_vm->main_thread_env = jEnv;
/* Load the Java classes, and the method and field descriptors required for
Java reflection. */
if (!init_java_VM_reflection(jsjava_vm, jEnv)) {
JSJ_DisconnectFromJavaVM(jsjava_vm);
return NULL;
}
/*
* JVM initialization for netscape.javascript.JSObject is performed
* independently of the other classes that are initialized in
* init_java_VM_reflection, because we allow it to fail. In the case
* of failure, LiveConnect is still operative, but only when calling
* from JS to Java and not vice-versa.
*/
init_netscape_java_classes(jsjava_vm, jEnv);
/* Put this VM on the list of all created VMs */
jsjava_vm->next = jsjava_vm_list;
jsjava_vm_list = jsjava_vm;
return jsjava_vm;
}
JSJCallbacks *JSJ_callbacks = NULL;
/* Called once to set up callbacks for all instances of LiveConnect */
void
JSJ_Init(JSJCallbacks *callbacks)
{
PR_ASSERT(callbacks);
JSJ_callbacks = callbacks;
}
/*
* Initialize the provided JSContext by setting up the JS classes necessary for
* reflection and by defining JavaPackage objects for the default Java packages
* as properties of global_obj. Additional packages may be pre-defined by
* setting the predefined_packages argument. (Pre-defining a Java package at
* initialization time is not necessary, but it will make package lookup faster
* and, more importantly, will avoid unnecessary network accesses if classes
* are being loaded over the network.)
*/
JSBool
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
JavaPackageDef *predefined_packages)
{
/* Initialize the JavaScript classes used for reflection */
if (!jsj_init_JavaObject(cx, global_obj))
return JS_FALSE;
/* if (!jsj_init_JavaMember(cx, global_obj))
return JS_FALSE; */
if (!jsj_init_JavaPackage(cx, global_obj, predefined_packages))
return JS_FALSE;
if (!jsj_init_JavaClass(cx, global_obj))
return JS_FALSE;
if (!jsj_init_JavaArray(cx, global_obj))
return JS_FALSE;
if (!jsj_init_JavaMember(cx, global_obj))
return JS_FALSE;
return JS_TRUE;
}
/* Eliminate a reference to a Java class */
#define UNLOAD_CLASS(qualified_name, class) \
if (class) { \
(*jEnv)->DeleteGlobalRef(jEnv, class); \
class = NULL; \
}
/*
* This routine severs the connection to a Java VM, freeing all related resources.
* It shouldn't be called until the global scope has been cleared in all related
* JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
* GC is performed. Otherwise, accessed to free'ed memory could result.
*/
void
JSJ_DisconnectFromJavaVM(JSJavaVM *jsjava_vm)
{
JNIEnv *jEnv;
SystemJavaVM *java_vm;
JSJavaVM *j, **jp;
java_vm = jsjava_vm->java_vm;
jEnv = jsjava_vm->main_thread_env;
/* Drop all references to Java objects and classes */
jsj_DiscardJavaObjReflections(jEnv);
jsj_DiscardJavaClassReflections(jEnv);
if (jsjava_vm->jsj_created_java_vm) {
(void)JSJ_callbacks->destroy_java_vm(java_vm, jEnv);
} else {
UNLOAD_CLASS(java/lang/Object, jlObject);
UNLOAD_CLASS(java/lang/Class, jlClass);
UNLOAD_CLASS(java/lang/reflect/Method, jlrMethod);
UNLOAD_CLASS(java/lang/reflect/Constructor, jlrConstructor);
UNLOAD_CLASS(java/lang/reflect/Field, jlrField);
UNLOAD_CLASS(java/lang/Throwable, jlThrowable);
UNLOAD_CLASS(java/lang/System, jlSystem);
UNLOAD_CLASS(java/lang/Boolean, jlBoolean);
UNLOAD_CLASS(java/lang/Double, jlDouble);
UNLOAD_CLASS(java/lang/String, jlString);
UNLOAD_CLASS(java/lang/Void, jlVoid);
UNLOAD_CLASS(netscape/javascript/JSObject, njJSObject);
UNLOAD_CLASS(netscape/javascript/JSException, njJSException);
UNLOAD_CLASS(netscape/javascript/JSUtil, njJSUtil);
}
/* Remove this VM from the list of all JSJavaVM objects. */
for (jp = &jsjava_vm_list; (j = *jp) != NULL; jp = &j->next) {
if (j == jsjava_vm) {
*jp = jsjava_vm->next;
break;
}
}
PR_ASSERT(j);
free(jsjava_vm);
}
static JSJavaThreadState *thread_list = NULL;
static JSJavaThreadState *
new_jsjava_thread_state(JSJavaVM *jsjava_vm, const char *thread_name, JNIEnv *jEnv)
{
JSJavaThreadState *jsj_env;
jsj_env = (JSJavaThreadState *)malloc(sizeof(JSJavaThreadState));
if (!jsj_env)
return NULL;
memset(jsj_env, 0, sizeof(JSJavaThreadState));
jsj_env->jEnv = jEnv;
jsj_env->jsjava_vm = jsjava_vm;
if (thread_name)
jsj_env->name = strdup(thread_name);
/* THREADSAFETY - need to protect against races */
jsj_env->next = thread_list;
thread_list = jsj_env;
return jsj_env;
}
static JSJavaThreadState *
find_jsjava_thread(JNIEnv *jEnv)
{
JSJavaThreadState *e, **p, *jsj_env;
jsj_env = NULL;
/* THREADSAFETY - need to protect against races in manipulating the thread list */
/* Search for the thread state among the list of all created
LiveConnect threads */
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
if (e->jEnv == jEnv) {
jsj_env = e;
*p = jsj_env->next;
break;
}
}
/* Move a found thread to head of list for faster search next time. */
if (jsj_env)
thread_list = jsj_env;
return jsj_env;
}
PR_IMPLEMENT(JSJavaThreadState *)
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *name, JNIEnv **java_envp)
{
JNIEnv *jEnv;
SystemJavaVM *java_vm;
JSJavaThreadState *jsj_env;
/* Try to attach a Java thread to the current native thread */
java_vm = jsjava_vm->java_vm;
jEnv = JSJ_callbacks->attach_current_thread(java_vm);
if (jEnv == NULL)
return NULL;
/* If we found an existing thread state, just return it. */
jsj_env = find_jsjava_thread(jEnv);
if (jsj_env)
return jsj_env;
/* Create a new wrapper around the thread/VM state */
jsj_env = new_jsjava_thread_state(jsjava_vm, name, jEnv);
if (java_envp)
*java_envp = jEnv;
return jsj_env;
}
static JSJavaVM *
map_java_vm_to_jsjava_vm(SystemJavaVM *java_vm)
{
JSJavaVM *v;
for (v = jsjava_vm_list; v; v = v->next) {
if (v->java_vm == java_vm)
return v;
}
return NULL;
}
/*
* Unfortunately, there's no standard means to associate any private data with
* a JNI thread environment, so we need to use the Java environment pointer as
* the key in a lookup table that maps it to a JSJavaThreadState structure,
* where we store all our per-thread private data. If no existing thread state
* is found, a new one is created.
*
* If an error occurs, returns NULL and sets the errp argument to an error
* message, which the caller is responsible for free'ing.
*/
JSJavaThreadState *
jsj_MapJavaThreadToJSJavaThreadState(JNIEnv *jEnv, char **errp)
{
JSJavaThreadState *jsj_env;
SystemJavaVM *java_vm;
JSJavaVM *jsjava_vm;
/* If we found an existing thread state, just return it. */
jsj_env = find_jsjava_thread(jEnv);
if (jsj_env)
return jsj_env;
/* No one set up a LiveConnect thread state for a given Java thread.
Invoke the callback to create one on-the-fly. */
/* First, figure out which Java VM is calling us */
java_vm = JSJ_callbacks->get_java_vm(jEnv);
if (jsjava_vm == NULL)
return NULL;
/* Get our private JavaVM data */
jsjava_vm = map_java_vm_to_jsjava_vm(java_vm);
if (!jsjava_vm) {
*errp = PR_smprintf("Total weirdness: No JSJavaVM wrapper ever created "
"for JavaVM 0x%08x", java_vm);
return NULL;
}
jsj_env = new_jsjava_thread_state(jsjava_vm, NULL, jEnv);
if (!jsj_env)
return NULL;
return jsj_env;
}
/*
* This function is used to specify a particular JSContext as *the* JavaScript
* execution environment to be used when LiveConnect is accessed from the given
* Java thread, i.e. by using one of the methods of netscape.javascript.JSObject.
* (There can only be one such JS context for a given Java thread. To
* multiplex JSContexts among a single thread, this function must be called
* before Java is invoked on that thread.) The return value is the previous
* context associated with the given Java thread.
*/
PR_IMPLEMENT(JSContext *)
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env)
{
JSContext *old_context;
old_context = jsj_env->cx;
jsj_env->cx = cx;
return old_context;
}
PR_IMPLEMENT(JSBool)
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env)
{
SystemJavaVM *java_vm;
JNIEnv* jEnv;
JSJavaThreadState *e, **p;
/* Disassociate the current native thread from its corresponding Java thread */
java_vm = jsj_env->jsjava_vm->java_vm;
jEnv = jsj_env->jEnv;
if (!JSJ_callbacks->detach_current_thread(java_vm, jEnv))
return JS_FALSE;
/* Destroy the LiveConnect execution environment passed in */
jsj_ClearPendingJSErrors(jsj_env);
/* THREADSAFETY - need to protect against races */
for (p = &thread_list; (e = *p) != NULL; p = &(e->next)) {
if (e == jsj_env) {
*p = jsj_env->next;
break;
}
}
free(jsj_env);
return JS_TRUE;
}
JSBool
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp)
{
JNIEnv *jEnv;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, vp);
}
/*===========================================================================*/
#ifndef MOZILLA_CLIENT
/* The convenience functions below present a complete, but simplified
LiveConnect API which is designed to handle the special case of a single
Java-VM, single-threaded operation, and use of only one JSContext. */
/* We can get away with global variables in our single-threaded,
single-JSContext case. */
static JSJavaVM * the_jsj_vm = NULL;
static JSContext * the_cx = NULL;
static JSJavaThreadState * the_jsj_thread = NULL;
static JSObject * the_global_js_obj = NULL;
/* Trivial implementation of callback function */
static JSJavaThreadState *
default_map_js_context_to_jsj_thread(JSContext *cx, char **errp)
{
return the_jsj_thread;
}
/* Trivial implementation of callback function */
static JSContext *
default_map_jsj_thread_to_js_context(JSJavaThreadState *jsj_env, JNIEnv *jEnv, char **errp)
{
return the_cx;
}
/* Trivial implementation of callback function */
static JSObject *
default_map_java_object_to_js_object(JNIEnv *jEnv, jobject hint, char **errp)
{
return the_global_js_obj;
}
static PRBool PR_CALLBACK
default_create_java_vm(SystemJavaVM* *jvm, JNIEnv* *initialEnv, void* initargs)
{
jint err;
const char* user_classpath = (const char*)initargs;
/* No Java VM supplied, so create our own */
JDK1_1InitArgs vm_args;
/* Magic constant indicates JRE version 1.1 */
vm_args.version = 0x00010001;
JNI_GetDefaultJavaVMInitArgs(&vm_args);
/* Prepend the classpath argument to the default JVM classpath */
if (user_classpath) {
#ifdef XP_UNIX
const char *full_classpath = PR_smprintf("%s:%s", user_classpath, vm_args.classpath);
#else
const char *full_classpath = PR_smprintf("%s;%s", user_classpath, vm_args.classpath);
#endif
if (!full_classpath) {
return PR_FALSE;
}
vm_args.classpath = (char*)full_classpath;
}
err = JNI_CreateJavaVM((JavaVM**)jvm, initialEnv, &vm_args);
return err == 0;
}
static PRBool PR_CALLBACK
default_destroy_java_vm(SystemJavaVM* jvm, JNIEnv* initialEnv)
{
JavaVM* java_vm = (JavaVM*)jvm;
jint err = (*java_vm)->DestroyJavaVM(java_vm);
return err == 0;
}
static JNIEnv* PR_CALLBACK
default_attach_current_thread(SystemJavaVM* jvm)
{
JavaVM* java_vm = (JavaVM*)jvm;
JNIEnv* env = NULL;
jint err = (*java_vm)->AttachCurrentThread(java_vm, &env, NULL);
return env;
}
static PRBool PR_CALLBACK
default_detach_current_thread(SystemJavaVM* jvm, JNIEnv* env)
{
JavaVM* java_vm = (JavaVM*)jvm;
/* assert that env is the JNIEnv of the current thread */
jint err = (*java_vm)->DetachCurrentThread(java_vm);
return err == 0;
}
static SystemJavaVM* PR_CALLBACK
default_get_java_vm(JNIEnv* env)
{
JavaVM* java_vm = NULL;
jint err = (*env)->GetJavaVM(env, &java_vm);
return (SystemJavaVM*)java_vm;
}
/* Trivial implementations of callback functions */
JSJCallbacks jsj_default_callbacks = {
default_map_jsj_thread_to_js_context,
default_map_js_context_to_jsj_thread,
default_map_java_object_to_js_object,
NULL,
NULL,
NULL,
NULL,
default_create_java_vm,
default_destroy_java_vm,
default_attach_current_thread,
default_detach_current_thread,
default_get_java_vm
};
/*
* Initialize the provided JSContext by setting up the JS classes necessary for
* reflection and by defining JavaPackage objects for the default Java packages
* as properties of global_obj. If java_vm is NULL, a new Java VM is
* created, using the provided classpath in addition to any default classpath.
* The classpath argument is ignored, however, if java_vm is non-NULL.
*/
JSBool
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj, SystemJavaVM *java_vm, const char *classpath)
{
JNIEnv *jEnv;
PR_ASSERT(!the_jsj_vm);
the_jsj_vm = JSJ_ConnectToJavaVM(java_vm, (void*)classpath);
if (!the_jsj_vm)
return JS_FALSE;
JSJ_Init(&jsj_default_callbacks);
if (!JSJ_InitJSContext(cx, global_obj, NULL))
goto error;
the_cx = cx;
the_global_js_obj = global_obj;
the_jsj_thread = JSJ_AttachCurrentThreadToJava(the_jsj_vm, "main thread", &jEnv);
if (!the_jsj_thread)
goto error;
JSJ_SetDefaultJSContextForJavaThread(cx, the_jsj_thread);
return JS_TRUE;
error:
JSJ_SimpleShutdown();
return JS_FALSE;
}
/*
* Free up all LiveConnect resources. Destroy the Java VM if it was
* created by LiveConnect.
*/
PR_IMPLEMENT(void)
JSJ_SimpleShutdown()
{
PR_ASSERT(the_jsj_vm);
JSJ_DisconnectFromJavaVM(the_jsj_vm);
the_jsj_vm = NULL;
the_cx = NULL;
the_global_js_obj = NULL;
the_jsj_thread = NULL;
}
#endif /* MOZILLA_CLIENT */

View File

@@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
// Version stamp for this .DLL
#include <windows.h>
#include <ver.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4 // major, minor, release (alpha 1), build #
PRODUCTVERSION 4
FILEFLAGSMASK 0
FILEFLAGS 0 // final version
FILEOS VOS_DOS_WINDOWS16
FILETYPE VFT_DLL
FILESUBTYPE 0 // not used
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual
BEGIN
VALUE "CompanyName", "Netscape Communications Corporation\0"
VALUE "FileDescription", "Netscape 16-bit JavaScript-Java Module\0"
VALUE "FileVersion", "4.0\0"
VALUE "InternalName", "JSJ1640\0"
VALUE "LegalCopyright", "Copyright Netscape Communications. 1994-96\0"
VALUE "LegalTrademarks", "Netscape, Mozilla\0"
VALUE "OriginalFilename","JSJ1640.DLL\0"
VALUE "ProductName", "NETSCAPE\0"
VALUE "ProductVersion", "4.0\0"
END
END
END

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,403 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the definition of the JavaScript JavaArray class.
* Instances of JavaArray are used to reflect Java arrays.
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
/* Shorthands for ASCII (7-bit) decimal and hex conversion. */
#define JS7_ISDEC(c) (((c) >= '0') && ((c) <= '9'))
#define JS7_UNDEC(c) ((c) - '0')
/*
* Convert any jsval v to an integer jsval if ToString(v)
* contains a base-10 integer that fits into 31 bits.
* Otherwise return v.
*/
static jsval
try_convert_to_jsint(JSContext *cx, jsval idval)
{
const jschar *cp;
JSString *jsstr;
jsstr = JS_ValueToString(cx, idval);
if (!jsstr)
return idval;
cp = JS_GetStringChars(jsstr);
if (JS7_ISDEC(*cp)) {
jsuint index = JS7_UNDEC(*cp++);
jsuint oldIndex = 0;
jsuint c = 0;
if (index != 0) {
while (JS7_ISDEC(*cp)) {
oldIndex = index;
c = JS7_UNDEC(*cp);
index = 10*index + c;
cp++;
}
}
if (*cp == 0 &&
(oldIndex < (JSVAL_INT_MAX / 10) ||
(oldIndex == (JSVAL_INT_MAX / 10) && c < (JSVAL_INT_MAX % 10)))) {
return INT_TO_JSVAL(index);
}
}
return idval;
}
static JSBool
access_java_array_element(JSContext *cx,
JNIEnv *jEnv,
JSObject *obj,
jsid id,
jsval *vp,
JSBool do_assignment)
{
jsval idval;
jarray java_array;
JavaClassDescriptor *class_descriptor;
JavaObjectWrapper *java_wrapper;
jsize array_length, index;
JavaSignature *array_component_signature;
/* printf("In JavaArray_getProperty\n"); */
java_wrapper = JS_GetPrivate(cx, obj);
if (!java_wrapper) {
const char *property_name;
if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
(property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
if (!strcmp(property_name, "constructor")) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
}
JS_ReportError(cx, "illegal operation on JavaArray prototype object");
return JS_FALSE;
}
class_descriptor = java_wrapper->class_descriptor;
java_array = java_wrapper->java_obj;
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_ARRAY);
JS_IdToValue(cx, id, &idval);
if (!JSVAL_IS_INT(idval))
idval = try_convert_to_jsint(cx, idval);
if (!JSVAL_IS_INT(idval)) {
/*
* Usually, properties of JavaArray objects are indexed by integers, but
* Java arrays also inherit all the methods of java.lang.Object, so a
* string-valued property is also possible.
*/
if (JSVAL_IS_STRING(idval)) {
const char *member_name;
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
if (do_assignment) {
JSVersion version = JS_GetVersion(cx);
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Attempt to write to invalid Java array "
"element \"%s\"", member_name);
return JS_FALSE;
} else {
*vp = JSVAL_VOID;
return JS_TRUE;
}
} else {
if (!strcmp(member_name, "length")) {
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array);
if (array_length < 0)
return JS_FALSE;
if (vp)
*vp = INT_TO_JSVAL(array_length);
return JS_TRUE;
}
/* Check to see if we're reflecting a Java array method */
return JavaObject_getPropertyById(cx, obj, id, vp);
}
}
JS_ReportError(cx, "invalid Java array index expression");
return JS_FALSE;
}
index = JSVAL_TO_INT(idval);
#if 0
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_array);
if (array_length < 0)
return JS_FALSE;
/* Just let Java throw an exception instead of checking array bounds here */
if (index < 0 || index >= array_length) {
JS_ReportError(cx, "Java array index %d out of range", index);
return JS_FALSE;
}
#endif
array_component_signature = class_descriptor->array_component_signature;
if (!vp)
return JS_TRUE;
if (do_assignment) {
return jsj_SetJavaArrayElement(cx, jEnv, java_array, index,
array_component_signature, *vp);
} else {
return jsj_GetJavaArrayElement(cx, jEnv, java_array, index,
array_component_signature, vp);
}
}
PR_STATIC_CALLBACK(JSBool)
JavaArray_getPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
return access_java_array_element(cx, jEnv, obj, id, vp, JS_FALSE);
}
PR_STATIC_CALLBACK(JSBool)
JavaArray_setPropertyById(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
return access_java_array_element(cx, jEnv, obj, id, vp, JS_TRUE);
}
static JSBool
JavaArray_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
JSObject **objp, JSProperty **propp
#if defined JS_THREADSAFE && defined DEBUG
, const char *file, uintN line
#endif
)
{
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
return access_java_array_element(cx, jEnv, obj, id, NULL, JS_FALSE);
}
static JSBool
JavaArray_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs, JSProperty **propp)
{
JS_ReportError(cx, "Cannot define a new property in a JavaArray");
return JS_FALSE;
}
static JSBool
JavaArray_getAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
return JS_FALSE;
}
static JSBool
JavaArray_setAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
PR_ASSERT(0);
return JS_FALSE;
}
/* Silently ignore all setAttribute attempts */
return JS_TRUE;
}
static JSBool
JavaArray_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
JSVersion version = JS_GetVersion(cx);
*vp = JSVAL_FALSE;
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Properties of JavaArray objects may not be deleted");
return JS_FALSE;
} else {
/* Attempts to delete permanent properties are silently ignored
by ECMAScript. */
return JS_TRUE;
}
}
static JSBool
JavaArray_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
/* printf("In JavaArray_defaultValue()\n"); */
return JavaObject_convert(cx, obj, JSTYPE_STRING, vp);
}
static JSBool
JavaArray_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp)
{
JavaObjectWrapper *java_wrapper;
JNIEnv *jEnv;
jsize array_length, index;
java_wrapper = JS_GetPrivate(cx, obj);
/* Check for prototype object */
if (!java_wrapper) {
*statep = JSVAL_NULL;
if (idp)
*idp = INT_TO_JSVAL(0);
return JS_TRUE;
}
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
array_length = jsj_GetJavaArrayLength(cx, jEnv, java_wrapper->java_obj);
if (array_length < 0)
return JS_FALSE;
switch(enum_op) {
case JSENUMERATE_INIT:
*statep = INT_TO_JSVAL(0);
if (idp)
*idp = INT_TO_JSVAL(array_length);
return JS_TRUE;
case JSENUMERATE_NEXT:
index = JSVAL_TO_INT(*statep);
if (index < array_length) {
JS_ValueToId(cx, INT_TO_JSVAL(index), idp);
index++;
*statep = INT_TO_JSVAL(index);
return JS_TRUE;
}
/* Fall through ... */
case JSENUMERATE_DESTROY:
*statep = JSVAL_NULL;
return JS_TRUE;
default:
PR_ASSERT(0);
return JS_FALSE;
}
}
static JSBool
JavaArray_checkAccess(JSContext *cx, JSObject *obj, jsid id,
JSAccessMode mode, jsval *vp, uintN *attrsp)
{
switch (mode) {
case JSACC_WATCH:
JS_ReportError(cx, "Cannot place watchpoints on JavaArray object properties");
return JS_FALSE;
case JSACC_IMPORT:
JS_ReportError(cx, "Cannot export a JavaArray object's properties");
return JS_FALSE;
default:
return JS_TRUE;
}
}
JSObjectOps JavaArray_ops = {
/* Mandatory non-null function pointer members. */
NULL, /* newObjectMap */
NULL, /* destroyObjectMap */
JavaArray_lookupProperty,
JavaArray_defineProperty,
JavaArray_getPropertyById, /* getProperty */
JavaArray_setPropertyById, /* setProperty */
JavaArray_getAttributes,
JavaArray_setAttributes,
JavaArray_deleteProperty,
JavaArray_defaultValue,
JavaArray_newEnumerate,
JavaArray_checkAccess,
/* Optionally non-null members start here. */
NULL, /* thisObject */
NULL, /* dropProperty */
NULL, /* call */
NULL, /* construct */
NULL, /* xdrObject */
NULL /* hasInstance */
};
static JSObjectOps *
JavaArray_getObjectOps(JSContext *cx, JSClass *clazz)
{
return &JavaArray_ops;
}
JSClass JavaArray_class = {
"JavaArray", JSCLASS_HAS_PRIVATE,
NULL, NULL, NULL, NULL,
NULL, NULL, JavaObject_convert, JavaObject_finalize,
JavaArray_getObjectOps,
};
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
/* Initialize the JS JavaArray class */
JSBool
jsj_init_JavaArray(JSContext *cx, JSObject *global_obj)
{
JavaArray_ops.newObjectMap = js_ObjectOps.newObjectMap;
JavaArray_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
if (!JS_InitClass(cx, global_obj,
0, &JavaArray_class, 0, 0,
0, 0, 0, 0))
return JS_FALSE;
return JS_TRUE;
}

View File

@@ -0,0 +1,586 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the native code implementation of JS's JavaClass class.
*
* A JavaClass is JavaScript's representation of a Java class.
* Its parent JS object is always a JavaPackage object. A JavaClass is not an
* exact reflection of Java's corresponding java.lang.Class object. Rather,
* the properties of a JavaClass are the static methods and properties of the
* corresponding Java class.
*
* Note that there is no runtime equivalent to the JavaClass class in Java.
* (Although there are instances of java.lang.String and there are static
* methods of java.lang.String that can be invoked, there's no such thing as
* a first-class object that can be referenced simply as "java.lang.String".)
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
static JSBool
JavaClass_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
char *name;
JSString *str;
JavaClassDescriptor *class_descriptor;
class_descriptor = JS_GetPrivate(cx, obj);
if (!class_descriptor)
return JS_FALSE;
switch(type) {
case JSTYPE_STRING:
/* Convert '/' to '.' so that it looks like Java language syntax. */
if (!class_descriptor->name)
break;
name = PR_smprintf("[JavaClass %s]", class_descriptor->name);
if (!name) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
str = JS_NewString(cx, name, strlen(name));
if (!str) {
free(name);
/* It's not necessary to call JS_ReportOutOfMemory(), as
JS_NewString() will do so on failure. */
return JS_FALSE;
}
*vp = STRING_TO_JSVAL(str);
return JS_TRUE;
default:
break;
}
return JS_TRUE;
}
static JSBool
lookup_static_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
JavaClassDescriptor **class_descriptorp,
jsid id, JavaMemberDescriptor **memberp)
{
jsval idval;
JavaMemberDescriptor *member_descriptor;
const char *member_name;
JavaClassDescriptor *class_descriptor;
class_descriptor = JS_GetPrivate(cx, obj);
if (!class_descriptor) {
*class_descriptorp = NULL;
*memberp = NULL;
return JS_TRUE;
}
if (class_descriptorp)
*class_descriptorp = class_descriptor;
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
if (!member_descriptor) {
JS_IdToValue(cx, id, &idval);
if (!JSVAL_IS_STRING(idval)) {
JS_ReportError(cx, "invalid JavaClass property expression. "
"(methods and fields of a JavaClass object can only be identified by their name)");
return JS_FALSE;
}
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
/* Why do we have to do this ? */
if (!strcmp(member_name, "prototype")) {
*memberp = NULL;
return JS_TRUE;
}
JS_ReportError(cx, "Java class %s has no public static field or method named \"%s\"",
class_descriptor->name, member_name);
return JS_FALSE;
}
if (memberp)
*memberp = member_descriptor;
return JS_TRUE;
}
PR_STATIC_CALLBACK(JSBool)
JavaClass_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
jsval idval;
jclass java_class;
const char *member_name;
JavaClassDescriptor *class_descriptor;
JavaMemberDescriptor *member_descriptor;
JNIEnv *jEnv;
/* printf("In JavaClass_getProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
return JS_FALSE;
if (!member_descriptor) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
java_class = class_descriptor->java_class;
if (member_descriptor->field) {
if (!member_descriptor->methods) {
return jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, vp);
} else {
PR_ASSERT(0);
}
} else {
JSFunction *function;
/* TODO - eliminate JSFUN_BOUND_METHOD */
JS_IdToValue(cx, id, &idval);
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
function = JS_NewFunction(cx, jsj_JavaStaticMethodWrapper, 0,
JSFUN_BOUND_METHOD, obj, member_name);
if (!function)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(JS_GetFunctionObject(function));
}
return JS_TRUE;
}
PR_STATIC_CALLBACK(JSBool)
JavaClass_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
jclass java_class;
const char *member_name;
JavaClassDescriptor *class_descriptor;
JavaMemberDescriptor *member_descriptor;
jsval idval;
JNIEnv *jEnv;
/* printf("In JavaClass_setProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_static_member_by_id(cx, jEnv, obj, &class_descriptor, id, &member_descriptor))
return JS_FALSE;
/* Check for the case where there is a method with the given name, but no field
with that name */
if (!member_descriptor->field)
goto no_such_field;
/* Silently fail if field value is final (immutable), as required by ECMA spec */
if (member_descriptor->field->modifiers & ACC_FINAL)
return JS_TRUE;
java_class = class_descriptor->java_class;
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_class, *vp);
no_such_field:
JS_IdToValue(cx, id, &idval);
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
JS_ReportError(cx, "No static field named \"%s\" in Java class %s",
member_name, class_descriptor->name);
return JS_FALSE;
}
/*
* Free the private native data associated with the JavaPackage object.
*/
PR_STATIC_CALLBACK(void)
JavaClass_finalize(JSContext *cx, JSObject *obj)
{
JNIEnv *jEnv;
JavaClassDescriptor *class_descriptor = JS_GetPrivate(cx, obj);
if (!class_descriptor)
return;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return;
/* printf("Finalizing %s\n", class_descriptor->name); */
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
}
static JSBool
JavaClass_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
JSObject **objp, JSProperty **propp
#if defined JS_THREADSAFE && defined DEBUG
, const char *file, uintN line
#endif
)
{
JNIEnv *jEnv;
JSErrorReporter old_reporter;
/* printf("In JavaClass_lookupProperty()\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
old_reporter = JS_SetErrorReporter(cx, NULL);
if (lookup_static_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
*objp = obj;
*propp = (JSProperty*)1;
} else {
*objp = NULL;
*propp = NULL;
}
JS_SetErrorReporter(cx, old_reporter);
return JS_TRUE;
}
static JSBool
JavaClass_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs, JSProperty **propp)
{
JS_ReportError(cx, "Cannot define a new property in a JavaClass");
return JS_FALSE;
}
static JSBool
JavaClass_getAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
return JS_FALSE;
}
static JSBool
JavaClass_setAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
PR_ASSERT(0);
return JS_FALSE;
}
/* Silently ignore all setAttribute attempts */
return JS_TRUE;
}
static JSBool
JavaClass_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
JSVersion version = JS_GetVersion(cx);
*vp = JSVAL_FALSE;
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Properties of JavaClass objects may not be deleted");
return JS_FALSE;
} else {
/* Attempts to delete permanent properties are silently ignored
by ECMAScript. */
return JS_TRUE;
}
}
static JSBool
JavaClass_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
/* printf("In JavaClass_defaultValue()\n"); */
return JavaClass_convert(cx, obj, JSTYPE_STRING, vp);
}
static JSBool
JavaClass_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp)
{
JavaMemberDescriptor *member_descriptor;
JavaClassDescriptor *class_descriptor;
JNIEnv *jEnv;
class_descriptor = JS_GetPrivate(cx, obj);
/* Check for prototype JavaClass object */
if (!class_descriptor) {
*statep = JSVAL_NULL;
if (idp)
*idp = INT_TO_JSVAL(0);
return JS_TRUE;
}
switch(enum_op) {
case JSENUMERATE_INIT:
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
*statep = PRIVATE_TO_JSVAL(member_descriptor);
if (idp)
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
return JS_TRUE;
case JSENUMERATE_NEXT:
member_descriptor = JSVAL_TO_PRIVATE(*statep);
if (member_descriptor) {
*idp = member_descriptor->id;
*statep = PRIVATE_TO_JSVAL(member_descriptor->next);
return JS_TRUE;
}
/* Fall through ... */
case JSENUMERATE_DESTROY:
*statep = JSVAL_NULL;
return JS_TRUE;
default:
PR_ASSERT(0);
return JS_FALSE;
}
}
static JSBool
JavaClass_checkAccess(JSContext *cx, JSObject *obj, jsid id,
JSAccessMode mode, jsval *vp, uintN *attrsp)
{
switch (mode) {
case JSACC_WATCH:
JS_ReportError(cx, "Cannot place watchpoints on JavaClass object properties");
return JS_FALSE;
case JSACC_IMPORT:
JS_ReportError(cx, "Cannot export a JavaClass object's properties");
return JS_FALSE;
default:
return JS_TRUE;
}
}
/*
* Implement the JavaScript instanceof operator for JavaClass objects by using
* the equivalent Java instanceof operation.
*/
static JSBool
JavaClass_hasInstance(JSContext *cx, JSObject *obj, jsval candidate_jsval,
JSBool *has_instancep)
{
JavaClassDescriptor *class_descriptor;
JavaObjectWrapper *java_wrapper;
JSClass *js_class;
JSBool has_instance;
JSObject *candidate_obj;
jclass java_class;
jobject java_obj;
JNIEnv *jEnv;
has_instance = JS_FALSE;
class_descriptor = JS_GetPrivate(cx, obj);
if (!class_descriptor) {
JS_ReportError(cx, "illegal operation on JavaClass prototype object");
return JS_FALSE;
}
/*
* Make sure that the thing to the left of the instanceof operator is a
* Java object.
*/
if (!JSVAL_IS_OBJECT(candidate_jsval))
goto done;
candidate_obj = JSVAL_TO_OBJECT(candidate_jsval);
js_class = JS_GetClass(candidate_obj);
if ((js_class != &JavaObject_class) && (js_class != &JavaArray_class))
goto done;
java_class = class_descriptor->java_class;
java_wrapper = JS_GetPrivate(cx, candidate_obj);
if (!java_wrapper) {
JS_ReportError(cx, "illegal operation on prototype object");
return JS_FALSE;
}
java_obj = java_wrapper->java_obj;
/* Get JNI pointer */
jsj_MapJSContextToJSJThread(cx, &jEnv);
has_instance = (*jEnv)->IsInstanceOf(jEnv, java_obj, java_class);
done:
*has_instancep = has_instance;
return JS_TRUE;
}
JSObjectOps JavaClass_ops = {
/* Mandatory non-null function pointer members. */
NULL, /* newObjectMap */
NULL, /* destroyObjectMap */
JavaClass_lookupProperty,
JavaClass_defineProperty,
JavaClass_getPropertyById, /* getProperty */
JavaClass_setPropertyById, /* setProperty */
JavaClass_getAttributes,
JavaClass_setAttributes,
JavaClass_deleteProperty,
JavaClass_defaultValue,
JavaClass_newEnumerate,
JavaClass_checkAccess,
/* Optionally non-null members start here. */
NULL, /* thisObject */
NULL, /* dropProperty */
jsj_JavaConstructorWrapper, /* call */
jsj_JavaConstructorWrapper, /* construct */
NULL, /* xdrObject */
JavaClass_hasInstance, /* hasInstance */
};
static JSObjectOps *
JavaClass_getObjectOps(JSContext *cx, JSClass *clazz)
{
return &JavaClass_ops;
}
JSClass JavaClass_class = {
"JavaClass", JSCLASS_HAS_PRIVATE,
NULL, NULL, NULL, NULL,
NULL, NULL, JavaClass_convert, JavaClass_finalize,
JavaClass_getObjectOps,
};
static JSObject *
jsj_new_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
JavaClassDescriptor *class_descriptor)
{
JSObject *JavaClass_obj;
JavaClass_obj = JS_NewObject(cx, &JavaClass_class, 0, parent_obj);
if (!JavaClass_obj)
return NULL;
JS_SetPrivate(cx, JavaClass_obj, (void *)class_descriptor);
#ifdef DEBUG
/* printf("JavaClass \'%s\' created\n", class_descriptor->name); */
#endif
return JavaClass_obj;
}
JSObject *
jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject* parent_obj,
const char *simple_class_name,
jclass java_class)
{
JavaClassDescriptor *class_descriptor;
JSObject *JavaClass_obj;
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
if (!class_descriptor)
return NULL;
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, parent_obj, class_descriptor);
if (!JavaClass_obj)
return NULL;
if (!JS_DefineProperty(cx, parent_obj, simple_class_name,
OBJECT_TO_JSVAL(JavaClass_obj), 0, 0,
JSPROP_PERMANENT|JSPROP_READONLY|JSPROP_ENUMERATE))
return NULL;
return JavaClass_obj;
}
/*
* The getClass() native JS method is defined as a property of the global
* object. Given a JavaObject it returns the corresponding JavaClass. This
* is useful for accessing static methods and fields.
*
* js> getClass(new java.lang.String("foo"))
* [JavaClass java.lang.String]
*/
static JSBool
getClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JSObject *obj_arg, *JavaClass_obj;
JavaObjectWrapper *java_wrapper;
JavaClassDescriptor *class_descriptor;
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (argc != 1 ||
!JSVAL_IS_OBJECT(argv[0]) ||
!(obj_arg = JSVAL_TO_OBJECT(argv[0])) ||
(!JS_InstanceOf(cx, obj_arg, &JavaObject_class, 0) &&
!JS_InstanceOf(cx, obj_arg, &JavaArray_class, 0))) {
JS_ReportError(cx, "getClass expects a Java object argument");
return JS_FALSE;
}
java_wrapper = JS_GetPrivate(cx, obj_arg);
if (!java_wrapper) {
JS_ReportError(cx, "getClass called on prototype object");
return JS_FALSE;
}
class_descriptor = java_wrapper->class_descriptor;
JavaClass_obj = jsj_new_JavaClass(cx, jEnv, NULL, class_descriptor);
if (!JavaClass_obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(JavaClass_obj);
return JS_TRUE;
}
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
JSBool
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj)
{
JavaClass_ops.newObjectMap = js_ObjectOps.newObjectMap;
JavaClass_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
/* Define JavaClass class */
if (!JS_InitClass(cx, global_obj, 0, &JavaClass_class, 0, 0, 0, 0, 0, 0))
return JS_FALSE;
if (!JS_DefineFunction(cx, global_obj, "getClass", getClass, 0,
JSPROP_READONLY))
return JS_FALSE;
return jsj_InitJavaClassReflectionsTable();
}

View File

@@ -0,0 +1,134 @@
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the native code implementation of JS's JavaMember class.
* JavaMember's are a strange beast required only to handle the special case
* of a public field and a public method that appear in the same class and
* have the same name. When such a field/method is used in Java, the compiler
* can statically determine from context whether the field or the method is
* being referenced, but that is not possible with JavaScript. For example:
*
* ambiguousVal = javaObj.fieldOrMethod; // ambiguousVal is a JavaMember object
* a = ambiguousVal(); // ambiguousVal used as a method value
* b = ambiguousVal + 4; // ambiguousVal used as a field value
*
* A JavaMember instance carries both the captured value of the Java field and
* the method value until the context that the value is to be used in is known,
* at which point conversion forces the use of one or the other.
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
/* Private, native portion of a JavaMember */
typedef struct JavaMethodOrFieldValue {
jsval method_val;
jsval field_val;
} JavaMethodOrFieldValue;
JSObject *
jsj_CreateJavaMember(JSContext *cx, jsval method_val, jsval field_val)
{
JavaMethodOrFieldValue *member_val;
JSObject *JavaMember_obj;
member_val = (JavaMethodOrFieldValue *)JS_malloc(cx, sizeof(*member_val));
if (!member_val)
return NULL;
JavaMember_obj = JS_NewObject(cx, &JavaMember_class, 0, 0);
if (!JavaMember_obj) {
JS_free(cx, member_val);
return NULL;
}
JS_SetPrivate(cx, JavaMember_obj, (void *)member_val);
member_val->method_val = method_val;
JS_AddRoot(cx, &member_val->method_val);
member_val->field_val = field_val;
if (JSVAL_IS_GCTHING(field_val))
JS_AddRoot(cx, &member_val->field_val);
return JavaMember_obj;
}
static void
JavaMember_finalize(JSContext *cx, JSObject *obj)
{
JavaMethodOrFieldValue *member_val;
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return;
member_val = JS_GetPrivate(cx, obj);
if (!member_val)
return;
JS_RemoveRoot(cx, &member_val->method_val);
if (JSVAL_IS_GCTHING(member_val->method_val))
JS_RemoveRoot(cx, &member_val->method_val);
JS_free(cx, member_val);
}
static JSBool
JavaMember_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
JavaMethodOrFieldValue *member_val;
member_val = JS_GetPrivate(cx, obj);
if (!member_val) {
if (type == JSTYPE_OBJECT) {
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
return JS_FALSE;
}
switch (type) {
case JSTYPE_VOID:
case JSTYPE_STRING:
case JSTYPE_NUMBER:
case JSTYPE_BOOLEAN:
case JSTYPE_OBJECT:
*vp = member_val->field_val;
return JS_TRUE;
case JSTYPE_FUNCTION:
*vp = member_val->method_val;
return JS_TRUE;
default:
PR_ASSERT(0);
return JS_FALSE;
}
}
JSClass JavaMember_class = {
"JavaMember", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JavaMember_convert, JavaMember_finalize
};
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
JSBool
jsj_init_JavaMember(JSContext *cx, JSObject *global_obj)
{
if (!JS_InitClass(cx, global_obj,
0, &JavaMember_class, 0, 0,
0, 0,
0, 0))
return JS_FALSE;
return JS_TRUE;
}

View File

@@ -0,0 +1,686 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the native code implementation of JS's JavaObject class.
*
* An instance of JavaObject is the JavaScript reflection of a Java object.
*
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
#include "jsj_hash.h" /* Hash table with Java object as key */
/*
* This is a hash table that maps from Java objects to JS objects.
* It is used to ensure that the same JS object is obtained when a Java
* object is reflected more than once, so that JS object equality tests
* work in the expected manner, i.e. the "==" and "===" operators.
*
* The table entry keys are Java objects (of type jobject) and the entry values
* are JSObject pointers. Because the jobject type is an opaque handle and
* not necessarily a pointer, the hashing and key comparison functions must
* invoke the appropriate JVM functions.
*
* When the corresponding JS object instance is finalized, the entry is
* removed from the table, and a Java GC root for the Java object is removed.
*/
static JSJHashTable *java_obj_reflections = NULL;
#ifdef JS_THREADSAFE
static PRMonitor *java_obj_reflections_monitor = NULL;
#endif
static JSBool
init_java_obj_reflections_table()
{
java_obj_reflections =
JSJ_NewHashTable(512, jsj_HashJavaObject, jsj_JavaObjectComparator,
NULL, NULL, NULL);
if (!java_obj_reflections)
return JS_FALSE;
#ifdef JS_THREADSAFE
java_obj_reflections_monitor = PR_NewNamedMonitor("java_obj_reflections");
if (!java_obj_reflections_monitor) {
PR_HashTableDestroy(java_obj_reflections);
return JS_FALSE;
}
#endif
return JS_TRUE;
}
JSObject *
jsj_WrapJavaObject(JSContext *cx,
JNIEnv *jEnv,
jobject java_obj,
jclass java_class)
{
JSJHashNumber hash_code;
JSClass *js_class;
JSObject *js_wrapper_obj;
JavaObjectWrapper *java_wrapper;
JavaClassDescriptor *class_descriptor;
JSJHashEntry *he, **hep;
js_wrapper_obj = NULL;
hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);
#ifdef JS_THREADSAFE
PR_EnterMonitor(java_obj_reflections_monitor);
#endif
hep = JSJ_HashTableRawLookup(java_obj_reflections,
hash_code, java_obj, (void*)jEnv);
he = *hep;
if (he) {
js_wrapper_obj = (JSObject *)he->value;
if (js_wrapper_obj)
goto done;
}
/* No existing reflection found. Construct a new one */
class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
if (!class_descriptor)
goto done;
if (class_descriptor->type == JAVA_SIGNATURE_ARRAY) {
js_class = &JavaArray_class;
} else {
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_CLASS);
js_class = &JavaObject_class;
}
/* Create new JS object to reflect Java object */
js_wrapper_obj = JS_NewObject(cx, js_class, NULL, NULL);
if (!js_wrapper_obj)
goto done;
/* Create private, native portion of JavaObject */
java_wrapper =
(JavaObjectWrapper *)JS_malloc(cx, sizeof(JavaObjectWrapper));
if (!java_wrapper) {
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
goto done;
}
JS_SetPrivate(cx, js_wrapper_obj, java_wrapper);
java_wrapper->class_descriptor = class_descriptor;
java_obj = (*jEnv)->NewGlobalRef(jEnv, java_obj);
java_wrapper->java_obj = java_obj;
if (!java_obj)
goto out_of_memory;
/* Add the JavaObject to the hash table */
he = JSJ_HashTableRawAdd(java_obj_reflections, hep, hash_code,
java_obj, js_wrapper_obj, (void*)jEnv);
if (!he) {
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
goto out_of_memory;
}
done:
#ifdef JS_THREADSAFE
PR_ExitMonitor(java_obj_reflections_monitor);
#endif
return js_wrapper_obj;
out_of_memory:
/* No need to free js_wrapper_obj, as it will be finalized by GC. */
JS_ReportOutOfMemory(cx);
js_wrapper_obj = NULL;
goto done;
}
static void
remove_java_obj_reflection_from_hashtable(jobject java_obj, JNIEnv *jEnv)
{
JSJHashNumber hash_code;
JSJHashEntry *he, **hep;
hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);
#ifdef JS_THREADSAFE
PR_EnterMonitor(java_obj_reflections_monitor);
#endif
hep = JSJ_HashTableRawLookup(java_obj_reflections, hash_code,
java_obj, (void*)jEnv);
he = *hep;
PR_ASSERT(he);
if (he)
JSJ_HashTableRawRemove(java_obj_reflections, hep, he, (void*)jEnv);
#ifdef JS_THREADSAFE
PR_ExitMonitor(java_obj_reflections_monitor);
#endif
}
void
JavaObject_finalize(JSContext *cx, JSObject *obj)
{
JavaObjectWrapper *java_wrapper;
jobject java_obj;
JNIEnv *jEnv;
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return;
java_wrapper = JS_GetPrivate(cx, obj);
if (!java_wrapper)
return;
java_obj = java_wrapper->java_obj;
if (java_obj) {
remove_java_obj_reflection_from_hashtable(java_obj, jEnv);
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
}
jsj_ReleaseJavaClassDescriptor(cx, jEnv, java_wrapper->class_descriptor);
JS_free(cx, java_wrapper);
}
/* Trivial helper for jsj_DiscardJavaObjReflections(), below */
static PRIntn
enumerate_remove_java_obj(JSJHashEntry *he, PRIntn i, void *arg)
{
JNIEnv *jEnv = (JNIEnv*)arg;
jobject java_obj;
JavaObjectWrapper *java_wrapper;
JSObject *java_wrapper_obj;
java_wrapper_obj = (JSObject *)he->value;
java_wrapper = JS_GetPrivate(NULL, java_wrapper_obj);
java_obj = java_wrapper->java_obj;
(*jEnv)->DeleteGlobalRef(jEnv, java_obj);
java_wrapper->java_obj = NULL;
return HT_ENUMERATE_REMOVE;
}
/* This shutdown routine discards all JNI references to Java objects
that have been reflected into JS, even if there are still references
to them from JS. */
void
jsj_DiscardJavaObjReflections(JNIEnv *jEnv)
{
if (java_obj_reflections) {
JSJ_HashTableEnumerateEntries(java_obj_reflections,
enumerate_remove_java_obj,
(void*)jEnv);
JSJ_HashTableDestroy(java_obj_reflections);
java_obj_reflections = NULL;
}
}
PR_CALLBACK JSBool
JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
JavaObjectWrapper *java_wrapper;
JavaClassDescriptor *class_descriptor;
jobject java_obj;
JNIEnv *jEnv;
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
java_wrapper = JS_GetPrivate(cx, obj);
if (!java_wrapper) {
if (type == JSTYPE_OBJECT) {
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
}
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
return JS_FALSE;
}
java_obj = java_wrapper->java_obj;
class_descriptor = java_wrapper->class_descriptor;
switch (type) {
case JSTYPE_OBJECT:
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
case JSTYPE_FUNCTION:
JS_ReportError(cx, "can't convert Java object to function");
return JS_FALSE;
case JSTYPE_VOID:
case JSTYPE_STRING:
/* Either extract a C-string from the java.lang.String object
or call the Java toString() method */
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp);
case JSTYPE_NUMBER:
/* Call Java doubleValue() method, if applicable */
return jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp);
case JSTYPE_BOOLEAN:
/* Call booleanValue() method, if applicable */
return jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp);
default:
PR_ASSERT(0);
return JS_FALSE;
}
}
static JSBool
lookup_member_by_id(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
JavaObjectWrapper **java_wrapperp,
jsid id,
JavaMemberDescriptor **member_descriptorp)
{
jsval idval;
JavaObjectWrapper *java_wrapper;
JavaMemberDescriptor *member_descriptor;
const char *member_name, *property_name;
JavaClassDescriptor *class_descriptor;
java_wrapper = JS_GetPrivate(cx, obj);
if (!java_wrapper) {
if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
(property_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
if (!strcmp(property_name, "constructor")) {
*java_wrapperp = NULL;
*member_descriptorp = NULL;
return JS_TRUE;
}
}
JS_ReportError(cx, "illegal operation on JavaObject prototype object");
return JS_FALSE;
}
class_descriptor = java_wrapper->class_descriptor;
PR_ASSERT(class_descriptor->type == JAVA_SIGNATURE_CLASS ||
class_descriptor->type == JAVA_SIGNATURE_ARRAY);
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
if (!member_descriptor) {
JS_IdToValue(cx, id, &idval);
if (!JSVAL_IS_STRING(idval)) {
JS_ReportError(cx, "invalid JavaObject property expression. "
"(methods and field properties of a JavaObject object can only be strings)");
return JS_FALSE;
}
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
JS_ReportError(cx, "Java class %s has no public instance field or "
"method named \"%s\"",
class_descriptor->name, member_name);
return JS_FALSE;
}
/* Success. Handle the multiple return values */
if (java_wrapperp)
*java_wrapperp = java_wrapper;
if (member_descriptorp)
*member_descriptorp = member_descriptor;
return JS_TRUE;
}
PR_CALLBACK JSBool
JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
jobject java_obj;
JavaMemberDescriptor *member_descriptor;
JavaObjectWrapper *java_wrapper;
JNIEnv *jEnv;
JSObject *funobj;
jsval field_val, method_val;
JSBool success;
/* printf("In JavaObject_getProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor))
return JS_FALSE;
/* Handle access to "constructor" property of prototype object with
silent failure. */
if (!member_descriptor) {
*vp = JSVAL_VOID;
return JS_TRUE;
}
java_obj = java_wrapper->java_obj;
field_val = method_val = JSVAL_VOID;
/* If a field member, get the value of the field */
if (member_descriptor->field) {
success = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, &field_val);
if (!success)
return JS_FALSE;
}
/* If a method member, build a wrapper around the Java method */
if (member_descriptor->methods) {
/* Create a function object with this JavaObject as its parent, so that
JSFUN_BOUND_METHOD binds it as the default 'this' for the function. */
funobj = JS_CloneFunctionObject(cx, member_descriptor->invoke_func_obj, obj);
if (!funobj)
return JS_FALSE;
method_val = OBJECT_TO_JSVAL(funobj);
}
#if TEST_JAVAMEMBER
/* Always create a JavaMember object, even though it's inefficient */
obj = jsj_CreateJavaMember(cx, method_val, field_val);
if (!obj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(obj);
#else /* !TEST_JAVAMEMBER */
if (member_descriptor->field) {
if (!member_descriptor->methods) {
/* Return value of Java field */
*vp = field_val;
} else {
/* Handle special case of access to a property that could refer
to either a Java field or a method that share the same name.
In Java, such ambiguity is not possible because the compiler
can statically determine which is being accessed. */
obj = jsj_CreateJavaMember(cx, method_val, field_val);
if (!obj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(obj);
}
} else {
/* Return wrapper around Java method */
*vp = method_val;
}
#endif /* !TEST_JAVAMEMBER */
return JS_TRUE;
}
PR_STATIC_CALLBACK(JSBool)
JavaObject_setPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
jobject java_obj;
const char *member_name;
JavaObjectWrapper *java_wrapper;
JavaClassDescriptor *class_descriptor;
JavaMemberDescriptor *member_descriptor;
jsval idval;
JNIEnv *jEnv;
/* printf("In JavaObject_setProperty\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor))
return JS_FALSE;
/* Check for the case where there is a method with the give name, but no field
with that name */
if (!member_descriptor->field)
goto no_such_field;
/* Silently fail if field value is final (immutable), as required by ECMA spec */
if (member_descriptor->field->modifiers & ACC_FINAL)
return JS_TRUE;
java_obj = java_wrapper->java_obj;
return jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, *vp);
no_such_field:
JS_IdToValue(cx, id, &idval);
member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
class_descriptor = java_wrapper->class_descriptor;
JS_ReportError(cx, "No instance field named \"%s\" in Java class %s",
member_name, class_descriptor->name);
return JS_FALSE;
}
static JSBool
JavaObject_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
JSObject **objp, JSProperty **propp
#if defined JS_THREADSAFE && defined DEBUG
, const char *file, uintN line
#endif
)
{
JNIEnv *jEnv;
JSErrorReporter old_reporter;
/* printf("In JavaObject_lookupProperty()\n"); */
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
old_reporter = JS_SetErrorReporter(cx, NULL);
if (lookup_member_by_id(cx, jEnv, obj, NULL, id, NULL)) {
*objp = obj;
*propp = (JSProperty*)1;
} else {
*objp = NULL;
*propp = NULL;
}
JS_SetErrorReporter(cx, old_reporter);
return JS_TRUE;
}
static JSBool
JavaObject_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs, JSProperty **propp)
{
JS_ReportError(cx, "Cannot define a new property in a JavaObject");
return JS_FALSE;
}
static JSBool
JavaObject_getAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
*attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
return JS_FALSE;
}
static JSBool
JavaObject_setAttributes(JSContext *cx, JSObject *obj, jsid id,
JSProperty *prop, uintN *attrsp)
{
/* We don't maintain JS property attributes for Java class members */
if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
PR_ASSERT(0);
return JS_FALSE;
}
/* Silently ignore all setAttribute attempts */
return JS_TRUE;
}
static JSBool
JavaObject_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
JSVersion version = JS_GetVersion(cx);
*vp = JSVAL_FALSE;
if (!JSVERSION_IS_ECMA(version)) {
JS_ReportError(cx, "Properties of JavaObject objects may not be deleted");
return JS_FALSE;
} else {
/* Attempts to delete permanent properties are silently ignored
by ECMAScript. */
return JS_TRUE;
}
}
static JSBool
JavaObject_defaultValue(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
/* printf("In JavaObject_defaultValue()\n"); */
return JavaObject_convert(cx, obj, type, vp);
}
static JSBool
JavaObject_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsval *statep, jsid *idp)
{
JavaObjectWrapper *java_wrapper;
JavaMemberDescriptor *member_descriptor;
JavaClassDescriptor *class_descriptor;
JNIEnv *jEnv;
java_wrapper = JS_GetPrivate(cx, obj);
/* Check for prototype object */
if (!java_wrapper) {
*statep = JSVAL_NULL;
if (idp)
*idp = INT_TO_JSVAL(0);
return JS_TRUE;
}
class_descriptor = java_wrapper->class_descriptor;
switch(enum_op) {
case JSENUMERATE_INIT:
/* Get the Java per-thread environment pointer for this JSContext */
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
*statep = PRIVATE_TO_JSVAL(member_descriptor);
if (idp)
*idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
return JS_TRUE;
case JSENUMERATE_NEXT:
member_descriptor = JSVAL_TO_PRIVATE(*statep);
if (member_descriptor) {
*idp = member_descriptor->id;
*statep = PRIVATE_TO_JSVAL(member_descriptor->next);
return JS_TRUE;
}
/* Fall through ... */
case JSENUMERATE_DESTROY:
*statep = JSVAL_NULL;
return JS_TRUE;
default:
PR_ASSERT(0);
return JS_FALSE;
}
}
static JSBool
JavaObject_checkAccess(JSContext *cx, JSObject *obj, jsid id,
JSAccessMode mode, jsval *vp, uintN *attrsp)
{
switch (mode) {
case JSACC_WATCH:
JS_ReportError(cx, "Cannot place watchpoints on JavaObject object properties");
return JS_FALSE;
case JSACC_IMPORT:
JS_ReportError(cx, "Cannot export a JavaObject object's properties");
return JS_FALSE;
default:
return JS_TRUE;
}
}
JSObjectOps JavaObject_ops = {
/* Mandatory non-null function pointer members. */
NULL, /* newObjectMap */
NULL, /* destroyObjectMap */
JavaObject_lookupProperty,
JavaObject_defineProperty,
JavaObject_getPropertyById, /* getProperty */
JavaObject_setPropertyById, /* setProperty */
JavaObject_getAttributes,
JavaObject_setAttributes,
JavaObject_deleteProperty,
JavaObject_defaultValue,
JavaObject_newEnumerate,
JavaObject_checkAccess,
/* Optionally non-null members start here. */
NULL, /* thisObject */
NULL, /* dropProperty */
NULL, /* call */
NULL, /* construct */
NULL, /* xdrObject */
NULL, /* hasInstance */
};
static JSObjectOps *
JavaObject_getObjectOps(JSContext *cx, JSClass *clazz)
{
return &JavaObject_ops;
}
JSClass JavaObject_class = {
"JavaObject", JSCLASS_HAS_PRIVATE,
NULL, NULL, NULL, NULL,
NULL, NULL, JavaObject_convert, JavaObject_finalize,
JavaObject_getObjectOps,
};
extern PR_IMPORT_DATA(JSObjectOps) js_ObjectOps;
JSBool
jsj_init_JavaObject(JSContext *cx, JSObject *global_obj)
{
JavaObject_ops.newObjectMap = js_ObjectOps.newObjectMap;
JavaObject_ops.destroyObjectMap = js_ObjectOps.destroyObjectMap;
if (!JS_InitClass(cx, global_obj,
0, &JavaObject_class, 0, 0,
0, 0,
0, 0))
return JS_FALSE;
return init_java_obj_reflections_table();
}

View File

@@ -0,0 +1,500 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the native code implementation of the JavaPackage class.
*
* A JavaPackage is JavaScript's representation of a Java package. The
* JavaPackage object contains only a string, which is the path to the package,
* e.g. "java/lang". The JS properties of a JavaPackage are either nested packages
* or a JavaClass object, which represents the path to a Java class.
*
* Note that there is no equivalent to a JavaPackage object in Java. Example:
* Although there are instances of java.lang.String and there are static methods
* of java.lang.String that can be invoked, there's no such thing as a java.lang
* object in Java that exists at run time.
*
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
#include "jsjava.h"
JSClass JavaPackage_class; /* Forward declaration */
/*
* The native part of a JavaPackage object. It gets stored in the object's
* private slot.
*/
typedef struct {
const char * path; /* e.g. "java/lang" or NULL if top level package */
int flags; /* e.g. PKG_SYSTEM, PKG_CLASS */
} JavaPackage_Private;
static JSObject *
define_JavaPackage(JSContext *cx, JSObject *parent_obj,
const char *obj_name, const char *path, int flags)
{
JSObject *package_obj;
JavaPackage_Private *package;
package_obj = JS_DefineObject(cx, parent_obj, obj_name, &JavaPackage_class, 0,
JSPROP_PERMANENT | JSPROP_READONLY);
if (!package_obj)
return NULL;
/* Attach private, native data to the JS object */
package = (JavaPackage_Private *)JS_malloc(cx, sizeof(JavaPackage_Private));
JS_SetPrivate(cx, package_obj, (void *)package);
if (path)
package->path = JS_strdup(cx, path);
else
package->path = "";
package->flags = flags;
/* Check for OOM */
if (!package->path) {
JS_DeleteProperty(cx, parent_obj, obj_name);
JS_free(cx, package);
return NULL;
}
return package_obj;
}
/* JavaPackage uses standard JS getProperty */
/*
* Don't allow user-defined properties to be set on Java package objects, e.g.
* it is illegal to write "java.lang.myProperty = 4". We probably could relax
* this restriction, but it's potentially confusing and not clearly useful.
*/
static JSBool
JavaPackage_setProperty(JSContext *cx, JSObject *obj, jsval slot, jsval *vp)
{
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
if (!package) {
JS_ReportError(cx, "illegal attempt to add property to "
"JavaPackage prototype object");
return JS_FALSE;
}
JS_ReportError(cx, "You may not add properties to a JavaPackage object");
return JS_FALSE;
}
static JSBool quiet_resolve_failure;
/*
* Resolve a component name to be either the name of a class or a package.
*/
static JSBool
JavaPackage_resolve(JSContext *cx, JSObject *obj, jsval id)
{
JavaPackage_Private *package;
JSBool ok = JS_TRUE;
jclass jclazz;
char *subPath, *newPath;
const char *path;
JNIEnv *jEnv;
package = (JavaPackage_Private *)JS_GetPrivate(cx, obj);
if (!package)
return JS_TRUE;
if (!JSVAL_IS_STRING(id))
return JS_TRUE;
subPath = JS_GetStringBytes(JSVAL_TO_STRING(id));
/*
* There will be an attempt to invoke the toString() method when producing
* the string representation of a JavaPackage. When this occurs, avoid
* creating a bogus toString package. (This means that no one can ever
* create a package with the simple name "toString", but we'll live with
* that limitation.)
*/
if (!strcmp(subPath, "toString"))
return JS_FALSE;
path = package->path;
newPath = PR_smprintf("%s%s%s", path, (path[0] ? "/" : ""), subPath);
if (!newPath) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
jsj_MapJSContextToJSJThread(cx, &jEnv);
if (!jEnv)
return JS_FALSE;
/*
Unfortunately, Java provides no way to find out whether a particular
name is a package or not. The only way to tell is to try to load the
name as a class file and, if that fails, assume it's a package. This
makes things work as expected for the most part, but it has three
noticeable problems that keep coming up:
- You can refer to a package like java.lang.i.buried.paul without
generating a complaint. Of course, you'll never be able to refer to
any classes through it.
- An annoying consequence of the above is that misspelling a class name
results in a cryptic error about packages.
- In a browser context, i.e. where applets are involved, figuring out
whether something is a class may require looking for it over the net
using the current classloader. This means that the first time you
refer to java.lang.System in a js context, there will be an attempt
to search for [[DOCBASE]]/java.class on the server.
A solution is to explicitly tell jsjava the names of all the (local)
packages on the CLASSPATH. (Not implemented yet.)
*/
jclazz = (*jEnv)->FindClass(jEnv, newPath);
if (jclazz) {
JSObject *newClass;
newClass = jsj_define_JavaClass(cx, jEnv, obj, subPath, jclazz);
if (!newClass) {
ok = JS_FALSE;
goto out;
}
} else {
/* We assume that any failed attempt to load a class is because it
doesn't exist. If we wanted to do a better job, we would check
the exception type and make sure that it's NoClassDefFoundError */
(*jEnv)->ExceptionClear(jEnv);
/* beard: this has to be done here, so built-in classes will be defined. */
/* Painful hack for pre_define_java_packages() */
if (quiet_resolve_failure) {
ok = JS_FALSE;
goto out;
}
/*
* If there's no class of the given name, then we must be referring to
* a package. However, don't allow bogus sub-packages of pre-defined
* system packages to be created.
*/
if (JS_InstanceOf(cx, obj, &JavaPackage_class, NULL)) {
JavaPackage_Private *package;
package = JS_GetPrivate(cx, obj);
if (package->flags & PKG_SYSTEM) {
char *msg, *cp;
msg = PR_smprintf("No Java system package with name \"%s\" was identified "
"and no Java class with that name exists either",
newPath);
/* Check for OOM */
if (msg) {
/* Convert package of form "java/lang" to "java.lang" */
for (cp = msg; *cp != '\0'; cp++)
if (*cp == '/')
*cp = '.';
JS_ReportError(cx, msg);
free((char*)msg);
}
ok = JS_FALSE;
goto out;
}
}
if (!define_JavaPackage(cx, obj, subPath, newPath, 0)) {
ok = JS_FALSE;
goto out;
}
#ifdef DEBUG
/* printf("JavaPackage \'%s\' created\n", newPath); */
#endif
}
out:
free(newPath);
return ok;
}
static JSBool
JavaPackage_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
JSString *str;
char *name, *cp;
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
if (!package) {
fprintf(stderr, "JavaPackage_resolve: no private data!\n");
return JS_FALSE;
}
switch (type) {
/* Pretty-printing of JavaPackage */
case JSTYPE_VOID: /* Default value */
case JSTYPE_NUMBER:
case JSTYPE_STRING:
/* Convert '/' to '.' so that it looks like Java language syntax. */
if (!package->path)
break;
name = PR_smprintf("[JavaPackage %s]", package->path);
if (!name) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
for (cp = name; *cp != '\0'; cp++)
if (*cp == '/')
*cp = '.';
str = JS_NewString(cx, name, strlen(name));
if (!str) {
free(name);
/* It's not necessary to call JS_ReportOutOfMemory(), as
JS_NewString() will do so on failure. */
return JS_FALSE;
}
*vp = STRING_TO_JSVAL(str);
break;
case JSTYPE_OBJECT:
*vp = OBJECT_TO_JSVAL(obj);
break;
default:
break;
}
return JS_TRUE;
}
/*
* Free the private native data associated with the JavaPackage object.
*/
static void
JavaPackage_finalize(JSContext *cx, JSObject *obj)
{
JavaPackage_Private *package = JS_GetPrivate(cx, obj);
if (!package)
return;
if (package->path)
JS_free(cx, (char *)package->path);
JS_free(cx, package);
}
/*
* The definition of the JavaPackage class
*/
JSClass JavaPackage_class = {
"JavaPackage", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JavaPackage_setProperty,
JS_EnumerateStub, JavaPackage_resolve,
JavaPackage_convert, JavaPackage_finalize
};
JavaPackageDef
standard_java_packages[] = {
{"java", NULL, PKG_USER},
{"java.applet", NULL, PKG_USER},
{"java.awt", NULL, PKG_USER},
{"java.awt.datatransfer",
NULL, PKG_SYSTEM},
{"java.awt.event", NULL, PKG_SYSTEM},
{"java.awt.image", NULL, PKG_SYSTEM},
{"java.awt.peer", NULL, PKG_SYSTEM},
{"java.beans", NULL, PKG_USER},
{"java.io", NULL, PKG_SYSTEM},
{"java.lang", NULL, PKG_USER},
{"java.lang.reflect", NULL, PKG_SYSTEM},
{"java.math", NULL, PKG_SYSTEM},
{"java.net", NULL, PKG_USER},
{"java.rmi", NULL, PKG_USER},
{"java.rmi.dgc", NULL, PKG_USER},
{"java.rmi.user", NULL, PKG_USER},
{"java.rmi.registry", NULL, PKG_USER},
{"java.rmi.server", NULL, PKG_USER},
{"java.security", NULL, PKG_USER},
{"java.security.acl", NULL, PKG_SYSTEM},
{"java.security.interfaces",
NULL, PKG_SYSTEM},
{"java.sql", NULL, PKG_USER},
{"java.text", NULL, PKG_USER},
{"java.text.resources", NULL, PKG_SYSTEM},
{"java.util", NULL, PKG_USER},
{"java.util.zip", NULL, PKG_SYSTEM},
{"netscape", NULL, PKG_USER},
{"netscape.applet", NULL, PKG_SYSTEM},
{"netscape.application",NULL, PKG_SYSTEM},
{"netscape.debug", NULL, PKG_SYSTEM},
{"netscape.javascript", NULL, PKG_SYSTEM},
{"netscape.ldap", NULL, PKG_SYSTEM},
{"netscape.misc", NULL, PKG_SYSTEM},
{"netscape.net", NULL, PKG_SYSTEM},
{"netscape.plugin", NULL, PKG_SYSTEM},
{"netscape.util", NULL, PKG_SYSTEM},
{"netscape.secfile", NULL, PKG_SYSTEM},
{"netscape.security", NULL, PKG_SYSTEM},
{"netscape.WAI", NULL, PKG_SYSTEM},
{"sun", NULL, PKG_USER},
{"Packages", "", PKG_USER},
{NULL, NULL, 0}
};
/*
* Pre-define a hierarchy of JavaPackage objects.
* Pre-defining a Java package at initialization time is not necessary, but
* it will make package lookup faster and, more importantly, will avoid
* unnecessary network accesses if classes are being loaded over the network.
*/
static JSBool
pre_define_java_packages(JSContext *cx, JSObject *global_obj,
JavaPackageDef *predefined_packages)
{
JSBool package_exists;
JSObject *parent_obj;
JavaPackageDef *package_def;
char *simple_name, *cp, *package_name, *path;
int flags;
if (!predefined_packages)
return JS_TRUE;
/* Iterate over all pre-defined Java packages */
for (package_def = predefined_packages; package_def->name; package_def++) {
package_name = path = NULL;
parent_obj = global_obj;
package_name = strdup(package_def->name);
if (!package_name)
goto out_of_memory;
/* Walk the chain of JavaPackage objects to get to the parent of the
rightmost sub-package in the fully-qualified package name. */
for (simple_name = strtok(package_name, "."); 1; simple_name = strtok(NULL, ".")) {
jsval v;
if (!simple_name) {
JS_ReportError(cx, "Package %s defined twice ?", package_name);
goto error;
}
/* Check to see if the sub-package already exists */
quiet_resolve_failure = JS_TRUE;
package_exists = JS_LookupProperty(cx, parent_obj, simple_name, &v) && JSVAL_IS_OBJECT(v);
quiet_resolve_failure = JS_FALSE;
if (package_exists) {
parent_obj = JSVAL_TO_OBJECT(v);
continue;
} else {
/* New package objects should only be created at the terminal
sub-package in a fully-qualified package-name */
if (strtok(NULL, ".")) {
JS_ReportError(cx, "Illegal predefined package definition for %s",
package_def->name);
goto error;
}
if (package_def->path) {
path = strdup(package_def->path);
if (!path)
goto out_of_memory;
} else {
/*
* The default path is specified, so create it from the
* fully-qualified package name.
*/
path = strdup(package_def->name);
if (!path)
goto out_of_memory;
/* Transform package name, e.g. "java.lang" ==> "java/lang" */
for (cp = path; *cp != '\0'; cp++) {
if (*cp == '.')
*cp = '/';
}
}
flags = package_def->flags;
parent_obj = define_JavaPackage(cx, parent_obj, simple_name, path, flags);
if (!parent_obj)
goto error;
free(path);
break;
}
}
free(package_name);
}
return JS_TRUE;
out_of_memory:
JS_ReportOutOfMemory(cx);
error:
JS_FREE_IF(cx, package_name);
JS_FREE_IF(cx, path);
return JS_FALSE;
}
static JSBool
JavaPackage_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
{
if (!JS_InstanceOf(cx, obj, &JavaPackage_class, argv))
return JS_FALSE;
return JavaPackage_convert(cx, obj, JSTYPE_STRING, rval);
}
static JSFunctionSpec JavaPackage_methods[] = {
{"toString", JavaPackage_toString, 0},
{0}
};
/*
* One-time initialization for the JavaPackage class. (This is not
* run once per thread, rather it's run once for a given JSContext.)
*/
JSBool
jsj_init_JavaPackage(JSContext *cx, JSObject *global_obj,
JavaPackageDef *additional_predefined_packages) {
/* Define JavaPackage class */
if (!JS_InitClass(cx, global_obj, 0, &JavaPackage_class,
0, 0, 0, JavaPackage_methods, 0, 0))
return JS_FALSE;
/* Add top-level packages, e.g. : java, netscape, sun */
if (!pre_define_java_packages(cx, global_obj, standard_java_packages))
return JS_FALSE;
if (!pre_define_java_packages(cx, global_obj, additional_predefined_packages))
return JS_FALSE;
return JS_TRUE;
}

View File

@@ -0,0 +1,180 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the code for reading and writing elements of a Java array.
*/
#include "jsj_private.h" /* LiveConnect internals */
/*
* Read the Java value at a given index into a Java array and convert it
* to a JS value. The array_component_signature describes the type of
* the resulting Java value, which can be a primitive type or an object type.
* More specifically it can be an array type in the case of multidimensional
* arrays.
*/
JSBool
jsj_GetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
JavaSignature *array_component_signature,
jsval *vp)
{
jvalue java_value;
JavaSignatureChar component_type;
#define GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
(*jEnv)->Get##Type##ArrayRegion(jEnv, java_array, index, 1, \
&java_value.member); \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_ReportJavaError(cx, jEnv, "Error reading element of " \
"Java primitive array"); \
return JS_FALSE; \
}
component_type = array_component_signature->type;
switch(component_type) {
case JAVA_SIGNATURE_BYTE:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
break;
case JAVA_SIGNATURE_INT:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
java_value.l = (*jEnv)->GetObjectArrayElement(jEnv, java_array, index);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_ReportJavaError(cx, jEnv, "Error reading Java object array");
return JS_FALSE;
}
break;
#undef GET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return jsj_ConvertJavaValueToJSValue(cx, jEnv, array_component_signature, &java_value, vp);
}
JSBool
jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize index,
JavaSignature *array_component_signature,
jsval js_val)
{
int dummy_cost;
jvalue java_value;
JavaSignatureChar component_type;
JSBool is_local_ref;
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, array_component_signature,
&dummy_cost, &java_value, &is_local_ref))
return JS_FALSE;
#define SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \
(*jEnv)->Set##Type##ArrayRegion(jEnv, java_array, index, 1, \
&java_value.member); \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_ReportJavaError(cx, jEnv, "Error assigning to element of " \
"Java primitive array"); \
return JS_FALSE; \
}
component_type = array_component_signature->type;
switch(component_type) {
case JAVA_SIGNATURE_BYTE:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Short,s);
break;
case JAVA_SIGNATURE_INT:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
(*jEnv)->SetObjectArrayElement(jEnv, java_array, index, java_value.l);
if (is_local_ref) \
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_ReportJavaError(cx, jEnv, "Error assigning to Java object array");
return JS_FALSE;
}
break;
#undef SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return JS_TRUE;
}

View File

@@ -0,0 +1,605 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the code that constructs and manipulates JavaClassDescriptor
* structs, which are the native wrappers for Java classes.
* JavaClassDescriptors are used to describe the signatures of methods and
* fields. There is a JavaClassDescriptor associated with the reflection of
* each Java Object.
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
#include "jsj_hash.h" /* Hash tables */
/* A one-to-one mapping between all referenced java.lang.Class objects and
their corresponding JavaClassDescriptor objects */
static JSJHashTable *java_class_reflections;
/*
* Given a JVM handle to a java.lang.Class object, malloc a C-string
* containing the UTF8 encoding of the fully qualified name of the class.
* It's the caller's responsibility to free the returned string.
*
* If an error occurs, NULL is returned and the error reporter called.
*/
const char *
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
jstring java_class_name_jstr;
const char *java_class_name;
/* Get java.lang.String object containing class name */
java_class_name_jstr =
(*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getName);
if (!java_class_name_jstr)
goto error;
/* Convert to UTF8 encoding and copy */
java_class_name = jsj_DupJavaStringUTF(cx, jEnv, java_class_name_jstr);
if (!java_class_name)
return NULL;
return java_class_name;
error:
jsj_UnexpectedJavaError(cx, jEnv, "Can't get Java class name using"
"java.lang.Class.getName()");
return NULL;
}
/*
* Convert in-place a string of the form "java.lang.String" into "java/lang/String".
* Though the former style is conventionally used by Java programmers, the latter is
* what the JNI functions require.
*/
void
jsj_MakeJNIClassname(char * class_name)
{
char * c;
for (c = class_name; *c; c++)
if (*c == '.')
*c = '/';
}
/*
* Classify an instance of java.lang.Class as either one of the primitive
* types, e.g. int, char, etc., as an array type or as a non-array object type
* (subclass of java.lang.Object) by returning the appropriate enum member.
*
*/
static JavaSignatureChar
get_signature_type(JSContext *cx, JavaClassDescriptor *class_descriptor)
{
JavaSignatureChar type;
const char *java_class_name;
/* Get UTF8 encoding of class name */
java_class_name = class_descriptor->name;
PR_ASSERT(java_class_name);
if (!java_class_name)
return JAVA_SIGNATURE_UNKNOWN;
if (!strcmp(java_class_name, "byte"))
type = JAVA_SIGNATURE_BYTE;
else if (!strcmp(java_class_name, "char"))
type = JAVA_SIGNATURE_CHAR;
else if (!strcmp(java_class_name, "float"))
type = JAVA_SIGNATURE_FLOAT;
else if (!strcmp(java_class_name, "double"))
type = JAVA_SIGNATURE_DOUBLE;
else if (!strcmp(java_class_name, "int"))
type = JAVA_SIGNATURE_INT;
else if (!strcmp(java_class_name, "long"))
type = JAVA_SIGNATURE_LONG;
else if (!strcmp(java_class_name, "short"))
type = JAVA_SIGNATURE_SHORT;
else if (!strcmp(java_class_name, "boolean"))
type = JAVA_SIGNATURE_BOOLEAN;
else if (!strcmp(java_class_name, "void"))
type = JAVA_SIGNATURE_VOID;
else
/* Well, I guess it's a Java class, then. */
type = JAVA_SIGNATURE_CLASS;
return type;
}
static JSBool
is_java_array_class(JNIEnv *jEnv, jclass java_class)
{
return (*jEnv)->CallBooleanMethod(jEnv, java_class, jlClass_isArray);
}
/*
* Return the class of a Java array's component type. This is not the same
* as the array's element type. For example, the component type of an array
* of type SomeType[][][] is SomeType[][], but its element type is SomeType.
*
* If an error occurs, NULL is returned and an error reported.
*/
static jclass
get_java_array_component_class(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
jclass result;
result = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getComponentType);
if (!result) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't get Java array component class using "
"java.lang.Class.getComponentType()");
return NULL;
}
return result;
}
/*
* Given a Java class, fill in the signature structure that describes the class.
* If an error occurs, JS_FALSE is returned and the error reporter called.
*/
static JSBool
compute_java_class_signature(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature)
{
jclass java_class = signature->java_class;
if (is_java_array_class(jEnv, java_class)) {
jclass component_class;
signature->type = JAVA_SIGNATURE_ARRAY;
component_class = get_java_array_component_class(cx, jEnv, java_class);
if (!component_class)
return JS_FALSE;
signature->array_component_signature =
jsj_GetJavaClassDescriptor(cx, jEnv, component_class);
if (!signature->array_component_signature)
return JS_FALSE;
} else {
signature->type = get_signature_type(cx, signature);
}
return JS_TRUE;
}
/*
* Convert a JavaSignature object into a string format as used by
* the JNI functions, e.g. java.lang.Object ==> "Ljava/lang/Object;"
* The caller is responsible for freeing the resulting string.
*
* If an error is encountered, NULL is returned and an error reported.
*/
const char *
jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature)
{
char *sig;
if (signature->type == JAVA_SIGNATURE_CLASS) {
/* A non-array object class */
sig = PR_smprintf("L%s;", signature->name);
if (sig)
jsj_MakeJNIClassname(sig);
} else if (signature->type == JAVA_SIGNATURE_ARRAY) {
/* An array class */
const char *component_signature_string;
component_signature_string =
jsj_ConvertJavaSignatureToString(cx, signature->array_component_signature);
if (!component_signature_string)
return NULL;
sig = PR_smprintf("[%s", component_signature_string);
JS_free(cx, (char*)component_signature_string);
} else {
/* A primitive class */
sig = PR_smprintf("%c", (char)signature->type);
}
if (!sig) {
JS_ReportOutOfMemory(cx);
return NULL;
}
return sig;
}
/*
* Convert a JavaSignature object into a human-readable string format as seen
* in Java source files, e.g. "byte", or "int[][]" or "java.lang.String".
* The caller is responsible for freeing the resulting string.
*
* If an error is encountered, NULL is returned and an error reported.
*/
const char *
jsj_ConvertJavaSignatureToHRString(JSContext *cx,
JavaSignature *signature)
{
char *sig;
JavaSignature *acs;
if (signature->type == JAVA_SIGNATURE_ARRAY) {
/* An array class */
const char *component_signature_string;
acs = signature->array_component_signature;
component_signature_string =
jsj_ConvertJavaSignatureToHRString(cx, acs);
if (!component_signature_string)
return NULL;
sig = PR_smprintf("%s[]", component_signature_string);
JS_free(cx, (char*)component_signature_string);
} else {
/* A primitive class or a non-array object class */
sig = JS_strdup(cx, signature->name);
}
if (!sig) {
JS_ReportOutOfMemory(cx);
return NULL;
}
return sig;
}
static void
destroy_java_member_descriptor(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
{
JavaMethodSpec *method, *next_method;
if (member_descriptor->field)
jsj_DestroyFieldSpec(cx, jEnv, member_descriptor->field);
method = member_descriptor->methods;
while (method) {
next_method = method->next;
jsj_DestroyMethodSpec(cx, jEnv, method);
method = next_method;
}
if (member_descriptor->invoke_func_obj)
JS_RemoveRoot(cx, &member_descriptor->invoke_func_obj);
}
static void
destroy_class_member_descriptors(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *member_descriptor)
{
JavaMemberDescriptor *next_member;
while (member_descriptor) {
next_member = member_descriptor->next;
destroy_java_member_descriptor(cx, jEnv, member_descriptor);
member_descriptor = next_member;
}
}
static void
destroy_class_descriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
{
JS_FREE_IF(cx, (char *)class_descriptor->name);
if (class_descriptor->java_class) {
JSJ_HashTableRemove(java_class_reflections,
class_descriptor->java_class, (void*)jEnv);
(*jEnv)->DeleteGlobalRef(jEnv, class_descriptor->java_class);
}
if (class_descriptor->array_component_signature)
jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor->array_component_signature);
destroy_class_member_descriptors(cx, jEnv, class_descriptor->instance_members);
destroy_class_member_descriptors(cx, jEnv, class_descriptor->static_members);
destroy_class_member_descriptors(cx, jEnv, class_descriptor->constructors);
JS_free(cx, class_descriptor);
}
static JavaClassDescriptor *
new_class_descriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
JavaClassDescriptor *class_descriptor;
class_descriptor = (JavaClassDescriptor *)JS_malloc(cx, sizeof(JavaClassDescriptor));
if (!class_descriptor)
return NULL;
memset(class_descriptor, 0, sizeof(JavaClassDescriptor));
class_descriptor->name = jsj_GetJavaClassName(cx, jEnv, java_class);
if (!class_descriptor->name)
goto error;
java_class = (*jEnv)->NewGlobalRef(jEnv, java_class);
if (!java_class) {
jsj_UnexpectedJavaError(cx, jEnv, "Unable to reference Java class");
goto error;
}
class_descriptor->java_class = java_class;
if (!compute_java_class_signature(cx, jEnv, class_descriptor))
goto error;
class_descriptor->modifiers =
(*jEnv)->CallIntMethod(jEnv, java_class, jlClass_getModifiers);
class_descriptor->ref_count = 1;
if (!JSJ_HashTableAdd(java_class_reflections, java_class, class_descriptor,
(void*)jEnv))
goto error;
return class_descriptor;
error:
destroy_class_descriptor(cx, jEnv, class_descriptor);
return NULL;
}
/* Trivial helper for jsj_DiscardJavaClassReflections(), below */
static PRIntn
enumerate_remove_java_class(JSJHashEntry *he, PRIntn i, void *arg)
{
JNIEnv *jEnv = (JNIEnv*)arg;
jclass java_class;
JavaClassDescriptor *class_descriptor;
class_descriptor = (JavaClassDescriptor*)he->value;
java_class = class_descriptor->java_class;
(*jEnv)->DeleteGlobalRef(jEnv, java_class);
class_descriptor->java_class = NULL;
return HT_ENUMERATE_REMOVE;
}
/* This shutdown routine discards all JNI references to Java objects
that have been reflected into JS, even if there are still references
to them from JS. */
void
jsj_DiscardJavaClassReflections(JNIEnv *jEnv)
{
if (java_class_reflections) {
JSJ_HashTableEnumerateEntries(java_class_reflections,
enumerate_remove_java_class,
(void*)jEnv);
JSJ_HashTableDestroy(java_class_reflections);
java_class_reflections = NULL;
}
}
extern JavaClassDescriptor *
jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class)
{
JavaClassDescriptor *class_descriptor;
class_descriptor = JSJ_HashTableLookup(java_class_reflections,
(const void *)java_class,
(void*)jEnv);
if (!class_descriptor)
return new_class_descriptor(cx, jEnv, java_class);
PR_ASSERT(class_descriptor->ref_count > 0);
class_descriptor->ref_count++;
return class_descriptor;
}
void
jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor)
{
if (!--class_descriptor->ref_count)
destroy_class_descriptor(cx, jEnv, class_descriptor);
}
static JSBool
reflect_java_methods_and_fields(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
JSBool reflect_statics_only)
{
JavaMemberDescriptor *member_descriptor;
if (reflect_statics_only)
class_descriptor->static_members_reflected = JS_TRUE;
else
class_descriptor->instance_members_reflected = JS_TRUE;
if (!jsj_ReflectJavaMethods(cx, jEnv, class_descriptor, reflect_statics_only))
return JS_FALSE;
if (!jsj_ReflectJavaFields(cx, jEnv, class_descriptor, reflect_statics_only))
return JS_FALSE;
if (reflect_statics_only) {
member_descriptor = class_descriptor->static_members;
while (member_descriptor) {
class_descriptor->num_static_members++;
member_descriptor = member_descriptor->next;
}
} else {
member_descriptor = class_descriptor->instance_members;
while (member_descriptor) {
class_descriptor->num_instance_members++;
member_descriptor = member_descriptor->next;
}
}
return JS_TRUE;
}
JavaMemberDescriptor *
jsj_GetClassStaticMembers(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->static_members_reflected)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
return class_descriptor->static_members;
}
JavaMemberDescriptor *
jsj_GetClassInstanceMembers(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->instance_members_reflected)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_FALSE);
return class_descriptor->instance_members;
}
JavaMemberDescriptor *
jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jsid id)
{
JavaMemberDescriptor *member_descriptor;
member_descriptor = jsj_GetClassStaticMembers(cx, jEnv, class_descriptor);
while (member_descriptor) {
if (id == member_descriptor->id)
return member_descriptor;
member_descriptor = member_descriptor->next;
}
return NULL;
}
JavaMemberDescriptor *
jsj_GetJavaStaticMemberDescriptor(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring member_name_jstr)
{
JavaMemberDescriptor *member_descriptor;
jsid id;
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
return NULL;
member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
if (member_descriptor)
return member_descriptor;
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
if (!member_descriptor)
return NULL;
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
if (!member_descriptor->name) {
JS_free(cx, member_descriptor);
return NULL;
}
member_descriptor->id = id;
member_descriptor->next = class_descriptor->static_members;
class_descriptor->static_members = member_descriptor;
return member_descriptor;
}
JavaMemberDescriptor *
jsj_GetJavaClassConstructors(JSContext *cx,
JavaClassDescriptor *class_descriptor)
{
JavaMemberDescriptor *member_descriptor;
if (class_descriptor->constructors)
return class_descriptor->constructors;
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
if (!member_descriptor)
return NULL;
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
member_descriptor->name = JS_strdup(cx, "<init>");
if (!member_descriptor->name) {
JS_free(cx, member_descriptor);
return NULL;
}
class_descriptor->constructors = member_descriptor;
return member_descriptor;
}
JavaMemberDescriptor *
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor)
{
if (!class_descriptor->static_members_reflected)
reflect_java_methods_and_fields(cx, jEnv, class_descriptor, JS_TRUE);
return class_descriptor->constructors;
}
JavaMemberDescriptor *
jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jsid id)
{
JavaMemberDescriptor *member_descriptor;
member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
while (member_descriptor) {
if (id == member_descriptor->id)
return member_descriptor;
member_descriptor = member_descriptor->next;
}
return NULL;
}
JavaMemberDescriptor *
jsj_GetJavaMemberDescriptor(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring member_name_jstr)
{
JavaMemberDescriptor *member_descriptor;
jsid id;
if (!JavaStringToId(cx, jEnv, member_name_jstr, &id))
return NULL;
member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
if (member_descriptor)
return member_descriptor;
member_descriptor = JS_malloc(cx, sizeof(JavaMemberDescriptor));
if (!member_descriptor)
return NULL;
memset(member_descriptor, 0, sizeof(JavaMemberDescriptor));
member_descriptor->name = jsj_DupJavaStringUTF(cx, jEnv, member_name_jstr);
if (!member_descriptor->name) {
JS_free(cx, member_descriptor);
return NULL;
}
member_descriptor->id = id;
member_descriptor->next = class_descriptor->instance_members;
class_descriptor->instance_members = member_descriptor;
return member_descriptor;
}
JSBool
jsj_InitJavaClassReflectionsTable()
{
java_class_reflections =
JSJ_NewHashTable(64, jsj_HashJavaObject, jsj_JavaObjectComparator,
NULL, NULL, NULL);
if (!java_class_reflections)
return JS_FALSE;
return JS_TRUE;
}

View File

@@ -0,0 +1,806 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* Below is the code that converts between Java and JavaScript values of all
* types.
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
/* Floating-point double utilities, stolen from jsnum.h */
#ifdef IS_LITTLE_ENDIAN
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
#else
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
#endif
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
#define JSDOUBLE_IS_NaN(x) \
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
#define JSDOUBLE_IS_INFINITE(x) \
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
!JSDOUBLE_LO32(x))
static JSBool
convert_js_obj_to_JSObject_wrapper(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj,
JavaSignature *signature,
int *cost, jobject *java_value)
{
if (!njJSObject) {
if (java_value)
JS_ReportError(cx, "Couldn't convert JavaScript object to an "
"instance of netscape.javascript.JSObject "
"because that class could not be loaded.");
return JS_FALSE;
}
if (!(*jEnv)->IsAssignableFrom(jEnv, njJSObject, signature->java_class))
return JS_FALSE;
if (!java_value)
return JS_TRUE;
*java_value = jsj_WrapJSObject(cx, jEnv, js_obj);
return (*java_value != NULL);
}
jstring
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str)
{
jstring result;
result = (*jEnv)->NewString(jEnv, JS_GetStringChars(js_str),
JS_GetStringLength(js_str));
if (!result) {
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance "
"of java.lang.String");
}
return result;
}
/*
* Convert a JS value to an instance of java.lang.Object or one of its subclasses,
* performing any necessary type coercion. If non-trivial coercion is required,
* the cost value is incremented. If the java_value pass-by-reference argument
* is non-NULL, the resulting Java value is stored there.
*
* Returns JS_TRUE if the conversion is possible, JS_FALSE otherwise
*/
JSBool
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
int *cost, jobject *java_value, JSBool *is_local_refp)
{
JSString *jsstr;
jclass target_java_class;
PR_ASSERT(signature->type == JAVA_SIGNATURE_CLASS ||
signature->type == JAVA_SIGNATURE_ARRAY);
/* Initialize to default case, in which no new Java object is
synthesized to perform the conversion and, therefore, no JNI local
references are being held. */
*is_local_refp = JS_FALSE;
/* Get the Java type of the target value */
target_java_class = signature->java_class;
if (JSVAL_IS_OBJECT(v)) {
JSObject *js_obj = JSVAL_TO_OBJECT(v);
/* JS null is always assignable to a Java object */
if (!js_obj) {
if (java_value)
*java_value = NULL;
return JS_TRUE;
}
if (JS_InstanceOf(cx, js_obj, &JavaObject_class, 0) ||
JS_InstanceOf(cx, js_obj, &JavaArray_class, 0)) {
/* The source value is a Java object wrapped inside a JavaScript
object. Unwrap the JS object and return the original Java
object if it's class makes it assignment-compatible with the
target class using Java's assignability rules. */
JavaObjectWrapper *java_wrapper = JS_GetPrivate(cx, js_obj);
jobject java_obj = java_wrapper->java_obj;
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, target_java_class)) {
if (java_value)
*java_value = java_obj;
return JS_TRUE;
}
#ifdef LIVECONNECT_IMPROVEMENTS
/* Don't allow wrapped Java objects to be converted to strings */
goto conversion_error;
#else
/* Fall through, to attempt conversion to a Java string */
#endif
} else if (JS_InstanceOf(cx, js_obj, &JavaClass_class, 0)) {
/* We're dealing with the reflection of a Java class */
JavaClassDescriptor *java_class_descriptor = JS_GetPrivate(cx, js_obj);
/* Check if target type is java.lang.Class class */
if ((*jEnv)->IsAssignableFrom(jEnv, jlClass, target_java_class)) {
if (java_value)
*java_value = java_class_descriptor->java_class;
return JS_TRUE;
}
/* Check if target type is netscape.javascript.JSObject wrapper class */
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
if (*java_value)
*is_local_refp = JS_TRUE;
return JS_TRUE;
}
/* Fall through, to attempt conversion to a Java string */
} else if (JS_InstanceOf(cx, js_obj, &JavaMember_class, 0)) {
if (!JS_ConvertValue(cx, v, JSTYPE_OBJECT, &v))
return JS_FALSE;
return jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
java_value, is_local_refp);
} else {
/* Otherwise, see if the target type is the netscape.javascript.JSObject
wrapper class or one of its subclasses, in which case a
reference is passed to the original JS object by wrapping it
inside an instance of netscape.javascript.JSObject */
if (convert_js_obj_to_JSObject_wrapper(cx, jEnv, js_obj, signature, cost, java_value)) {
return JS_TRUE;
}
/* Fall through, to attempt conversion to a Java string */
}
} else if (JSVAL_IS_NUMBER(v)) {
/* JS numbers, integral or not, can be converted to instances of java.lang.Double */
if ((*jEnv)->IsAssignableFrom(jEnv, jlDouble, target_java_class)) {
if (java_value) {
jsdouble d;
if (!JS_ValueToNumber(cx, v, &d))
goto conversion_error;
*java_value = (*jEnv)->NewObject(jEnv, jlDouble, jlDouble_Double, d);
if (*java_value) {
*is_local_refp = JS_TRUE;
} else {
jsj_UnexpectedJavaError(cx, jEnv,
"Couldn't construct instance of java.lang.Double");
return JS_FALSE;
}
}
#ifdef LIVECONNECT_IMPROVEMENTS
(*cost)++;
#endif
return JS_TRUE;
}
/* Fall through, to attempt conversion to a java.lang.String ... */
} else if (JSVAL_IS_BOOLEAN(v)) {
/* JS boolean values can be converted to instances of java.lang.Boolean */
if ((*jEnv)->IsAssignableFrom(jEnv, jlBoolean, target_java_class)) {
if (java_value) {
JSBool b;
if (!JS_ValueToBoolean(cx, v, &b))
goto conversion_error;
*java_value =
(*jEnv)->NewObject(jEnv, jlBoolean, jlBoolean_Boolean, b);
if (*java_value) {
*is_local_refp = JS_TRUE;
} else {
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't construct instance "
"of java.lang.Boolean");
return JS_FALSE;
}
}
#ifdef LIVECONNECT_IMPROVEMENTS
(*cost)++;
#endif
return JS_TRUE;
}
/* Fall through, to attempt conversion to a java.lang.String ... */
}
/* If no other conversion is possible, see if the target type is java.lang.String */
if ((*jEnv)->IsAssignableFrom(jEnv, jlString, target_java_class)) {
#ifdef LIVECONNECT_IMPROVEMENTS
JSBool is_string = JSVAL_IS_STRING(v);
#endif
/* Convert to JS string, if necessary, and then to a Java Unicode string */
jsstr = JS_ValueToString(cx, v);
if (jsstr) {
if (java_value) {
*java_value = jsj_ConvertJSStringToJavaString(cx, jEnv, jsstr);
if (*java_value) {
*is_local_refp = JS_TRUE;
} else {
return JS_FALSE;
}
}
#ifdef LIVECONNECT_IMPROVEMENTS
if (!is_string)
(*cost)++;
#endif
return JS_TRUE;
}
}
conversion_error:
return JS_FALSE;
}
/* Valid ranges for Java numeric types */
#define jbyte_MAX_VALUE 127.0
#define jbyte_MIN_VALUE -128.0
#define jchar_MAX_VALUE 65535.0
#define jchar_MIN_VALUE 0.0
#define jshort_MAX_VALUE 32767.0
#define jshort_MIN_VALUE -32768.0
#define jint_MAX_VALUE 2147483647.0
#define jint_MIN_VALUE -2147483648.0
#define jlong_MAX_VALUE 9223372036854775807.0
#define jlong_MIN_VALUE -9223372036854775808.0
/* Utility macro for jsj_ConvertJSValueToJavaValue(), below */
#define JSVAL_TO_INTEGRAL_JVALUE(type_name, member_name, member_type, jsval, java_value) \
if (!JSVAL_IS_NUMBER(v)) { \
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v)) \
goto conversion_error; \
(*cost)++; \
} \
{ \
member_type member_name; \
\
if (JSVAL_IS_INT(v)) { \
jsint ival = JSVAL_TO_INT(v); \
member_name = (member_type) ival; \
\
/* Check to see if the jsval's magnitude is too large to be \
representable in the target java type */ \
if (member_name != ival) \
goto numeric_conversion_error; \
} else { \
jdouble dval = *JSVAL_TO_DOUBLE(v); \
\
/* NaN becomes zero when converted to integral value */ \
if (JSDOUBLE_IS_NaN(dval)) \
member_name = 0; \
\
/* Unrepresentably large numbers, including infinities, */ \
/* cause an error. */ \
else if ((dval > member_type ## _MAX_VALUE) || \
(dval < member_type ## _MIN_VALUE)) { \
goto numeric_conversion_error; \
} else \
member_name = (member_type) dval; \
\
/* Don't allow a non-integral number to be converted \
to an integral type */ \
/* Actually, we have to allow this for LC1 compatibility */ \
/* if ((jdouble)member_name != dval) \
(*cost)++; */ \
} \
if (java_value) \
java_value->member_name = member_name; \
}
#if XP_MAC
/* on MRJ jlong is typedef'd to wide, which is a struct. */
#include <Math64.h>
static jsint jlong_to_jsint(jlong lvalue)
{
SInt64 val = WideToSInt64(lvalue);
return S32Set(val);
}
static jlong jsint_to_jlong(jsint ivalue)
{
SInt64 val = S64Set(ivalue);
wide wval =SInt64ToWide(val);
return *(jlong*)&wval;
}
static jdouble jlong_to_jdouble(jlong lvalue)
{
SInt64 val = WideToSInt64(lvalue);
return SInt64ToLongDouble(val);
}
static jlong jdouble_to_jlong(jdouble dvalue)
{
SInt64 val = LongDoubleToSInt64(dvalue);
wide wval = SInt64ToWide(val);
return *(jlong*)&wval;
}
/* Mac utility macro for jsj_ConvertJSValueToJavaValue(), below */
#define JSVAL_TO_JLONG_JVALUE(member_name, member_type, jsvalue, java_value) \
if (!JSVAL_IS_NUMBER(jsvalue)) { \
if (!JS_ConvertValue(cx, jsvalue, JSTYPE_NUMBER, &jsvalue)) \
goto conversion_error; \
(*cost)++; \
} \
{ \
member_type member_name; \
\
if (JSVAL_IS_INT(jsvalue)) { \
jsint ival = JSVAL_TO_INT(jsvalue); \
member_name = jsint_to_jlong(ival); \
\
} else { \
jdouble dval = *JSVAL_TO_DOUBLE(jsvalue); \
\
/* NaN becomes zero when converted to integral value */ \
if (JSDOUBLE_IS_NaN(dval)) \
member_name = jsint_to_jlong(0); \
\
/* Unrepresentably large numbers, including infinities, */ \
/* cause an error. */ \
else if ((dval > member_type ## _MAX_VALUE) || \
(dval < member_type ## _MIN_VALUE)) { \
goto numeric_conversion_error; \
} else \
member_name = jdouble_to_jlong(dval); \
\
/* Don't allow a non-integral number to be converted \
to an integral type */ \
/* Actually, we have to allow this for LC1 compatibility */ \
/*if (jlong_to_jdouble(member_name) != dval) \
(*cost)++;*/ \
} \
if (java_value) \
java_value->member_name = member_name; \
}
#else
#define jlong_to_jdouble(lvalue) ((jdouble) lvalue)
#endif
/*
* Convert a JS value to a Java value of the given type signature. The cost
* variable is incremented if coercion is required, e.g. the source value is
* a string, but the target type is a boolean.
*
* Returns JS_FALSE if no conversion is possible, either because the jsval has
* a type that is wholly incompatible with the Java value, or because a scalar
* jsval can't be represented in a variable of the target type without loss of
* precision, e.g. the source value is "4.2" but the destination type is byte.
* If conversion is not possible and java_value is non-NULL, the JS error
* reporter is called with an appropriate message.
*/
JSBool
jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v,
JavaSignature *signature,
int *cost, jvalue *java_value, JSBool *is_local_refp)
{
JavaSignatureChar type;
JSBool success = JS_FALSE;
/* Initialize to default case, in which no new Java object is
synthesized to perform the conversion and, therefore, no JNI local
references are being held. */
*is_local_refp = JS_FALSE;
type = signature->type;
switch (type) {
case JAVA_SIGNATURE_BOOLEAN:
if (!JSVAL_IS_BOOLEAN(v)) {
if (!JS_ConvertValue(cx, v, JSTYPE_BOOLEAN, &v))
goto conversion_error;
(*cost)++;
}
if (java_value)
java_value->z = (jboolean)(JSVAL_TO_BOOLEAN(v) == JS_TRUE);
break;
case JAVA_SIGNATURE_SHORT:
JSVAL_TO_INTEGRAL_JVALUE(short, s, jshort, v, java_value);
break;
case JAVA_SIGNATURE_BYTE:
JSVAL_TO_INTEGRAL_JVALUE(byte, b, jbyte, v, java_value);
break;
case JAVA_SIGNATURE_CHAR:
/* A one-character string can be converted into a character */
if (JSVAL_IS_STRING(v) && (JS_GetStringLength(JSVAL_TO_STRING(v)) == 1)) {
v = INT_TO_JSVAL(*JS_GetStringChars(JSVAL_TO_STRING(v)));
}
JSVAL_TO_INTEGRAL_JVALUE(char, c, jchar, v, java_value);
break;
case JAVA_SIGNATURE_INT:
JSVAL_TO_INTEGRAL_JVALUE(int, i, jint, v, java_value);
break;
case JAVA_SIGNATURE_LONG:
#if XP_MAC
JSVAL_TO_JLONG_JVALUE(j, jlong, v, java_value);
#else
JSVAL_TO_INTEGRAL_JVALUE(long, j, jlong, v, java_value);
#endif
break;
case JAVA_SIGNATURE_FLOAT:
if (!JSVAL_IS_NUMBER(v)) {
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
goto conversion_error;
(*cost)++;
}
if (java_value) {
if (JSVAL_IS_INT(v))
java_value->f = (jfloat) JSVAL_TO_INT(v);
else
java_value->f = (jfloat) *JSVAL_TO_DOUBLE(v);
}
break;
case JAVA_SIGNATURE_DOUBLE:
if (!JSVAL_IS_NUMBER(v)) {
if (!JS_ConvertValue(cx, v, JSTYPE_NUMBER, &v))
goto conversion_error;
(*cost)++;
}
if (java_value) {
if (JSVAL_IS_INT(v))
java_value->d = (jdouble) JSVAL_TO_INT(v);
else
java_value->d = (jdouble) *JSVAL_TO_DOUBLE(v);
}
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, v, signature, cost,
&java_value->l, is_local_refp))
goto conversion_error;
break;
default:
PR_ASSERT(0);
return JS_FALSE;
}
/* Success */
return JS_TRUE;
numeric_conversion_error:
success = JS_TRUE;
/* Fall through ... */
conversion_error:
if (java_value) {
const char *jsval_string;
JSString *jsstr;
jsval_string = NULL;
jsstr = JS_ValueToString(cx, v);
if (jsstr)
jsval_string = JS_GetStringBytes(jsstr);
if (!jsval_string)
jsval_string = "";
JS_ReportError(cx, "Unable to convert JavaScript value %s to "
"Java value of type %s",
jsval_string, signature->name);
return JS_FALSE;
}
return success;
}
/*
* A utility routine to create a JavaScript Unicode string from a
* java.lang.String (Unicode) string.
*/
JSString *
jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str)
{
JSString *js_str;
jboolean is_copy;
const jchar *ucs2_str;
jchar *copy_ucs2_str;
jsize ucs2_str_len, num_bytes;
ucs2_str_len = (*jEnv)->GetStringLength(jEnv, java_str);
ucs2_str = (*jEnv)->GetStringChars(jEnv, java_str, &is_copy);
if (!ucs2_str) {
jsj_UnexpectedJavaError(cx, jEnv,
"Unable to extract native Unicode from Java string");
return NULL;
}
js_str = NULL;
/* The string data passed into JS_NewUCString() is
not copied, so make a copy of the Unicode character vector. */
num_bytes = ucs2_str_len * sizeof(jchar);
copy_ucs2_str = (jchar*)JS_malloc(cx, num_bytes);
if (!copy_ucs2_str)
goto done;
memcpy(copy_ucs2_str, ucs2_str, num_bytes);
js_str = JS_NewUCString(cx, (jschar*)copy_ucs2_str, ucs2_str_len);
done:
(*jEnv)->ReleaseStringChars(jEnv, java_str, ucs2_str);
return js_str;
}
/*
* Attempt to obtain a JS string representation of a Java object.
* The java_obj argument must be of type java.lang.Object or a subclass.
* If java_obj is a Java string, it's value is simply extracted and
* copied into a JS string. Otherwise, the toString() method is called
* on java_obj.
*/
JSBool
jsj_ConvertJavaObjectToJSString(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp)
{
JSString *js_str;
jstring java_str;
jmethodID toString;
/* Create a Java string, unless java_obj is already a java.lang.String */
if ((*jEnv)->IsInstanceOf(jEnv, java_obj, jlString)) {
java_str = java_obj;
} else {
jclass java_class;
java_class = class_descriptor->java_class;
toString = (*jEnv)->GetMethodID(jEnv, java_class, "toString",
"()Ljava/lang/String;");
if (!toString) {
/* All Java objects have a toString method */
jsj_UnexpectedJavaError(cx, jEnv, "No toString() method for class %s!",
class_descriptor->name);
return JS_FALSE;
}
java_str = (*jEnv)->CallObjectMethod(jEnv, java_obj, toString);
if (!java_str) {
jsj_ReportJavaError(cx, jEnv, "toString() method failed");
return JS_FALSE;
}
}
/* Extract Unicode from java.lang.String instance and convert to JS string */
js_str = jsj_ConvertJavaStringToJSString(cx, jEnv, java_str);
if (!js_str)
return JS_FALSE;
*vp = STRING_TO_JSVAL(js_str);
return JS_TRUE;
}
/*
* Convert a Java object to a number by attempting to call the
* doubleValue() method on a Java object to get a double result.
* This usually only works on instances of java.lang.Double, but the code
* is generalized to work with any Java object that supports this method.
*
* Returns JS_TRUE if the call was successful.
* Returns JS_FALSE if conversion is not possible or an error occurs.
*/
JSBool
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp)
{
jdouble d;
jmethodID doubleValue;
jclass java_class;
java_class = class_descriptor->java_class;
doubleValue = (*jEnv)->GetMethodID(jEnv, java_class, "doubleValue", "()D");
if (!doubleValue) {
/* There is no doubleValue() method for the object. Try toString()
instead and the JS engine will attempt to convert the result to
a number. */
(*jEnv)->ExceptionClear(jEnv);
return jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor,
java_obj, vp);
}
d = (*jEnv)->CallDoubleMethod(jEnv, java_obj, doubleValue);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_UnexpectedJavaError(cx, jEnv, "doubleValue() method failed");
return JS_FALSE;
}
return JS_NewDoubleValue(cx, d, vp);
}
/*
* Convert a Java object to a boolean by attempting to call the
* booleanValue() method on a Java object to get a boolean result.
* This usually only works on instances of java.lang.Boolean, but the code
* is generalized to work with any Java object that supports this method.
*
* Returns JS_TRUE if the call was successful.
* Returns JS_FALSE if conversion is not possible or an error occurs.
*/
extern JSBool
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp)
{
jboolean b;
jmethodID booleanValue;
jclass java_class;
/* Null converts to false. */
if (!java_obj) {
*vp = JSVAL_FALSE;
return JS_TRUE;
}
java_class = class_descriptor->java_class;
booleanValue = (*jEnv)->GetMethodID(jEnv, java_obj, "booleanValue", "()Z");
/* Non-null Java object does not have a booleanValue() method, so
it converts to true. */
if (!booleanValue) {
(*jEnv)->ExceptionClear(jEnv);
*vp = JSVAL_TRUE;
return JS_TRUE;
}
b = (*jEnv)->CallBooleanMethod(jEnv, java_obj, booleanValue);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_UnexpectedJavaError(cx, jEnv, "booleanValue() method failed");
return JS_FALSE;
}
*vp = BOOLEAN_TO_JSVAL(b);
return JS_TRUE;
}
/*
* Reflect a Java object into a JS value. The source object, java_obj, must
* be of type java.lang.Object or a subclass and may, therefore, be an array.
*/
JSBool
jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv,
jobject java_obj, jsval *vp)
{
jclass java_class;
JSObject *js_obj;
/* A null in Java-land is also null in JS */
if (!java_obj) {
*vp = JSVAL_NULL;
return JS_TRUE;
}
java_class = (*jEnv)->GetObjectClass(jEnv, java_obj);
/*
* If it's an instance of netscape.javascript.JSObject, i.e. a wrapper
* around a JS object that has been passed into the Java world, unwrap
* it to obtain the original JS object.
*/
if (njJSObject && (*jEnv)->IsInstanceOf(jEnv, java_obj, njJSObject)) {
#ifdef PRESERVE_JSOBJECT_IDENTITY
js_obj = (JSObject *)((*jEnv)->GetIntField(jEnv, java_obj, njJSObject_internal));
#else
js_obj = jsj_UnwrapJSObjectWrapper(jEnv, java_obj);
#endif
PR_ASSERT(js_obj);
if (!js_obj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(js_obj);
return JS_TRUE;
}
/*
* Instances of java.lang.String are wrapped so we can call methods on
* them, but they convert to a JS string if used in a string context.
*/
/* TODO - let's get rid of this annoying "feature" */
/* otherwise, wrap it inside a JavaObject */
js_obj = jsj_WrapJavaObject(cx, jEnv, java_obj, java_class);
if (!js_obj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(js_obj);
return JS_TRUE;
}
/*
* Convert a Java value (primitive or object) to a JS value.
*
* This is usually an infallible operation, but JS_FALSE is returned
* on an out-of-memory condition and the error reporter is called.
*/
JSBool
jsj_ConvertJavaValueToJSValue(JSContext *cx, JNIEnv *jEnv,
JavaSignature *signature,
jvalue *java_value,
jsval *vp)
{
int32 ival32;
switch (signature->type) {
case JAVA_SIGNATURE_VOID:
*vp = JSVAL_VOID;
return JS_TRUE;
case JAVA_SIGNATURE_BYTE:
*vp = INT_TO_JSVAL((jsint)java_value->b);
return JS_TRUE;
case JAVA_SIGNATURE_CHAR:
*vp = INT_TO_JSVAL((jsint)java_value->c);
return JS_TRUE;
case JAVA_SIGNATURE_SHORT:
*vp = INT_TO_JSVAL((jsint)java_value->s);
return JS_TRUE;
case JAVA_SIGNATURE_INT:
ival32 = java_value->i;
if (INT_FITS_IN_JSVAL(ival32)) {
*vp = INT_TO_JSVAL((jsint) ival32);
return JS_TRUE;
} else {
return JS_NewDoubleValue(cx, ival32, vp);
}
case JAVA_SIGNATURE_BOOLEAN:
*vp = BOOLEAN_TO_JSVAL((JSBool) java_value->z);
return JS_TRUE;
case JAVA_SIGNATURE_LONG:
return JS_NewDoubleValue(cx, jlong_to_jdouble(java_value->j), vp);
case JAVA_SIGNATURE_FLOAT:
return JS_NewDoubleValue(cx, java_value->f, vp);
case JAVA_SIGNATURE_DOUBLE:
return JS_NewDoubleValue(cx, java_value->d, vp);
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_value->l, vp);
default:
PR_ASSERT(0);
return JS_FALSE;
}
}

View File

@@ -0,0 +1,383 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the code used to reflect Java fields as properties of
* JavaObject objects and the code to access those fields.
*
*/
#include <stdlib.h>
#include "jsj_private.h" /* LiveConnect internals */
/*
* Add a single field, described by java_field, to the JavaMemberDescriptor
* named by field_name within the given JavaClassDescriptor.
*
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
*/
static JSBool
add_java_field_to_class_descriptor(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring field_name_jstr,
jobject java_field, /* a java.lang.reflect.Field */
jint modifiers)
{
jclass fieldType;
jfieldID fieldID;
jclass java_class;
JSBool is_static_field;
JavaMemberDescriptor *member_descriptor = NULL;
const char *sig_cstr = NULL;
const char *field_name = NULL;
JavaSignature *signature = NULL;
JavaFieldSpec *field_spec = NULL;
is_static_field = modifiers & ACC_STATIC;
if (is_static_field) {
member_descriptor = jsj_GetJavaStaticMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
} else {
member_descriptor = jsj_GetJavaMemberDescriptor(cx, jEnv, class_descriptor, field_name_jstr);
}
if (!member_descriptor)
goto error;
field_spec = (JavaFieldSpec*)JS_malloc(cx, sizeof(JavaFieldSpec));
if (!field_spec)
goto error;
field_spec->modifiers = modifiers;
/* Get the Java class corresponding to the type of the field */
fieldType = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getType);
if (!fieldType) {
jsj_UnexpectedJavaError(cx, jEnv,
"Unable to determine type of field using"
" java.lang.reflect.Field.getType()");
goto error;
}
signature = jsj_GetJavaClassDescriptor(cx, jEnv, fieldType);
if (!signature)
goto error;
field_spec->signature = signature;
field_name = jsj_DupJavaStringUTF(cx, jEnv, field_name_jstr);
if (!field_name)
goto error;
field_spec->name = field_name;
/* Compute the JNI-style (string-based) signature of the field type */
sig_cstr = jsj_ConvertJavaSignatureToString(cx, signature);
if (!sig_cstr)
goto error;
/* Compute the JNI fieldID and cache it for quick field access */
java_class = class_descriptor->java_class;
if (is_static_field)
fieldID = (*jEnv)->GetStaticFieldID(jEnv, java_class, field_name, sig_cstr);
else
fieldID = (*jEnv)->GetFieldID(jEnv, java_class, field_name, sig_cstr);
if (!fieldID) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't get Java field ID for class %s, field %s (sig=%s)",
class_descriptor->name, field_name, sig_cstr);
goto error;
}
field_spec->fieldID = fieldID;
JS_free(cx, (char*)sig_cstr);
member_descriptor->field = field_spec;
/* Success */
return JS_TRUE;
error:
if (field_spec) {
JS_FREE_IF(cx, (char*)field_spec->name);
JS_free(cx, field_spec);
}
JS_FREE_IF(cx, (char*)sig_cstr);
if (signature)
jsj_ReleaseJavaClassDescriptor(cx, jEnv, signature);
return JS_FALSE;
}
/*
* Free up a JavaFieldSpec and all its resources.
*/
void
jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field)
{
JS_FREE_IF(cx, (char*)field->name);
jsj_ReleaseJavaClassDescriptor(cx, jEnv, field->signature);
JS_free(cx, field);
}
/*
* Add a JavaMemberDescriptor to the collection of members in class_descriptor
* for every public field of the identified Java class. (A separate collection
* is kept in class_descriptor for static and instance members.)
* If reflect_only_static_fields is set, instance fields are not reflected. If
* it isn't set, only instance fields are reflected and static fields are not
* reflected.
*
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
*/
JSBool
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor,
JSBool reflect_only_static_fields)
{
int i;
JSBool ok;
jint modifiers;
jobject java_field;
jstring field_name_jstr;
jarray joFieldArray;
jsize num_fields;
jclass java_class;
/* Get a java array of java.lang.reflect.Field objects, by calling
java.lang.Class.getFields(). */
java_class = class_descriptor->java_class;
joFieldArray = (*jEnv)->CallObjectMethod(jEnv, java_class, jlClass_getFields);
if (!joFieldArray) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't determine Java object's fields "
"using java.lang.Class.getFields()");
return JS_FALSE;
}
/* Iterate over the class fields */
num_fields = (*jEnv)->GetArrayLength(jEnv, joFieldArray);
for (i = 0; i < num_fields; i++) {
/* Get the i'th reflected field */
java_field = (*jEnv)->GetObjectArrayElement(jEnv, joFieldArray, i);
if (!java_field) {
jsj_UnexpectedJavaError(cx, jEnv, "Can't access a Field[] array");
return JS_FALSE;
}
/* Get the field modifiers, e.g. static, public, private, etc. */
modifiers = (*jEnv)->CallIntMethod(jEnv, java_field, jlrField_getModifiers);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't access a Field's modifiers using"
"java.lang.reflect.Field.getModifiers()");
return JS_FALSE;
}
/* Don't allow access to private or protected Java fields. */
if (!(modifiers & ACC_PUBLIC))
continue;
/* Reflect all instance fields or all static fields, but not both */
if (reflect_only_static_fields != ((modifiers & ACC_STATIC) != 0))
continue;
/* Determine the unqualified name of the field */
field_name_jstr = (*jEnv)->CallObjectMethod(jEnv, java_field, jlrField_getName);
if (!field_name_jstr) {
jsj_UnexpectedJavaError(cx, jEnv,
"Can't obtain a Field's name"
"java.lang.reflect.Field.getName()");
return JS_FALSE;
}
/* Add a JavaFieldSpec object to the JavaClassDescriptor */
ok = add_java_field_to_class_descriptor(cx, jEnv, class_descriptor, field_name_jstr,
java_field, modifiers);
if (!ok)
return JS_FALSE;
}
/* Success */
return JS_TRUE;
}
/*
* Read the value of a Java field and return it as a JavaScript value.
* If the field is static, then java_obj is a Java class, otherwise
* it's a Java instance object.
*
* Returns JS_TRUE on success. Otherwise, returns JS_FALSE and reports an error.
*/
JSBool
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
jobject java_obj, jsval *vp)
{
JSBool is_static_field;
jvalue java_value;
JavaSignature *signature;
JavaSignatureChar field_type;
jfieldID fieldID = field_spec->fieldID;
is_static_field = field_spec->modifiers & ACC_STATIC;
#define GET_JAVA_FIELD(Type,member) \
PR_BEGIN_MACRO \
if (is_static_field) \
java_value.member = \
(*jEnv)->GetStatic##Type##Field(jEnv, java_obj, fieldID); \
else \
java_value.member = \
(*jEnv)->Get##Type##Field(jEnv, java_obj, fieldID); \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_UnexpectedJavaError(cx, jEnv, "Error reading Java field"); \
return JS_FALSE; \
} \
PR_END_MACRO
signature = field_spec->signature;
field_type = signature->type;
switch(field_type) {
case JAVA_SIGNATURE_BYTE:
GET_JAVA_FIELD(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
GET_JAVA_FIELD(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
GET_JAVA_FIELD(Short,s);
break;
case JAVA_SIGNATURE_INT:
GET_JAVA_FIELD(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
GET_JAVA_FIELD(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
GET_JAVA_FIELD(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
GET_JAVA_FIELD(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
GET_JAVA_FIELD(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
GET_JAVA_FIELD(Object,l);
break;
#undef GET_JAVA_FIELD
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return jsj_ConvertJavaValueToJSValue(cx, jEnv, signature, &java_value, vp);
}
JSBool
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
jclass java_obj, jsval js_val)
{
JSBool is_static_field, is_local_ref;
int dummy_cost;
jvalue java_value;
JavaSignature *signature;
JavaSignatureChar field_type;
jfieldID fieldID = field_spec->fieldID;
is_static_field = field_spec->modifiers & ACC_STATIC;
#define SET_JAVA_FIELD(Type,member) \
PR_BEGIN_MACRO \
if (is_static_field) { \
(*jEnv)->SetStatic##Type##Field(jEnv, java_obj, fieldID, \
java_value.member); \
} else { \
(*jEnv)->Set##Type##Field(jEnv, java_obj, fieldID,java_value.member);\
} \
if ((*jEnv)->ExceptionOccurred(jEnv)) { \
jsj_UnexpectedJavaError(cx, jEnv, "Error assigning to Java field"); \
return JS_FALSE; \
} \
PR_END_MACRO
signature = field_spec->signature;
if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost,
&java_value, &is_local_ref))
return JS_FALSE;
field_type = signature->type;
switch(field_type) {
case JAVA_SIGNATURE_BYTE:
SET_JAVA_FIELD(Byte,b);
break;
case JAVA_SIGNATURE_CHAR:
SET_JAVA_FIELD(Char,c);
break;
case JAVA_SIGNATURE_SHORT:
SET_JAVA_FIELD(Short,s);
break;
case JAVA_SIGNATURE_INT:
SET_JAVA_FIELD(Int,i);
break;
case JAVA_SIGNATURE_BOOLEAN:
SET_JAVA_FIELD(Boolean,z);
break;
case JAVA_SIGNATURE_LONG:
SET_JAVA_FIELD(Long,j);
break;
case JAVA_SIGNATURE_FLOAT:
SET_JAVA_FIELD(Float,f);
break;
case JAVA_SIGNATURE_DOUBLE:
SET_JAVA_FIELD(Double,d);
break;
case JAVA_SIGNATURE_CLASS:
case JAVA_SIGNATURE_ARRAY:
SET_JAVA_FIELD(Object,l);
if (is_local_ref)
(*jEnv)->DeleteLocalRef(jEnv, java_value.l);
break;
#undef SET_JAVA_FIELD
default:
PR_ASSERT(0); /* Unknown java type signature */
return JS_FALSE;
}
return JS_TRUE;
}

View File

@@ -0,0 +1,487 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This is a copy of the NSPR hash-table library, but it has been slightly
* modified to allow an additional argument to be passed into the hash
* key-comparision function. This is used to maintain thread-safety by
* passing in a JNIEnv pointer to the key-comparison function rather
* than storing it in a global. All types,function names, etc. have
* been renamed from their original NSPR names to protect the innocent.
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_hash.h"
#include "prtypes.h"
#ifdef NSPR20
# include "prlog.h"
# include "prbit.h"
#else
# include "prassert.h"
#endif
/* Compute the number of buckets in ht */
#define NBUCKETS(ht) (1 << (JSJ_HASH_BITS - (ht)->shift))
/* The smallest table has 16 buckets */
#define MINBUCKETSLOG2 4
#define MINBUCKETS (1 << MINBUCKETSLOG2)
/* Compute the maximum entries given n buckets that we will tolerate, ~90% */
#define OVERLOADED(n) ((n) - ((n) >> 3))
/* Compute the number of entries below which we shrink the table by half */
#define UNDERLOADED(n) (((n) > MINBUCKETS) ? ((n) >> 2) : 0)
/*
** Stubs for default hash allocator ops.
*/
static void *
DefaultAllocTable(void *pool, size_t size)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
return malloc(size);
}
static void
DefaultFreeTable(void *pool, void *item)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
free(item);
}
static JSJHashEntry *
DefaultAllocEntry(void *pool, const void *key)
{
#if defined(XP_MAC)
#pragma unused (pool,key)
#endif
return malloc(sizeof(JSJHashEntry));
}
static void
DefaultFreeEntry(void *pool, JSJHashEntry *he, PRUintn flag)
{
#if defined(XP_MAC)
#pragma unused (pool)
#endif
if (flag == HT_FREE_ENTRY)
free(he);
}
static JSJHashAllocOps defaultHashAllocOps = {
DefaultAllocTable, DefaultFreeTable,
DefaultAllocEntry, DefaultFreeEntry
};
PR_IMPLEMENT(JSJHashTable *)
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
JSJHashAllocOps *allocOps, void *allocPriv)
{
JSJHashTable *ht;
PRUint32 nb;
if (n <= MINBUCKETS) {
n = MINBUCKETSLOG2;
} else {
n = PR_CeilingLog2(n);
if ((PRInt32)n < 0)
return 0;
}
if (!allocOps) allocOps = &defaultHashAllocOps;
ht = (*allocOps->allocTable)(allocPriv, sizeof *ht);
if (!ht)
return 0;
memset(ht, 0, sizeof *ht);
ht->shift = JSJ_HASH_BITS - n;
n = 1 << n;
#if defined(XP_PC) && !defined(_WIN32)
if (n > 16000) {
(*allocOps->freeTable)(allocPriv, ht);
return 0;
}
#endif /* WIN16 */
nb = n * sizeof(JSJHashEntry *);
ht->buckets = (*allocOps->allocTable)(allocPriv, nb);
if (!ht->buckets) {
(*allocOps->freeTable)(allocPriv, ht);
return 0;
}
memset(ht->buckets, 0, nb);
ht->keyHash = keyHash;
ht->keyCompare = keyCompare;
ht->valueCompare = valueCompare;
ht->allocOps = allocOps;
ht->allocPriv = allocPriv;
return ht;
}
PR_IMPLEMENT(void)
JSJ_HashTableDestroy(JSJHashTable *ht)
{
PRUint32 i, n;
JSJHashEntry *he, *next;
JSJHashAllocOps *allocOps = ht->allocOps;
void *allocPriv = ht->allocPriv;
n = NBUCKETS(ht);
for (i = 0; i < n; i++) {
for (he = ht->buckets[i]; he; he = next) {
next = he->next;
(*allocOps->freeEntry)(allocPriv, he, HT_FREE_ENTRY);
}
}
#ifdef DEBUG
memset(ht->buckets, 0xDB, n * sizeof ht->buckets[0]);
#endif
(*allocOps->freeTable)(allocPriv, ht->buckets);
#ifdef DEBUG
memset(ht, 0xDB, sizeof *ht);
#endif
(*allocOps->freeTable)(allocPriv, ht);
}
/*
** Multiplicative hash, from Knuth 6.4.
*/
#define GOLDEN_RATIO 0x9E3779B9U
PR_IMPLEMENT(JSJHashEntry **)
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg)
{
JSJHashEntry *he, **hep, **hep0;
JSJHashNumber h;
#ifdef HASHMETER
ht->nlookups++;
#endif
h = keyHash * GOLDEN_RATIO;
h >>= ht->shift;
hep = hep0 = &ht->buckets[h];
while ((he = *hep) != 0) {
if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key, arg)) {
/* Move to front of chain if not already there */
if (hep != hep0) {
*hep = he->next;
he->next = *hep0;
*hep0 = he;
}
return hep0;
}
hep = &he->next;
#ifdef HASHMETER
ht->nsteps++;
#endif
}
return hep;
}
PR_IMPLEMENT(JSJHashEntry *)
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep,
JSJHashNumber keyHash, const void *key, void *value,
void *arg)
{
PRUint32 i, n;
JSJHashEntry *he, *next, **oldbuckets;
PRUint32 nb;
/* Grow the table if it is overloaded */
n = NBUCKETS(ht);
if (ht->nentries >= OVERLOADED(n)) {
#ifdef HASHMETER
ht->ngrows++;
#endif
ht->shift--;
oldbuckets = ht->buckets;
#if defined(XP_PC) && !defined(_WIN32)
if (2 * n > 16000)
return 0;
#endif /* WIN16 */
nb = 2 * n * sizeof(JSJHashEntry *);
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
if (!ht->buckets) {
ht->buckets = oldbuckets;
return 0;
}
memset(ht->buckets, 0, nb);
for (i = 0; i < n; i++) {
for (he = oldbuckets[i]; he; he = next) {
next = he->next;
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
PR_ASSERT(*hep == 0);
he->next = 0;
*hep = he;
}
}
#ifdef DEBUG
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
#endif
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
}
/* Make a new key value entry */
he = (*ht->allocOps->allocEntry)(ht->allocPriv, key);
if (!he)
return 0;
he->keyHash = keyHash;
he->key = key;
he->value = value;
he->next = *hep;
*hep = he;
ht->nentries++;
return he;
}
PR_IMPLEMENT(JSJHashEntry *)
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg)
{
JSJHashNumber keyHash;
JSJHashEntry *he, **hep;
keyHash = (*ht->keyHash)(key, arg);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
if ((he = *hep) != 0) {
/* Hit; see if values match */
if ((*ht->valueCompare)(he->value, value, arg)) {
/* key,value pair is already present in table */
return he;
}
if (he->value)
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_VALUE);
he->value = value;
return he;
}
return JSJ_HashTableRawAdd(ht, hep, keyHash, key, value, arg);
}
PR_IMPLEMENT(void)
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg)
{
PRUint32 i, n;
JSJHashEntry *next, **oldbuckets;
PRUint32 nb;
*hep = he->next;
(*ht->allocOps->freeEntry)(ht->allocPriv, he, HT_FREE_ENTRY);
/* Shrink table if it's underloaded */
n = NBUCKETS(ht);
if (--ht->nentries < UNDERLOADED(n)) {
#ifdef HASHMETER
ht->nshrinks++;
#endif
ht->shift++;
oldbuckets = ht->buckets;
nb = n * sizeof(JSJHashEntry*) / 2;
ht->buckets = (*ht->allocOps->allocTable)(ht->allocPriv, nb);
if (!ht->buckets) {
ht->buckets = oldbuckets;
return;
}
memset(ht->buckets, 0, nb);
for (i = 0; i < n; i++) {
for (he = oldbuckets[i]; he; he = next) {
next = he->next;
hep = JSJ_HashTableRawLookup(ht, he->keyHash, he->key, arg);
PR_ASSERT(*hep == 0);
he->next = 0;
*hep = he;
}
}
#ifdef DEBUG
memset(oldbuckets, 0xDB, n * sizeof oldbuckets[0]);
#endif
(*ht->allocOps->freeTable)(ht->allocPriv, oldbuckets);
}
}
PR_IMPLEMENT(PRBool)
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg)
{
JSJHashNumber keyHash;
JSJHashEntry *he, **hep;
keyHash = (*ht->keyHash)(key, arg);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
if ((he = *hep) == 0)
return PR_FALSE;
/* Hit; remove element */
JSJ_HashTableRawRemove(ht, hep, he, arg);
return PR_TRUE;
}
PR_IMPLEMENT(void *)
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg)
{
JSJHashNumber keyHash;
JSJHashEntry *he, **hep;
keyHash = (*ht->keyHash)(key, arg);
hep = JSJ_HashTableRawLookup(ht, keyHash, key, arg);
if ((he = *hep) != 0) {
return he->value;
}
return 0;
}
/*
** Iterate over the entries in the hash table calling func for each
** entry found. Stop if "f" says to (return value & PR_ENUMERATE_STOP).
** Return a count of the number of elements scanned.
*/
PR_IMPLEMENT(int)
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg)
{
JSJHashEntry *he, **hep;
PRUint32 i, nbuckets;
int rv, n = 0;
JSJHashEntry *todo = 0;
nbuckets = NBUCKETS(ht);
for (i = 0; i < nbuckets; i++) {
hep = &ht->buckets[i];
while ((he = *hep) != 0) {
rv = (*f)(he, n, arg);
n++;
if (rv & (HT_ENUMERATE_REMOVE | HT_ENUMERATE_UNHASH)) {
*hep = he->next;
if (rv & HT_ENUMERATE_REMOVE) {
he->next = todo;
todo = he;
}
} else {
hep = &he->next;
}
if (rv & HT_ENUMERATE_STOP) {
goto out;
}
}
}
out:
hep = &todo;
while ((he = *hep) != 0) {
JSJ_HashTableRawRemove(ht, hep, he, arg);
}
return n;
}
#ifdef HASHMETER
#include <math.h>
#include <stdio.h>
PR_IMPLEMENT(void)
JSJ_HashTableDumpMeter(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
{
double mean, variance;
PRUint32 nchains, nbuckets;
PRUint32 i, n, maxChain, maxChainLen;
JSJHashEntry *he;
variance = 0;
nchains = 0;
maxChainLen = 0;
nbuckets = NBUCKETS(ht);
for (i = 0; i < nbuckets; i++) {
he = ht->buckets[i];
if (!he)
continue;
nchains++;
for (n = 0; he; he = he->next)
n++;
variance += n * n;
if (n > maxChainLen) {
maxChainLen = n;
maxChain = i;
}
}
mean = (double)ht->nentries / nchains;
variance = fabs(variance / nchains - mean * mean);
fprintf(fp, "\nHash table statistics:\n");
fprintf(fp, " number of lookups: %u\n", ht->nlookups);
fprintf(fp, " number of entries: %u\n", ht->nentries);
fprintf(fp, " number of grows: %u\n", ht->ngrows);
fprintf(fp, " number of shrinks: %u\n", ht->nshrinks);
fprintf(fp, " mean steps per hash: %g\n", (double)ht->nsteps
/ ht->nlookups);
fprintf(fp, "mean hash chain length: %g\n", mean);
fprintf(fp, " standard deviation: %g\n", sqrt(variance));
fprintf(fp, " max hash chain length: %u\n", maxChainLen);
fprintf(fp, " max hash chain: [%u]\n", maxChain);
for (he = ht->buckets[maxChain], i = 0; he; he = he->next, i++)
if ((*dump)(he, i, fp) != HT_ENUMERATE_NEXT)
break;
}
#endif /* HASHMETER */
PR_IMPLEMENT(int)
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp)
{
int count;
count = JSJ_HashTableEnumerateEntries(ht, dump, fp);
#ifdef HASHMETER
JSJ_HashTableDumpMeter(ht, dump, fp);
#endif
return count;
}
PR_IMPLEMENT(JSJHashNumber)
JSJ_HashString(const void *key)
{
JSJHashNumber h;
const unsigned char *s;
h = 0;
for (s = key; *s; s++)
h = (h >> 28) ^ (h << 4) ^ *s;
return h;
}
PR_IMPLEMENT(int)
JSJ_CompareStrings(const void *v1, const void *v2)
{
return strcmp(v1, v2) == 0;
}
PR_IMPLEMENT(int)
JSJ_CompareValues(const void *v1, const void *v2)
{
return v1 == v2;
}

View File

@@ -0,0 +1,141 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This is a copy of the NSPR hash-table library, but it has been slightly
* modified to allow an additional argument to be passed into the hash
* key-comparision function. This is used to maintain thread-safety by
* passing in a JNIEnv pointer to the key-comparison function rather
* than storing it in a global. All types,function names, etc. have
* been renamed from their original NSPR names to protect the innocent.
*/
#ifndef jsj_hash_h___
#define jsj_hash_h___
/*
* API to portable hash table code.
*/
#include <stddef.h>
#include <stdio.h>
#include "prtypes.h"
PR_BEGIN_EXTERN_C
typedef struct JSJHashEntry JSJHashEntry;
typedef struct JSJHashTable JSJHashTable;
typedef PRUint32 JSJHashNumber;
#define JSJ_HASH_BITS 32
typedef JSJHashNumber (*JSJHashFunction)(const void *key, void *arg);
typedef PRIntn (*JSJHashComparator)(const void *v1, const void *v2, void *arg);
typedef PRIntn (*JSJHashEnumerator)(JSJHashEntry *he, PRIntn i, void *arg);
/* Flag bits in JSJHashEnumerator's return value */
#define HT_ENUMERATE_NEXT 0 /* continue enumerating entries */
#define HT_ENUMERATE_STOP 1 /* stop enumerating entries */
#define HT_ENUMERATE_REMOVE 2 /* remove and free the current entry */
#define HT_ENUMERATE_UNHASH 4 /* just unhash the current entry */
typedef struct JSJHashAllocOps {
void * (*allocTable)(void *pool, size_t size);
void (*freeTable)(void *pool, void *item);
JSJHashEntry * (*allocEntry)(void *pool, const void *key);
void (*freeEntry)(void *pool, JSJHashEntry *he, PRUintn flag);
} JSJHashAllocOps;
#define HT_FREE_VALUE 0 /* just free the entry's value */
#define HT_FREE_ENTRY 1 /* free value and entire entry */
struct JSJHashEntry {
JSJHashEntry *next; /* hash chain linkage */
JSJHashNumber keyHash; /* key hash function result */
const void *key; /* ptr to opaque key */
void *value; /* ptr to opaque value */
};
struct JSJHashTable {
JSJHashEntry **buckets; /* vector of hash buckets */
PRUint32 nentries; /* number of entries in table */
PRUint32 shift; /* multiplicative hash shift */
JSJHashFunction keyHash; /* key hash function */
JSJHashComparator keyCompare; /* key comparison function */
JSJHashComparator valueCompare; /* value comparison function */
JSJHashAllocOps *allocOps; /* allocation operations */
void *allocPriv; /* allocation private data */
#ifdef HASHMETER
PRUint32 nlookups; /* total number of lookups */
PRUint32 nsteps; /* number of hash chains traversed */
PRUint32 ngrows; /* number of table expansions */
PRUint32 nshrinks; /* number of table contractions */
#endif
};
/*
* Create a new hash table.
* If allocOps is null, use default allocator ops built on top of malloc().
*/
PR_EXTERN(JSJHashTable *)
JSJ_NewHashTable(PRUint32 n, JSJHashFunction keyHash,
JSJHashComparator keyCompare, JSJHashComparator valueCompare,
JSJHashAllocOps *allocOps, void *allocPriv);
PR_EXTERN(void)
JSJ_HashTableDestroy(JSJHashTable *ht);
/* Low level access methods */
PR_EXTERN(JSJHashEntry **)
JSJ_HashTableRawLookup(JSJHashTable *ht, JSJHashNumber keyHash, const void *key, void *arg);
PR_EXTERN(JSJHashEntry *)
JSJ_HashTableRawAdd(JSJHashTable *ht, JSJHashEntry **hep, JSJHashNumber keyHash,
const void *key, void *value, void *arg);
PR_EXTERN(void)
JSJ_HashTableRawRemove(JSJHashTable *ht, JSJHashEntry **hep, JSJHashEntry *he, void *arg);
/* Higher level access methods */
PR_EXTERN(JSJHashEntry *)
JSJ_HashTableAdd(JSJHashTable *ht, const void *key, void *value, void *arg);
PR_EXTERN(PRBool)
JSJ_HashTableRemove(JSJHashTable *ht, const void *key, void *arg);
PR_EXTERN(PRIntn)
JSJ_HashTableEnumerateEntries(JSJHashTable *ht, JSJHashEnumerator f, void *arg);
PR_EXTERN(void *)
JSJ_HashTableLookup(JSJHashTable *ht, const void *key, void *arg);
PR_EXTERN(PRIntn)
JSJ_HashTableDump(JSJHashTable *ht, JSJHashEnumerator dump, FILE *fp);
/* General-purpose C string hash function. */
PR_EXTERN(JSJHashNumber)
JSJ_HashString(const void *key);
/* Compare strings using strcmp(), return true if equal. */
PR_EXTERN(int)
JSJ_CompareStrings(const void *v1, const void *v2);
/* Stub function just returns v1 == v2 */
PR_EXTERN(PRIntn)
JSJ_CompareValues(const void *v1, const void *v2);
PR_END_EXTERN_C
#endif /* jsj_hash_h___ */

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,552 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* Declarations of private (internal) functions/data/types for
* JavaScript <==> Java communication.
*
*/
#ifndef _JSJAVA_PVT_H
#define _JSJAVA_PVT_H
#include "prtypes.h"
/* NSPR1 compatibility definitions */
#ifdef NSPR20
# include "prprf.h"
# include "prlog.h"
# include "plhash.h" /* NSPR hash-tables */
#else
# include "prprintf.h"
# include "prassert.h"
# include "prhash.h" /* NSPR hash-tables */
# define PRHashNumber prhashcode
#endif
#ifdef XP_MAC
# include "prosdep.h"
#endif
#include "jsj_hash.h" /* Hash tables */
#include "jni.h" /* Java Native Interface */
#include "jsapi.h" /* JavaScript engine API */
#include "jsjava.h" /* LiveConnect public API */
/*************************** Type Declarations ******************************/
/* Forward type declarations */
typedef struct JavaMemberDescriptor JavaMemberDescriptor;
typedef struct JavaMethodSpec JavaMethodSpec;
typedef struct JavaClassDescriptor JavaClassDescriptor;
typedef struct JavaClassDescriptor JavaSignature;
typedef struct CapturedJSError CapturedJSError;
typedef struct JavaMemberVal JavaMemberVal;
/*
* This enum uses the same character encoding used by the JDK to encode
* Java type signatures, but the enum is easier to debug/compile with.
*/
typedef enum {
JAVA_SIGNATURE_ARRAY = '[',
JAVA_SIGNATURE_BYTE = 'B',
JAVA_SIGNATURE_CHAR = 'C',
JAVA_SIGNATURE_CLASS = 'L',
JAVA_SIGNATURE_FLOAT = 'F',
JAVA_SIGNATURE_DOUBLE = 'D',
JAVA_SIGNATURE_INT = 'I',
JAVA_SIGNATURE_LONG = 'J',
JAVA_SIGNATURE_SHORT = 'S',
JAVA_SIGNATURE_VOID = 'V',
JAVA_SIGNATURE_BOOLEAN = 'Z',
JAVA_SIGNATURE_UNKNOWN = 0
} JavaSignatureChar;
/* The signature of a Java method consists of the signatures of all its
arguments and its return type signature. */
typedef struct JavaMethodSignature {
jsize num_args; /* Length of arg_signatures array */
JavaSignature ** arg_signatures; /* Array of argument signatures */
JavaSignature * return_val_signature; /* Return type signature */
} JavaMethodSignature;
/* A descriptor for the reflection of a single Java field */
typedef struct JavaFieldSpec {
jfieldID fieldID; /* JVM opaque access handle for field */
JavaSignature * signature; /* Java type of field */
int modifiers; /* Bitfield indicating field qualifiers */
const char * name; /* UTF8; TODO - Should support Unicode field names */
} JavaFieldSpec;
/* A descriptor for the reflection of a single Java method.
Each overloaded method has a separate corresponding JavaMethodSpec. */
struct JavaMethodSpec {
jmethodID methodID; /* JVM opaque access handle for method */
JavaMethodSignature signature;
const char * name; /* UTF8; TODO - Should support Unicode method names */
JavaMethodSpec * next; /* next method in chain of overloaded methods */
};
/*
* A descriptor for the reflection of a single member of a Java object.
* This can represent one or more Java methods and/or a single field.
* (When there is more than one method attached to a single JavaMemberDescriptor
* they are overloaded methods sharing the same simple name.) This same
* descriptor type is used for both static or instance members.
*/
struct JavaMemberDescriptor {
const char * name; /* simple name of field and/or method */
jsid id; /* hashed name for quick JS property lookup */
JavaFieldSpec * field; /* field with the given name, if any */
JavaMethodSpec * methods; /* Overloaded methods which share the same name, if any */
JavaMemberDescriptor * next; /* next descriptor in same defining class */
JSObject * invoke_func_obj; /* If non-null, JSFunction obj to invoke method */
};
/* This is the native portion of a reflected Java class */
struct JavaClassDescriptor {
const char * name; /* Name of class, e.g. "java/lang/Byte" */
JavaSignatureChar type; /* class category: primitive type, object, array */
jclass java_class; /* Opaque JVM handle to corresponding java.lang.Class */
int num_instance_members;
int num_static_members;
JSBool instance_members_reflected;
JavaMemberDescriptor * instance_members;
JSBool static_members_reflected;
JavaMemberDescriptor * static_members;
JavaMemberDescriptor * constructors;
int modifiers; /* Class declaration qualifiers,
e.g. abstract, private */
int ref_count; /* # of references to this struct */
JavaSignature * array_component_signature; /* Only non-NULL for array classes */
};
/* This is the native portion of a reflected Java method or field */
struct JavaMemberVal {
jsval field_val; /* Captured value of Java field */
jsval invoke_method_func_val; /* JSFunction wrapper around Java method invoker */
JavaMemberDescriptor * descriptor;
JavaMemberVal * next;
};
/* This is the native portion of a reflected Java object */
typedef struct JavaObjectWrapper {
jobject java_obj; /* Opaque JVM ref to Java object */
JavaClassDescriptor * class_descriptor; /* Java class info */
} JavaObjectWrapper;
/* These are definitions of the Java class/method/field modifier bits.
These really shouldn't be hard-coded here. Rather,
they should be read from java.lang.reflect.Modifier */
#define ACC_PUBLIC 0x0001 /* visible to everyone */
#define ACC_STATIC 0x0008 /* instance variable is static */
#define ACC_FINAL 0x0010 /* no further subclassing,overriding */
#define ACC_INTERFACE 0x0200 /* class is an interface */
#define ACC_ABSTRACT 0x0400 /* no definition provided */
/* A JSJavaVM structure must be created for each Java VM that is accessed
via LiveConnect */
struct JSJavaVM {
/* TODO - all LiveConnect global variables should be migrated into this
structure in order to allow more than one LiveConnect-enabled
Java VM to exist within the same process. */
SystemJavaVM * java_vm;
JNIEnv * main_thread_env; /* Main-thread Java environment */
JSBool jsj_created_java_vm;
int num_attached_threads;
JSJavaVM * next; /* next VM among all created VMs */
};
/* Per-thread state that encapsulates the connection to the Java VM */
struct JSJavaThreadState {
const char * name; /* Thread name, for debugging */
JSJavaVM * jsjava_vm; /* All per-JVM state */
JNIEnv * jEnv; /* Per-thread opaque handle to Java VM */
CapturedJSError * pending_js_errors; /* JS errors to be thrown as Java exceptions */
JSContext * cx; /* current JS context for thread */
JSJavaThreadState * next; /* next thread state among all created threads */
};
struct JavaToJSSavedState {
JSErrorReporter error_reporter;
JSJavaThreadState* java_jsj_env;
};
typedef struct JavaToJSSavedState JavaToJSSavedState;
/******************************** Globals ***********************************/
extern JSJCallbacks *JSJ_callbacks;
/* JavaScript classes that reflect Java objects */
extern JSClass JavaObject_class;
extern JSClass JavaArray_class;
extern JSClass JavaClass_class;
extern JSClass JavaMember_class;
/*
* Opaque JVM handles to Java classes, methods and objects required for
* Java reflection. These are computed and cached during initialization.
* TODO: These should be moved inside the JSJavaVM struct
*/
extern jclass jlObject; /* java.lang.Object */
extern jclass jlrConstructor; /* java.lang.reflect.Constructor */
extern jclass jlThrowable; /* java.lang.Throwable */
extern jclass jlSystem; /* java.lang.System */
extern jclass jlClass; /* java.lang.Class */
extern jclass jlBoolean; /* java.lang.Boolean */
extern jclass jlDouble; /* java.lang.Double */
extern jclass jlString; /* java.lang.String */
extern jclass njJSObject; /* netscape.javascript.JSObject */
extern jclass njJSException; /* netscape.javascript.JSException */
extern jclass njJSUtil; /* netscape.javascript.JSUtil */
extern jmethodID jlClass_getMethods; /* java.lang.Class.getMethods() */
extern jmethodID jlClass_getConstructors; /* java.lang.Class.getConstructors() */
extern jmethodID jlClass_getFields; /* java.lang.Class.getFields() */
extern jmethodID jlClass_getName; /* java.lang.Class.getName() */
extern jmethodID jlClass_getComponentType; /* java.lang.Class.getComponentType() */
extern jmethodID jlClass_getModifiers; /* java.lang.Class.getModifiers() */
extern jmethodID jlClass_isArray; /* java.lang.Class.isArray() */
extern jmethodID jlrMethod_getName; /* java.lang.reflect.Method.getName() */
extern jmethodID jlrMethod_getParameterTypes; /* java.lang.reflect.Method.getParameterTypes() */
extern jmethodID jlrMethod_getReturnType; /* java.lang.reflect.Method.getReturnType() */
extern jmethodID jlrMethod_getModifiers; /* java.lang.reflect.Method.getModifiers() */
extern jmethodID jlrConstructor_getParameterTypes; /* java.lang.reflect.Constructor.getParameterTypes() */
extern jmethodID jlrConstructor_getModifiers; /* java.lang.reflect.Constructor.getModifiers() */
extern jmethodID jlrField_getName; /* java.lang.reflect.Field.getName() */
extern jmethodID jlrField_getType; /* java.lang.reflect.Field.getType() */
extern jmethodID jlrField_getModifiers; /* java.lang.reflect.Field.getModifiers() */
extern jmethodID jlThrowable_getMessage; /* java.lang.Throwable.getMessage() */
extern jmethodID jlThrowable_toString; /* java.lang.Throwable.toString() */
extern jmethodID jlBoolean_Boolean; /* java.lang.Boolean constructor */
extern jmethodID jlBoolean_booleanValue; /* java.lang.Boolean.booleanValue() */
extern jmethodID jlDouble_Double; /* java.lang.Double constructor */
extern jmethodID jlDouble_doubleValue; /* java.lang.Double.doubleValue() */
extern jmethodID jlSystem_identityHashCode; /* java.lang.System.identityHashCode() */
extern jobject jlVoid_TYPE; /* java.lang.Void.TYPE value */
extern jmethodID njJSException_JSException; /* netscape.javascipt.JSexception constructor */
extern jmethodID njJSObject_JSObject; /* netscape.javascript.JSObject constructor */
extern jmethodID njJSUtil_getStackTrace; /* netscape.javascript.JSUtil.getStackTrace() */
extern jfieldID njJSObject_internal; /* netscape.javascript.JSObject.internal */
extern jfieldID njJSException_lineno; /* netscape.javascript.JSException.lineno */
extern jfieldID njJSException_tokenIndex; /* netscape.javascript.JSException.tokenIndex */
extern jfieldID njJSException_source; /* netscape.javascript.JSException.source */
extern jfieldID njJSException_filename; /* netscape.javascript.JSException.filename */
/**************** Java <==> JS conversions and Java types *******************/
extern JSBool
jsj_ComputeJavaClassSignature(JSContext *cx,
JavaSignature *signature,
jclass java_class);
extern const char *
jsj_ConvertJavaSignatureToString(JSContext *cx, JavaSignature *signature);
extern const char *
jsj_ConvertJavaSignatureToHRString(JSContext *cx,
JavaSignature *signature);
extern JavaMethodSignature *
jsj_InitJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, jobject method,
JavaMethodSignature *method_signature);
extern const char *
jsj_ConvertJavaMethodSignatureToString(JSContext *cx,
JavaMethodSignature *method_signature);
extern const char *
jsj_ConvertJavaMethodSignatureToHRString(JSContext *cx,
const char *method_name,
JavaMethodSignature *method_signature);
extern void
jsj_PurgeJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, JavaMethodSignature *signature);
extern JSBool
jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
int *cost, jvalue *java_value, JSBool *is_local_refp);
extern JSBool
jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature,
int *cost, jobject *java_value, JSBool *is_local_refp);
extern jstring
jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str);
extern JSBool
jsj_ConvertJavaValueToJSValue(JSContext *cx, JNIEnv *jEnv, JavaSignature *signature,
jvalue *java_value, jsval *vp);
extern JSBool
jsj_ConvertJavaObjectToJSValue(JSContext *cx, JNIEnv *jEnv,
jobject java_obj, jsval *vp);
extern JSString *
jsj_ConvertJavaStringToJSString(JSContext *cx, JNIEnv *jEnv, jstring java_str);
extern JSBool
jsj_ConvertJavaObjectToJSString(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp);
extern JSBool
jsj_ConvertJavaObjectToJSNumber(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp);
extern JSBool
jsj_ConvertJavaObjectToJSBoolean(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jobject java_obj, jsval *vp);
extern JSJavaThreadState *
jsj_enter_js(JNIEnv *jEnv, jobject java_wrapper_obj,
JSContext **cxp, JSObject **js_objp, JavaToJSSavedState* saved_state);
extern JSBool
jsj_exit_js(JSContext *cx, JSJavaThreadState *jsj_env, JavaToJSSavedState* original_state);
extern JavaClassDescriptor *
jsj_get_jlObject_descriptor(JSContext *cx, JNIEnv *jEnv);
extern JSBool
jsj_remove_js_obj_reflection_from_hashtable(JSContext *cx, JSObject *js_obj);
extern JSBool
jsj_init_js_obj_reflections_table();
/************************ Java package reflection **************************/
extern JSBool
jsj_init_JavaPackage(JSContext *, JSObject *,
JavaPackageDef *predefined_packages);
/************************* Java class reflection ***************************/
extern JSBool
jsj_init_JavaClass(JSContext *cx, JSObject *global_obj);
extern void
jsj_DiscardJavaClassReflections(JNIEnv *jEnv);
extern const char *
jsj_GetJavaClassName(JSContext *cx, JNIEnv *jEnv, jclass java_class);
extern JavaClassDescriptor *
jsj_GetJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, jclass java_class);
extern void
jsj_ReleaseJavaClassDescriptor(JSContext *cx, JNIEnv *jEnv, JavaClassDescriptor *class_descriptor);
extern JSObject *
jsj_define_JavaClass(JSContext *cx, JNIEnv *jEnv, JSObject *obj,
const char *unqualified_class_name,
jclass jclazz);
extern JavaMemberDescriptor *
jsj_GetJavaMemberDescriptor(JSContext *cx,
JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring member_name);
extern JavaMemberDescriptor *
jsj_LookupJavaMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jsid id);
extern JavaMemberDescriptor *
jsj_LookupJavaStaticMemberDescriptorById(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jsid id);
extern JavaMemberDescriptor *
jsj_GetJavaStaticMemberDescriptor(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
jstring member_name);
extern JavaMemberDescriptor *
jsj_GetJavaClassConstructors(JSContext *cx,
JavaClassDescriptor *class_descriptor);
extern JavaMemberDescriptor *
jsj_LookupJavaClassConstructors(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor);
extern JavaMemberDescriptor *
jsj_GetClassInstanceMembers(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor);
extern JavaMemberDescriptor *
jsj_GetClassStaticMembers(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor);
extern JSBool
jsj_InitJavaClassReflectionsTable();
/************************* Java field reflection ***************************/
extern JSBool
jsj_GetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
jobject java_obj, jsval *vp);
extern JSBool
jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec,
jobject java_obj, jsval js_val);
extern JSBool
jsj_ReflectJavaFields(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
JSBool reflect_only_static_fields);
extern void
jsj_DestroyFieldSpec(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field);
/************************* Java method reflection ***************************/
extern JSBool
jsj_JavaInstanceMethodWrapper(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *vp);
extern JSBool
jsj_JavaStaticMethodWrapper(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *vp);
extern JSBool
jsj_JavaConstructorWrapper(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *vp);
extern JSBool
jsj_ReflectJavaMethods(JSContext *cx, JNIEnv *jEnv,
JavaClassDescriptor *class_descriptor,
JSBool reflect_only_static_methods);
extern void
jsj_DestroyMethodSpec(JSContext *cx, JNIEnv *jEnv, JavaMethodSpec *method_spec);
/************************* Java member reflection ***************************/
extern JSBool
jsj_init_JavaMember(JSContext *, JSObject *);
extern JSBool
jsj_ReflectJavaMethodsAndFields(JSContext *cx, JavaClassDescriptor *class_descriptor,
JSBool reflect_only_statics);
extern JSObject *
jsj_CreateJavaMember(JSContext *cx, jsval method_val, jsval field_val);
/************************* Java object reflection **************************/
extern JSBool
jsj_init_JavaObject(JSContext *, JSObject *);
extern JSObject *
jsj_WrapJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_obj, jclass java_class);
extern void
jsj_DiscardJavaObjReflections(JNIEnv *jEnv);
extern JSBool
JavaObject_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
extern void
JavaObject_finalize(JSContext *cx, JSObject *obj);
extern JSBool
JavaObject_resolve(JSContext *cx, JSObject *obj, jsval id);
extern JSBool
JavaObject_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
extern JSBool
JavaObject_getPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
/************************* Java array reflection ***************************/
extern JSBool
jsj_init_JavaArray(JSContext *cx, JSObject *global_obj);
extern JSBool
jsj_GetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array,
jsize index, JavaSignature *array_component_signature,
jsval *vp);
extern JSBool
jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array,
jsize index, JavaSignature *array_component_signature,
jsval js_val);
/********************* JavaScript object reflection ************************/
extern jobject
jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj);
extern JSObject *
jsj_UnwrapJSObjectWrapper(JNIEnv *jEnv, jobject java_wrapper_obj);
extern void
jsj_ClearPendingJSErrors(JSJavaThreadState *jsj_env);
extern JSBool
jsj_ReportUncaughtJSException(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception);
/**************************** Utilities ************************************/
extern void
jsj_ReportJavaError(JSContext *cx, JNIEnv *env, const char *format, ...);
extern void
jsj_UnexpectedJavaError(JSContext *cx, JNIEnv *env, const char *format, ...);
extern const char *
jsj_GetJavaErrorMessage(JNIEnv *env);
extern void
jsj_LogError(const char *error_msg);
PR_CALLBACK JSJHashNumber
jsj_HashJavaObject(const void *key, void* env);
PR_CALLBACK intN
jsj_JavaObjectComparator(const void *v1, const void *v2, void *arg);
extern JSJavaThreadState *
jsj_MapJavaThreadToJSJavaThreadState(JNIEnv *jEnv, char **errp);
extern void
jsj_MakeJNIClassname(char *jClassName);
extern const char *
jsj_ClassNameOfJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_object);
extern jsize
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array);
extern JSBool
JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp);
extern const char *
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr);
JSJavaThreadState *
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp);
JSJavaThreadState *
jsj_SetJavaJSJEnv(JSJavaThreadState* java_jsj_env);
#ifdef DEBUG
#define DEBUG_LOG(args) printf args
#endif
#define JS_FREE_IF(cx, x) \
PR_BEGIN_MACRO \
if (x) \
JS_free(cx, x); \
PR_END_MACRO
#endif /* _JSJAVA_PVT_H */

View File

@@ -0,0 +1,361 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains low-level utility code.
*
*/
#include <stdlib.h>
#include <string.h>
#include "jsj_private.h" /* LiveConnect internals */
#include "jsjava.h" /* External LiveConnect API */
/*
* This is a hash-table utility routine that computes the hash code of a Java
* object by calling java.lang.System.identityHashCode()
*/
PR_CALLBACK JSJHashNumber
jsj_HashJavaObject(const void *key, void* env)
{
PRHashNumber hash_code;
jobject java_obj;
JNIEnv *jEnv;
java_obj = (jobject)key;
jEnv = (JNIEnv*) env;
hash_code = (*jEnv)->CallStaticIntMethod(jEnv, jlSystem,
jlSystem_identityHashCode, java_obj);
PR_ASSERT(!(*jEnv)->ExceptionOccurred(jEnv));
return hash_code;
}
/*
* This is a hash-table utility routine for comparing two Java objects.
* It's not possible to use the == operator to directly compare two jobject's,
* since they're opaque references and aren't guaranteed to be simple pointers
* or handles (though they may be in some JVM implementations). Instead,
* use the JNI routine for comparing the two objects.
*/
PR_CALLBACK intN
jsj_JavaObjectComparator(const void *v1, const void *v2, void *arg)
{
jobject java_obj1, java_obj2;
JNIEnv *jEnv;
jEnv = (JNIEnv*)arg;
java_obj1 = (jobject)v1;
java_obj2 = (jobject)v2;
if (java_obj1 == java_obj2)
return 1;
return (*jEnv)->IsSameObject(jEnv, java_obj1, java_obj2);
}
/*
* Return a UTF8, null-terminated encoding of a Java string. The string must
* be free'ed by the caller.
*
* If an error occurs, returns NULL and calls the JS error reporter.
*/
const char *
jsj_DupJavaStringUTF(JSContext *cx, JNIEnv *jEnv, jstring jstr)
{
const char *str, *retval;
str = (*jEnv)->GetStringUTFChars(jEnv, jstr, 0);
if (!str) {
jsj_UnexpectedJavaError(cx, jEnv, "Can't get UTF8 characters from "
"Java string");
return NULL;
}
retval = JS_strdup(cx, str);
(*jEnv)->ReleaseStringUTFChars(jEnv, jstr, str);
return retval;
}
JSBool
JavaStringToId(JSContext *cx, JNIEnv *jEnv, jstring jstr, jsid *idp)
{
const jschar *ucs2;
JSString *jsstr;
jsize ucs2_len;
jsval val;
ucs2 = (*jEnv)->GetStringChars(jEnv, jstr, 0);
if (!ucs2) {
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain Unicode characters"
"from Java string");
return JS_FALSE;
}
ucs2_len = (*jEnv)->GetStringLength(jEnv, jstr);
jsstr = JS_InternUCStringN(cx, ucs2, ucs2_len);
(*jEnv)->ReleaseStringChars(jEnv, jstr, ucs2);
if (!jsstr)
return JS_FALSE;
val = STRING_TO_JSVAL(jsstr);
JS_ValueToId(cx, STRING_TO_JSVAL(jsstr), idp);
return JS_TRUE;
}
/* Not used ?
const char *
jsj_ClassNameOfJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_object)
{
jobject java_class;
java_class = (*jEnv)->GetObjectClass(jEnv, java_object);
if (!java_class) {
PR_ASSERT(0);
return NULL;
}
return jsj_GetJavaClassName(cx, jEnv, java_class);
}
*/
/*
* Return, as a C string, the error message associated with a Java exception
* that occurred as a result of a JNI call, preceded by the class name of
* the exception. As a special case, if the class of the exception is
* netscape.javascript.JSException, the exception class name is omitted.
*
* NULL is returned if no Java exception is pending. The caller is
* responsible for free'ing the returned string. On exit, the Java exception
* is *not* cleared.
*/
const char *
jsj_GetJavaErrorMessage(JNIEnv *jEnv)
{
const char *java_error_msg;
char *error_msg = NULL;
jthrowable exception;
jstring java_exception_jstring;
exception = (*jEnv)->ExceptionOccurred(jEnv);
if (exception && jlThrowable_toString) {
java_exception_jstring =
(*jEnv)->CallObjectMethod(jEnv, exception, jlThrowable_toString);
java_error_msg = (*jEnv)->GetStringUTFChars(jEnv, java_exception_jstring, NULL);
error_msg = strdup((char*)java_error_msg);
(*jEnv)->ReleaseStringUTFChars(jEnv, java_exception_jstring, java_error_msg);
#ifdef DEBUG
/* (*jEnv)->ExceptionDescribe(jEnv); */
#endif
}
return error_msg;
}
/*
* Return, as a C string, the JVM stack trace associated with a Java
* exception, as would be printed by java.lang.Throwable.printStackTrace().
* The caller is responsible for free'ing the returned string.
*
* Returns NULL if an error occurs.
*/
static const char *
get_java_stack_trace(JSContext *cx, JNIEnv *jEnv, jthrowable java_exception)
{
const char *backtrace;
jstring backtrace_jstr;
backtrace = NULL;
if (java_exception && njJSUtil_getStackTrace) {
backtrace_jstr = (*jEnv)->CallStaticObjectMethod(jEnv, njJSUtil,
njJSUtil_getStackTrace,
java_exception);
if (!backtrace_jstr) {
jsj_UnexpectedJavaError(cx, jEnv, "Unable to get exception stack trace");
return NULL;
}
backtrace = jsj_DupJavaStringUTF(cx, jEnv, backtrace_jstr);
}
return backtrace;
}
/* Full Java backtrace when Java exceptions reported to JavaScript */
#define REPORT_JAVA_EXCEPTION_STACK_TRACE
/*
* This is a wrapper around JS_ReportError(), useful when an error condition
* is the result of a JVM failure or exception condition. It appends the
* message associated with the pending Java exception to the passed in
* printf-style format string and arguments.
*/
static void
vreport_java_error(JSContext *cx, JNIEnv *jEnv, const char *format, va_list ap)
{
char *error_msg, *js_error_msg;
const char *java_stack_trace;
const char *java_error_msg;
jthrowable java_exception;
java_error_msg = NULL;
java_exception = (*jEnv)->ExceptionOccurred(jEnv);
if (java_exception && njJSException &&
(*jEnv)->IsInstanceOf(jEnv, java_exception, njJSException)) {
(*jEnv)->ExceptionClear(jEnv);
jsj_ReportUncaughtJSException(cx, jEnv, java_exception);
return;
}
js_error_msg = PR_vsmprintf(format, ap);
if (!js_error_msg) {
PR_ASSERT(0); /* Out-of-memory */
return;
}
#ifdef REPORT_JAVA_EXCEPTION_STACK_TRACE
java_stack_trace = get_java_stack_trace(cx, jEnv, java_exception);
if (java_stack_trace) {
error_msg = PR_smprintf("%s\n%s", js_error_msg, java_stack_trace);
free((char*)java_stack_trace);
if (!error_msg) {
PR_ASSERT(0); /* Out-of-memory */
return;
}
} else
#endif
{
java_error_msg = jsj_GetJavaErrorMessage(jEnv);
if (java_error_msg) {
error_msg = PR_smprintf("%s (%s)\n", js_error_msg, java_error_msg);
free((char*)java_error_msg);
free(js_error_msg);
} else {
error_msg = js_error_msg;
}
}
JS_ReportError(cx, error_msg);
/* Important: the Java exception must not be cleared until the reporter
has been called, because the capture_js_error_reports_for_java(),
called from JS_ReportError(), needs to read the exception from the JVM */
(*jEnv)->ExceptionClear(jEnv);
free(error_msg);
}
void
jsj_ReportJavaError(JSContext *cx, JNIEnv *env, const char *format, ...)
{
va_list ap;
va_start(ap, format);
vreport_java_error(cx, env, format, ap);
va_end(ap);
}
/*
* Same as jsj_ReportJavaError, except "internal error: " is prepended
* to message.
*/
void
jsj_UnexpectedJavaError(JSContext *cx, JNIEnv *env, const char *format, ...)
{
va_list ap;
const char *format2;
va_start(ap, format);
format2 = PR_smprintf("internal error: %s", format);
if (format2) {
vreport_java_error(cx, env, format2, ap);
free((void*)format2);
}
va_end(ap);
}
/*
* Most LiveConnect errors are signaled by calling JS_ReportError(),
* but in some circumstances, the target JSContext for such errors
* is not determinable, e.g. during initialization. In such cases
* any error messages are routed to this function.
*/
void
jsj_LogError(const char *error_msg)
{
if (JSJ_callbacks && JSJ_callbacks->error_print)
JSJ_callbacks->error_print(error_msg);
else
fputs(error_msg, stderr);
}
jsize
jsj_GetJavaArrayLength(JSContext *cx, JNIEnv *jEnv, jarray java_array)
{
jsize array_length = (*jEnv)->GetArrayLength(jEnv, java_array);
if ((*jEnv)->ExceptionOccurred(jEnv)) {
jsj_UnexpectedJavaError(cx, jEnv, "Couldn't obtain array length");
return -1;
}
return array_length;
}
static JSJavaThreadState *the_java_jsj_env = NULL;
JSJavaThreadState *
jsj_MapJSContextToJSJThread(JSContext *cx, JNIEnv **envp)
{
JSJavaThreadState *jsj_env;
char *err_msg;
*envp = NULL;
err_msg = NULL;
jsj_env = the_java_jsj_env;
if (jsj_env == NULL)
jsj_env = JSJ_callbacks->map_js_context_to_jsj_thread(cx, &err_msg);
if (!jsj_env) {
if (err_msg) {
JS_ReportError(cx, err_msg);
free(err_msg);
}
return NULL;
}
if (envp)
*envp = jsj_env->jEnv;
return jsj_env;
}
/**
* Since only one Java thread is allowed to enter JavaScript, this function is
* used to enforce the use of that thread's state. The static global the_java_jsj_env
* overrides using JSJ_callbacks->map_js_context_to_jsj_thread, which maps
* native threads to JSJavaThreadStates. This isn't appropriate when Java calls
* JavaScript, as there can be a many to one mapping from Java threads to native
* threads.
*/
JSJavaThreadState *
jsj_SetJavaJSJEnv(JSJavaThreadState* java_jsj_env)
{
JSJavaThreadState *old_jsj_env = the_java_jsj_env;
the_java_jsj_env = java_jsj_env;
return old_jsj_env;
}

View File

@@ -0,0 +1,264 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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/NPL/
*
* 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.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1998
* Netscape Communications Corporation. All Rights Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* Publicly exported functions for JavaScript <==> Java communication.
*
*/
#ifndef _JSJAVA_H
#define _JSJAVA_H
#ifndef prtypes_h___
#include "prtypes.h"
#endif
PR_BEGIN_EXTERN_C
#include "jni.h" /* Java Native Interface */
#include "jsapi.h" /* JavaScript engine API */
/*
* A JSJavaVM structure is a wrapper around a JavaVM which incorporates
* additional LiveConnect state.
*/
typedef struct JSJavaVM JSJavaVM;
/* LiveConnect and Java state, one per thread */
typedef struct JSJavaThreadState JSJavaThreadState;
/*
* An opaque type that represents the connection to the Java VM. In stand-alone
* Java environments, this may be a JNI JavaVM object; in the browser environment
* it is a reference to a JVM plugin. A set of callbacks in the JSJCallbacks
* struct allow it to be manipulated.
*/
typedef struct SystemJavaVM SystemJavaVM;
/*
* This callback table provides hooks to external functions that implement
* functionality specific to the embedding. For example, these callbacks are
* necessary in multi-threaded environments or to implement a security
* policy.
*/
typedef struct JSJCallbacks {
/* This callback is invoked when there is no JavaScript execution
environment (JSContext) associated with the current Java thread and
a call is made from Java into JavaScript. (A JSContext is associated
with a Java thread by calling the JSJ_SetJSContextForJavaThread()
function.) This callback is only invoked when Java spontaneously calls
into JavaScript, i.e. it is not called when JS calls into Java which
calls back into JS.
This callback can be used to create a JSContext lazily, or obtain
one from a pool of available JSContexts. The implementation of this
callback can call JSJ_SetJSContextForJavaThread() to avoid any further
callbacks of this type for this Java thread. */
JSContext * (*map_jsj_thread_to_js_context)(JSJavaThreadState *jsj_env,
JNIEnv *jEnv,
char **errp);
/* This callback is invoked whenever a call is made into Java from
JavaScript. It's responsible for mapping from a JavaScript execution
environment (JSContext) to a Java thread. (A JavaContext can only
be associated with one Java thread at a time.) */
JSJavaThreadState * (*map_js_context_to_jsj_thread)(JSContext *cx,
char **errp);
/* This callback implements netscape.javascript.JSObject.getWindow(),
a method named for its behavior in the browser environment, where it
returns the JS "Window" object corresponding to the HTML window that an
applet is embedded within. More generally, it's a way for Java to get
hold of a JS object that has not been explicitly passed to it. */
JSObject * (*map_java_object_to_js_object)(JNIEnv *jEnv, void *pJavaObject,
char **errp);
/* An interim callback function until the LiveConnect security story is
straightened out. This function pointer can be set to NULL. */
JSPrincipals * (*get_JSPrincipals_from_java_caller)(JNIEnv *jEnv, JSContext *pJSContext);
/* The following two callbacks sandwich any JS evaluation performed
from Java. They may be used to implement concurrency constraints, e.g.
by suspending the current thread until some condition is met. In the
browser embedding, these are used to maintain the run-to-completion
semantics of JavaScript. It is acceptable for either function pointer
to be NULL. */
JSBool (*enter_js_from_java)(JNIEnv *jEnv, char **errp);
void (*exit_js)(JNIEnv *jEnv);
/* Most LiveConnect errors are signaled by calling JS_ReportError(), but in
some circumstances, the target JSContext for such errors is not
determinable, e.g. during initialization. In such cases any error
messages are routed to this function. If the function pointer is set to
NULL, error messages are sent to stderr. */
void (*error_print)(const char *error_msg);
/* This enables liveconnect to ask the VM for a java wrapper so that VM gets a chance to
store a mapping between a jsobject and java wrapper. So the unwrapping can be done on the
VM side before calling nsILiveconnect apis. This saves on a round trip request. */
jobject (*get_java_wrapper)(JNIEnv *jEnv, jint jsobject);
/* The following set of methods abstract over the JavaVM object. */
PRBool (*create_java_vm)(SystemJavaVM* *jvm, JNIEnv* *initialEnv, void* initargs);
PRBool (*destroy_java_vm)(SystemJavaVM* jvm, JNIEnv* initialEnv);
JNIEnv* (*attach_current_thread)(SystemJavaVM* jvm);
PRBool (*detach_current_thread)(SystemJavaVM* jvm, JNIEnv* env);
SystemJavaVM* (*get_java_vm)(JNIEnv* env);
/* Reserved for future use */
void * reserved[10];
} JSJCallbacks;
/*===========================================================================*/
/* A flag that denotes that a Java package has no sub-packages other than those
explicitly pre-defined at the time of initialization. An access
to a simple name within such a package, therefore, must either correspond to
one of these explicitly pre-defined sub-packages or to a class within this
package. It is reasonable for LiveConnect to signal an error if a simple
name does not comply with these criteria. */
#define PKG_SYSTEM 1
/* A flag that denotes that a Java package which might contain sub-packages
that are not pre-defined at initialization time, because the sub-packages
may not be the same in all installations. Therefore, an access to a simple
name within such a a package which does not correspond to either a
pre-defined sub-package or to a class, must be assummed to refer to an
unknown sub-package. This behavior may cause bogus JavaPackage objects to be
created if a package name is misspelled, e.g. sun.oi.net. */
#define PKG_USER 2
/* A Java package defined at initialization time. */
typedef struct JavaPackageDef {
const char * name; /* e.g. "java.lang" */
const char * path; /* e.g. "java/lang", or NULL for default */
int flags; /* PKG_USER, PKG_SYSTEM, etc. */
} JavaPackageDef;
/*===========================================================================*/
/* The following two convenience functions present a complete, but simplified
LiveConnect API which is designed to handle the special case of a single
Java-VM, with single-threaded operation, and the use of only one JSContext.
The full API is in the section below. */
/* Initialize the provided JSContext by setting up the JS classes necessary for
reflection and by defining JavaPackage objects for the default Java packages
as properties of global_obj. If java_vm is NULL, a new Java VM is
created, using the provided classpath in addition to any default classpath.
The classpath argument is ignored, however, if java_vm is non-NULL. */
PR_IMPLEMENT(JSBool)
JSJ_SimpleInit(JSContext *cx, JSObject *global_obj,
SystemJavaVM *java_vm, const char *classpath);
/* Free up all resources. Destroy the Java VM if it was created by LiveConnect */
PR_IMPLEMENT(void)
JSJ_SimpleShutdown();
/*===========================================================================*/
/* The "full" LiveConnect API, required when more than one thread, Java VM, or
JSContext is involved. Initialization pseudocode might go roughly like
this:
JSJ_Init() // Setup callbacks
for each JavaVM {
JSJ_ConnectToJavaVM(...)
}
for each JSContext {
JSJ_InitJSContext(...)
}
for each JS evaluation {
run JavaScript code in the JSContext;
}
*/
/* Called once for all instances of LiveConnect to set up callbacks */
PR_IMPLEMENT(void)
JSJ_Init(JSJCallbacks *callbacks);
/* Called once per Java VM, this function initializes the classes, fields, and
methods required for Java reflection. If java_vm is NULL, a new Java VM is
created according to the create_java_vm callback in the JSJCallbacks,
using the provided classpath in addition to any default initargs.
The initargs argument is ignored, however, if java_vm is non-NULL. */
PR_IMPLEMENT(JSJavaVM *)
JSJ_ConnectToJavaVM(SystemJavaVM *java_vm, void* initargs);
/* Initialize the provided JSContext by setting up the JS classes necessary for
reflection and by defining JavaPackage objects for the default Java packages
as properties of global_obj. Additional packages may be pre-defined by
setting the predefined_packages argument. (Pre-defining a Java package at
initialization time is not necessary, but it will make package lookup faster
and, more importantly, will avoid unnecessary network accesses if classes
are being loaded over the network.) */
PR_IMPLEMENT(JSBool)
JSJ_InitJSContext(JSContext *cx, JSObject *global_obj,
JavaPackageDef *predefined_packages);
/* This function returns a structure that encapsulates the Java and JavaScript
execution environment for the current native thread. It is intended to
be called from the embedder's implementation of JSJCallback's
map_js_context_to_jsj_thread() function. The thread_name argument is only
used for debugging purposes and can be set to NULL. The Java JNI
environment associated with this thread is returned through the java_envp
argument if java_envp is non-NULL. */
PR_IMPLEMENT(JSJavaThreadState *)
JSJ_AttachCurrentThreadToJava(JSJavaVM *jsjava_vm, const char *thread_name,
JNIEnv **java_envp);
/* Destructor routine for per-thread JSJavaThreadState structure */
PR_IMPLEMENT(JSBool)
JSJ_DetachCurrentThreadFromJava(JSJavaThreadState *jsj_env);
/* This function is used to specify a particular JSContext as *the* JavaScript
execution environment to be used when LiveConnect is accessed from the given
Java thread, i.e. when one of the methods of netscape.javascript.JSObject
has been called. There can only be one such JS context for any given Java
thread at a time. (To multiplex JSContexts among a single thread, this
function could be called before Java is invoked on that thread.) The return
value is the previous JSContext associated with the given Java thread.
If this function has not been called for a thread and a crossing is made
into JavaScript from Java, the map_jsj_thread_to_js_context() callback will
be invoked to determine the JSContext for the thread. The purpose of the
function is to improve performance by avoiding the expense of the callback.
*/
PR_IMPLEMENT(JSContext *)
JSJ_SetDefaultJSContextForJavaThread(JSContext *cx, JSJavaThreadState *jsj_env);
/* This routine severs the connection to a Java VM, freeing all related resources.
It shouldn't be called until the global scope has been cleared in all related
JSContexts (so that all LiveConnect objects are finalized) and a JavaScript
GC is performed. Otherwise, accessed to free'ed memory could result. */
PR_IMPLEMENT(void)
JSJ_DisconnectFromJavaVM(JSJavaVM *);
/*
* Reflect a Java object into a JS value. The source object, java_obj, must
* be of type java.lang.Object or a subclass and may, therefore, be an array.
*/
PR_IMPLEMENT(JSBool)
JSJ_ConvertJavaObjectToJSValue(JSContext *cx, jobject java_obj, jsval *vp);
PR_END_EXTERN_C
#endif /* _JSJAVA_H */

View File

@@ -0,0 +1,182 @@
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
IGNORE_MANIFEST=1
#//------------------------------------------------------------------------
#//
#// Makefile to build the Java reflections of JavaScript objects
#//
#//------------------------------------------------------------------------
#//------------------------------------------------------------------------
#//
#// Specify the depth of the current directory relative to the
#// root of NS
#//
#//------------------------------------------------------------------------
DEPTH= ..\..\..
include <$(DEPTH)/config/config.mak>
!ifdef NSJVM
DIRS = classes
!endif
#//------------------------------------------------------------------------
#//
#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...)
#//
#//------------------------------------------------------------------------
DLLNAME=jsj$(MOZ_BITS)$(VERSION_NUMBER)
PDBFILE=$(DLLNAME).pdb
MAPFILE = $(DLLNAME).map
RESFILE = jsj1640.res
DLL=.\$(OBJDIR)\$(DLLNAME).dll
MAKE_OBJ_TYPE = DLL
!if "$(MOZ_BITS)" == "16"
DEFFILE = $(DLLNAME).def
!endif
LLIBS=$(LIBNSPR) $(DIST)\lib\js$(MOZ_BITS)$(VERSION_NUMBER).lib \
$(DIST)\lib\xpcom32.lib
!if "$(MOZ_BITS)"=="32" && defined(MOZ_DEBUG) && defined(GLOWCODE)
LLIBS=$(LLIBS) $(GLOWDIR)\glowcode.lib
!endif
#//------------------------------------------------------------------------
#//
#// Define the files necessary to build the target (ie. OBJS)
#//
#//------------------------------------------------------------------------
OBJS= \
.\$(OBJDIR)\jsj.obj \
.\$(OBJDIR)\jsj_JSObject.obj \
.\$(OBJDIR)\jsj_JavaArray.obj \
.\$(OBJDIR)\jsj_JavaClass.obj \
.\$(OBJDIR)\jsj_JavaMember.obj \
.\$(OBJDIR)\jsj_JavaObject.obj \
.\$(OBJDIR)\jsj_JavaPackage.obj \
.\$(OBJDIR)\jsj_array.obj \
.\$(OBJDIR)\jsj_class.obj \
.\$(OBJDIR)\jsj_convert.obj \
.\$(OBJDIR)\jsj_field.obj \
.\$(OBJDIR)\jsj_hash.obj \
.\$(OBJDIR)\jsj_method.obj \
.\$(OBJDIR)\jsj_utils.obj \
.\$(OBJDIR)\nsCLiveconnect.obj \
.\$(OBJDIR)\nsCLiveconnectFactory.obj \
!if "$(MOZ_BITS)" == "16"
.\$(OBJDIR)\jsj_nodl.obj \
!endif
$(NULL)
#//------------------------------------------------------------------------
#//
#// install headers
#//
#//------------------------------------------------------------------------
INSTALL_DIR=$(PUBLIC)\js
INSTALL_FILE_LIST= \
jsjava.h nsILiveconnect.h
#//------------------------------------------------------------------------
#//
#// Define any Public Targets here (ie. PROGRAM, LIBRARY, DLL, ...)
#// (these must be defined before the common makefiles are included)
#//
#//------------------------------------------------------------------------
!ifdef NSJVM
JNI_GEN= \
netscape.javascript.JSObject \
netscape.javascript.JSException \
$(NULL)
!endif
MODULE = java
EXPORTS = \
$(JNI_GEN_DIR)\netscape_javascript_JSObject.h \
$(JNI_GEN_DIR)\netscape_javascript_JSException.h \
$(NULL)
#//------------------------------------------------------------------------
#//
#// Define any local options for the make tools
#// (ie. LCFLAGS, LLFLAGS, LLIBS, LINCS)
#//
#//------------------------------------------------------------------------
LINCS=$(LINCS) -I$(JNI_GEN_DIR) \
-I$(PUBLIC)\js \
-I$(PUBLIC)\java \
-I$(PUBLIC)\xpcom \
$(NULL)
#!ifdef SERVER_BUILD
#LLIBS=$(DIST)/lib/httpdlw.lib $(DIST)/lib/libsjboot.lib
#!endif
#//------------------------------------------------------------------------
#//
#// Include the common makefile rules
#//
#//------------------------------------------------------------------------
include <$(DEPTH)/config/rules.mak>
export:: INSTALL_FILES
libs:: $(DLL)
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
####
# this bit of extreme scariness came from the js/src makefile
# reproduced here since that's where jsjava.c lives now...
!if ("$(MOZ_BITS)" == "16")
#//
#// Win16 Hoovers SO BAD!!!
#//
!if !defined(MOZ_DEBUG)
#//
#// We must turn off codeview debug info so jni.c can build.
#// Otherwise the linker gives errors about data in the $SYMBOLS
#// segment being beyond a segment boundary.
#//
$(OBJDIR)\jsjava.obj: jsjava.c
@$(CC) @<<$(CFGFILE)
-c
-Od
$(CFLAGS)
$(LCFLAGS)
$(LINCS)
$(LINCS_1)
$(INCS)
-Fd$(PDBFILE)
-Fo.\$(OBJDIR)\
$(*B).c
<<KEEP
!endif
!endif

View File

@@ -0,0 +1,111 @@
/* -*- Mode: C; tab-width: 8 -*-
* Copyright (C) 1998 Netscape Communications Corporation, All Rights Reserved.
*/
#include <jni.h>
/* Header for class netscape_javascript_JSObject */
#ifndef _Included_netscape_javascript_JSObject
#define _Included_netscape_javascript_JSObject
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: netscape_javascript_JSObject
* Method: initClass
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_initClass
(JNIEnv *, jclass);
/*
* Class: netscape_javascript_JSObject
* Method: getMember
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getMember
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: getSlot
* Signature: (I)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getSlot
(JNIEnv *, jobject, jint);
/*
* Class: netscape_javascript_JSObject
* Method: setMember
* Signature: (Ljava/lang/String;Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setMember
(JNIEnv *, jobject, jstring, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: setSlot
* Signature: (ILjava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_setSlot
(JNIEnv *, jobject, jint, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: removeMember
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_removeMember
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: call
* Signature: (Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_call
(JNIEnv *, jobject, jstring, jobjectArray);
/*
* Class: netscape_javascript_JSObject
* Method: eval
* Signature: (Ljava/lang/String;)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_eval
(JNIEnv *, jobject, jstring);
/*
* Class: netscape_javascript_JSObject
* Method: toString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_netscape_javascript_JSObject_toString
(JNIEnv *, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: getWindow
* Signature: (Ljava/applet/Applet;)Lnetscape/javascript/JSObject;
*/
JNIEXPORT jobject JNICALL Java_netscape_javascript_JSObject_getWindow
(JNIEnv *, jclass, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: finalize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_javascript_JSObject_finalize
(JNIEnv *, jobject);
/*
* Class: netscape_javascript_JSObject
* Method: equals
* Signature: (Ljava/lang/Object;)Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_javascript_JSObject_equals
(JNIEnv *, jobject, jobject);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,567 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* 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"
PR_BEGIN_EXTERN_C
#ifdef XP_MAC
#include "prosdep.h"
#endif
#include "jsj_private.h"
#include "jsjava.h"
#include "jscntxt.h" /* For js_ReportErrorAgain().
TODO - get rid of private header */
#include "netscape_javascript_JSObject.h" /* javah-generated headers */
/* 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"
static NS_DEFINE_IID(kILiveconnectIID, NS_ILIVECONNECT_IID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
////////////////////////////////////////////////////////////////////////////
// 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)
{
if (aIID.Equals(kISupportsIID)) {
*aInstancePtr = GetInner();
AddRef();
return NS_OK;
}
if (aIID.Equals(kILiveconnectIID)) {
*aInstancePtr = this;
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
////////////////////////////////////////////////////////////////////////////
// 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 char *name, jobject *pjobj)
{
JSContext *cx = NULL;
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
nsresult err = NS_OK;
jobject member = NULL;
jsval js_val = NULL;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
JavaToJSSavedState saved_state = {NULL,NULL};
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NS_ERROR_FAILURE;
if (!name) {
JS_ReportError(cx, "illegal null member name");
member = NULL;
goto done;
}
if (!JS_GetProperty(cx, js_obj, name, &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, int slot, jobject *pjobj)
{
JSContext *cx = NULL;
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
nsresult err = NS_OK;
jobject member = NULL;
jsval js_val = NULL;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
JavaToJSSavedState saved_state = {NULL,NULL};
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NS_ERROR_FAILURE;
// =-= 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 char *name, jobject java_obj)
{
JSContext *cx = NULL;
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
nsresult err = NS_OK;
jobject member = NULL;
jsval js_val = NULL;
JavaToJSSavedState saved_state = {NULL,NULL};
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NS_ERROR_FAILURE;
if (!name) {
JS_ReportError(cx, "illegal null member name");
goto done;
}
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
goto done;
JS_SetProperty(cx, js_obj, name, &js_val);
done:
jsj_exit_js(cx, jsj_env, &saved_state);
return NS_OK;
}
/**
* set 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 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::SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject java_obj)
{
JSContext *cx = NULL;
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
nsresult err = NS_OK;
jsval js_val = NULL;
JavaToJSSavedState saved_state = {NULL,NULL};
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NS_ERROR_FAILURE;
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_obj, &js_val))
goto done;
JS_SetElement(cx, js_obj, slot, &js_val);
done:
jsj_exit_js(cx, jsj_env, &saved_state);
return NS_OK;
}
/**
* remove 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.
*/
NS_METHOD
nsCLiveconnect::RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name)
{
JSContext *cx = NULL;
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
nsresult err = NS_OK;
jsval js_val = NULL;
JavaToJSSavedState saved_state = {NULL,NULL};
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NS_ERROR_FAILURE;
if (!name) {
JS_ReportError(cx, "illegal null member name");
goto done;
}
JS_DeleteProperty2(cx, js_obj, name, &js_val);
done:
jsj_exit_js(cx, jsj_env, &saved_state);
return NS_OK;
}
/**
* call a method of Native JSObject.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
* @param name - Name of a method.
* @param jobjArr - Array of jobjects representing parameters of method being caled.
* @param pjobj - return value.
*/
NS_METHOD
nsCLiveconnect::Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray java_args, jobject *pjobj)
{
int i = 0;
int argc = 0;
int arg_num = 0;
jsval *argv = 0;
JSContext *cx = NULL;
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
nsresult err = NS_OK;
jobject member = NULL;
jsval js_val = NULL;
jsval function_val = NULL;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
JavaToJSSavedState saved_state = {NULL,NULL};
jobject result = NULL;
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NS_ERROR_FAILURE;
result = NULL;
if (!name) {
JS_ReportError(cx, "illegal null JavaScript function name");
goto done;
}
/* FIXME: What about security stuff ? Don't principals need to be set here ? */
/* Allocate space for JS arguments */
if (java_args) {
argc = jEnv->GetArrayLength(java_args);
argv = (jsval*)JS_malloc(cx, argc * sizeof(jsval));
} else {
argc = 0;
argv = 0;
}
/* Convert arguments from Java to JS values */
for (arg_num = 0; arg_num < argc; arg_num++) {
jobject arg = jEnv->GetObjectArrayElement(java_args, arg_num);
if (!jsj_ConvertJavaObjectToJSValue(cx, jEnv, arg, &argv[arg_num]))
goto cleanup_argv;
JS_AddRoot(cx, &argv[arg_num]);
}
if (!JS_GetProperty(cx, js_obj, name, &function_val))
goto cleanup_argv;
if (!JS_CallFunctionValue(cx, js_obj, function_val, argc, argv, &js_val))
goto cleanup_argv;
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
&dummy_cost, &result, &dummy_bool);
cleanup_argv:
if (argv) {
for (i = 0; i < arg_num; i++)
JS_RemoveRoot(cx, &argv[i]);
JS_free(cx, argv);
}
done:
if (!jsj_exit_js(cx, jsj_env, &saved_state))
return NS_ERROR_FAILURE;
*pjobj = result;
return NS_OK;
}
/**
* Evaluate a script with a Native JS Object representing scope.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
* @param numPrincipals - Number of principals being passed.
* @param script - Script to be executed.
* @param pjobj - return value.
*/
NS_METHOD
nsCLiveconnect::Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj)
{
JSContext *cx = NULL;
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
nsresult err = NS_OK;
jobject member = NULL;
jsval js_val = NULL;
jsval function_val = NULL;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
JavaToJSSavedState saved_state = {NULL,NULL};
jobject result = NULL;
const char *codebase = NULL;
JSPrincipals *principals = NULL;
JSBool eval_succeeded = PR_FALSE;
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NULL;
result = NULL;
if (!script) {
JS_ReportError(cx, "illegal null string eval argument");
goto done;
}
/* Set up security stuff */
principals = NULL;
if (JSJ_callbacks->get_JSPrincipals_from_java_caller)
principals = JSJ_callbacks->get_JSPrincipals_from_java_caller(jEnv, cx);
codebase = principals ? principals->codebase : NULL;
/* Have the JS engine evaluate the unicode string */
eval_succeeded = JS_EvaluateScriptForPrincipals(cx, js_obj, principals,
script, strlen(script),
codebase, 0, &js_val);
if (!eval_succeeded)
goto done;
/* Convert result to a subclass of java.lang.Object */
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
&dummy_cost, &result, &dummy_bool);
done:
if (!jsj_exit_js(cx, jsj_env, &saved_state))
return NULL;
*pjobj = result;
return NS_OK;
}
/**
* Get the window object for a plugin instance.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
* representing the java object.
* @param pjobj - return value. This is a native js object
* representing the window object of a frame
* in which a applet/bean resides.
*/
NS_METHOD
nsCLiveconnect::GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj)
{
char *err_msg = NULL;
JSContext *cx = NULL;
JSObject *js_obj = NULL;
jsval js_val = NULL;
int dummy_cost = 0;
JSBool dummy_bool = PR_FALSE;
JavaToJSSavedState saved_state = {NULL,NULL};
jobject java_obj = NULL;
JSJavaThreadState *jsj_env = NULL;
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env)
return NULL;
err_msg = NULL;
java_obj = NULL;
js_obj = JSJ_callbacks->map_java_object_to_js_object(jEnv, pJavaObject, &err_msg);
if (!js_obj) {
if (err_msg) {
JS_ReportError(cx, err_msg);
free(err_msg);
}
goto done;
}
#if 0
js_val = OBJECT_TO_JSVAL(js_obj);
jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, jsj_get_jlObject_descriptor(cx, jEnv),
&dummy_cost, &java_obj, &dummy_bool);
#endif
done:
if (!jsj_exit_js(cx, jsj_env, &saved_state))
return NULL;
//*pjobj = java_obj;
*pobj = (jint)js_obj;
return NS_OK;
}
/**
* Get the window object for a plugin instance.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
*/
NS_METHOD
nsCLiveconnect::FinalizeJSObject(JNIEnv *jEnv, jsobject obj)
{
JSContext *cx = NULL;
JavaToJSSavedState saved_state = {NULL,NULL};
JSJavaThreadState *jsj_env = NULL;
JSObject *js_obj = (JSObject *)obj;
if(jEnv == NULL)
{
return NS_ERROR_FAILURE;
}
jsj_env = jsj_enter_js(jEnv, NULL, &cx, NULL, &saved_state);
if (!jsj_env) /* Note: memory leak if we exit here */
return NS_ERROR_FAILURE;
#ifdef PRESERVE_JSOBJECT_IDENTITY
jsj_remove_js_obj_reflection_from_hashtable(cx, js_obj);
#endif /* PRESERVE_JSOBJECT_IDENTITY */
jsj_exit_js(cx, jsj_env, &saved_state);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////
// from nsCLiveconnect:
nsCLiveconnect::nsCLiveconnect(nsISupports *aOuter)
{
NS_INIT_AGGREGATED(aOuter);
jsj_init_js_obj_reflections_table();
}
nsCLiveconnect::~nsCLiveconnect()
{
}

View File

@@ -0,0 +1,166 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains class definition implementing the public interface.
*
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the class definition to implement nsILiveconnect XP-COM interface.
*
*/
#ifndef nsCLiveconnect_h___
#define nsCLiveconnect_h___
#include "nsILiveconnect.h"
#include "nsAgg.h"
/**
* nsCLiveconnect implements nsILiveconnect interface for navigator.
* This is used by a JVM to implement netscape.javascript.JSObject functionality.
*/
class nsCLiveconnect :public nsILiveconnect {
public:
////////////////////////////////////////////////////////////////////////////
// from nsISupports and AggregatedQueryInterface:
NS_DECL_AGGREGATED
////////////////////////////////////////////////////////////////////////////
// from nsILiveconnect:
/**
* get member of a Native JSObject for a given name.
*
* @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_IMETHOD
GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj);
/**
* get member of a Native JSObject for a given index.
*
* @param obj - A Native JS Object.
* @param index - Index of a member.
* @param pjobj - return parameter as a java object representing
* the member.
*/
NS_IMETHOD
GetSlot(JNIEnv *jEnv, jsobject obj, int index, jobject *pjobj);
/**
* set member of a Native JSObject for a given name.
*
* @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_IMETHOD
SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject jobj);
/**
* set member of a Native JSObject for a given index.
*
* @param obj - A Native JS Object.
* @param index - Index 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_IMETHOD
SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject jobj);
/**
* remove member of a Native JSObject for a given name.
*
* @param obj - A Native JS Object.
* @param name - Name of a member.
*/
NS_IMETHOD
RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name);
/**
* call a method of Native JSObject.
*
* @param obj - A Native JS Object.
* @param name - Name of a method.
* @param jobjArr - Array of jobjects representing parameters of method being caled.
* @param pjobj - return value.
*/
NS_IMETHOD
Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray jobjArr, jobject *pjobj);
/**
* Evaluate a script with a Native JS Object representing scope.
*
* @param obj - A Native JS Object.
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
* @param numPrincipals - Number of principals being passed.
* @param script - Script to be executed.
* @param pjobj - return value.
*/
NS_IMETHOD
//Eval(JNIEnv *jEnv, jsobject obj, nsIPrincipal **pNSIPrincipaArray, PRInt32 numPrincipals, const char *script, jobject *pjobj);
Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj);
/**
* Get the window object for a plugin instance.
*
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
* representing the java object.
* @param pjobj - return value. This is a native js object
* representing the window object of a frame
* in which a applet/bean resides.
*/
NS_IMETHOD
GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj);
/**
* Get the window object for a plugin instance.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
*/
NS_IMETHOD
FinalizeJSObject(JNIEnv *jEnv, jsobject obj);
////////////////////////////////////////////////////////////////////////////
// from nsCLiveconnect:
nsCLiveconnect(nsISupports *aOuter);
virtual ~nsCLiveconnect(void);
protected:
};
#endif // nsCLiveconnect_h___

View File

@@ -0,0 +1,168 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the implementation providing nsILiveconnect XP-COM interface.
*
*/
#include "prtypes.h"
#include "nspr.h"
#include "prmem.h"
#include "prmon.h"
#include "prlog.h"
#include "nsCLiveconnect.h"
#include "nsCLiveconnectFactory.h"
#include "nsRepository.h"
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
static NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
static NS_DEFINE_IID(kILiveconnectIID, NS_ILIVECONNECT_IID);
nsIFactory *nsCLiveconnectFactory::m_pNSIFactory = NULL;
nsCLiveconnect *nsCLiveconnectFactory::m_pNSCLiveconnect = NULL;
/*+++++++++++++++++++++++++++++++++++++++++++++++++
* NSGetFactory:
* Provides entry point to liveconnect dll.
+++++++++++++++++++++++++++++++++++++++++++++++++*/
extern "C" NS_EXPORT nsresult
NSGetFactory(const nsCID &aClass, nsIFactory **aFactory)
{
if (!aClass.Equals(kCLiveconnectCID)) {
return NS_ERROR_FACTORY_NOT_LOADED; // XXX right error?
}
nsCLiveconnectFactory* pCLiveConnectFactory = new nsCLiveconnectFactory();
if (pCLiveConnectFactory == NULL)
return NS_ERROR_OUT_OF_MEMORY;
pCLiveConnectFactory->AddRef();
*aFactory = pCLiveConnectFactory;
return NS_OK;
}
extern "C" NS_EXPORT PRBool
NSCanUnload(void)
{
return PR_FALSE;
}
////////////////////////////////////////////////////////////////////////////
// from nsISupports
NS_METHOD
nsCLiveconnectFactory::QueryInterface(const nsIID& aIID, void** aInstancePtr)
{
PR_ASSERT(NULL != aInstancePtr);
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIFactoryIID) ||
aIID.Equals(kISupportsIID)) {
*aInstancePtr = (void*) this;
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMPL_ADDREF(nsCLiveconnectFactory)
NS_IMPL_RELEASE(nsCLiveconnectFactory)
////////////////////////////////////////////////////////////////////////////
// from nsIFactory:
NS_METHOD
nsCLiveconnectFactory::CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
nsCLiveconnect *pNSCLiveconnect = NULL;
*aResult = NULL;
if (aOuter && !aIID.Equals(kISupportsIID))
return NS_NOINTERFACE; // XXX right error?
if (m_pNSCLiveconnect == NULL)
{
m_pNSCLiveconnect = new nsCLiveconnect(aOuter);
}
if (m_pNSCLiveconnect == NULL)
{
return NS_ERROR_FAILURE;
}
if (m_pNSCLiveconnect->QueryInterface(aIID,
(void**)aResult) != NS_OK) {
// then we're trying get a interface other than nsISupports and
// nsICapsManager
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_METHOD
nsCLiveconnectFactory::LockFactory(PRBool aLock)
{
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////
// from nsCLiveconnectFactory:
nsCLiveconnectFactory::nsCLiveconnectFactory(void)
{
if( m_pNSIFactory != NULL)
{
return;
}
NS_INIT_REFCNT();
nsresult err = NS_OK;
NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
err = this->QueryInterface(kIFactoryIID, (void**)&m_pNSIFactory);
if ( (err == NS_OK) && (m_pNSIFactory != NULL) )
{
NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
nsRepository::RegisterFactory(kCLiveconnectCID, m_pNSIFactory,
PR_FALSE);
}
}
nsCLiveconnectFactory::~nsCLiveconnectFactory()
{
if(mRefCnt == 0)
{
NS_DEFINE_CID(kCLiveconnectCID, NS_CLIVECONNECT_CID);
nsRepository::UnregisterFactory(kCLiveconnectCID, (nsIFactory *)m_pNSIFactory);
}
}

View File

@@ -0,0 +1,59 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the class definition to implement nsIFactory XP-COM interface.
*
*/
#ifndef nsCLiveconnectFactory_h___
#define nsCLiveconnectFactory_h___
#include "nsISupports.h"
#include "nsIFactory.h"
class nsCLiveconnectFactory : public nsIFactory {
public:
////////////////////////////////////////////////////////////////////////////
// from nsISupports and AggregatedQueryInterface:
NS_DECL_ISUPPORTS
////////////////////////////////////////////////////////////////////////////
// from nsIFactory:
NS_IMETHOD
CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult);
NS_IMETHOD
LockFactory(PRBool aLock);
////////////////////////////////////////////////////////////////////////////
// from nsCLiveconnectFactory:
nsCLiveconnectFactory(void);
virtual ~nsCLiveconnectFactory(void);
protected:
static nsIFactory *m_pNSIFactory;
static nsCLiveconnect *m_pNSCLiveconnect;
};
#endif // nsCLiveconnectFactory_h___

View File

@@ -0,0 +1,157 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* This file is part of the Java-vendor-neutral implementation of LiveConnect
*
* It contains the public XP-COM based interface for java to javascript communication.
*
*/
#ifndef nsILiveconnect_h___
#define nsILiveconnect_h___
#include "nsISupports.h"
#include "nsIFactory.h"
#include "jni.h"
typedef jint jsobject;
class nsILiveconnect : public nsISupports {
public:
/**
* get member of a Native JSObject for a given name.
*
* @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_IMETHOD
GetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject *pjobj) = 0;
/**
* get member of a Native JSObject for a given index.
*
* @param obj - A Native JS Object.
* @param index - Index of a member.
* @param pjobj - return parameter as a java object representing
* the member.
*/
NS_IMETHOD
GetSlot(JNIEnv *jEnv, jsobject obj, int index, jobject *pjobj) = 0;
/**
* set member of a Native JSObject for a given name.
*
* @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_IMETHOD
SetMember(JNIEnv *jEnv, jsobject obj, const char *name, jobject jobj) = 0;
/**
* set member of a Native JSObject for a given index.
*
* @param obj - A Native JS Object.
* @param index - Index 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_IMETHOD
SetSlot(JNIEnv *jEnv, jsobject obj, int slot, jobject jobj) = 0;
/**
* remove member of a Native JSObject for a given name.
*
* @param obj - A Native JS Object.
* @param name - Name of a member.
*/
NS_IMETHOD
RemoveMember(JNIEnv *jEnv, jsobject obj, const char *name) = 0;
/**
* call a method of Native JSObject.
*
* @param obj - A Native JS Object.
* @param name - Name of a method.
* @param jobjArr - Array of jobjects representing parameters of method being caled.
* @param pjobj - return value.
*/
NS_IMETHOD
Call(JNIEnv *jEnv, jsobject obj, const char *name, jobjectArray jobjArr, jobject *pjobj) = 0;
/**
* Evaluate a script with a Native JS Object representing scope.
*
* @param obj - A Native JS Object.
* @param pNSIPrincipaArray - Array of principals to be used to compare privileges.
* @param numPrincipals - Number of principals being passed.
* @param script - Script to be executed.
* @param pjobj - return value.
*/
NS_IMETHOD
//Eval(jsobject obj, nsIPrincipal **pNSIPrincipaArray, PRInt32 numPrincipals, const char *script, jobject *pjobj) = 0;
Eval(JNIEnv *jEnv, jsobject obj, const char *script, jobject *pjobj) = 0;
/**
* Get the window object for a plugin instance.
*
* @param pJavaObject - Either a jobject or a pointer to a plugin instance
* representing the java object.
* @param pjobj - return value. This is a native js object
* representing the window object of a frame
* in which a applet/bean resides.
*/
NS_IMETHOD
GetWindow(JNIEnv *jEnv, void *pJavaObject, jsobject *pobj) = 0;
/**
* Get the window object for a plugin instance.
*
* @param jEnv - JNIEnv on which the call is being made.
* @param obj - A Native JS Object.
*/
NS_IMETHOD
FinalizeJSObject(JNIEnv *jEnv, jsobject obj) = 0;
};
#define NS_ILIVECONNECT_IID \
{ /* 68190910-3318-11d2-97f0-00805f8a28d0 */ \
0x68190910, \
0x3318, \
0x11d2, \
{0x97, 0xf0, 0x00, 0x80, 0x5f, 0x8a, 0x28, 0xd0} \
};
#define NS_CLIVECONNECT_CID \
{ /* b8f0cef0-3931-11d2-97f0-00805f8a28d0 */ \
0xb8f0cef0, \
0x3931, \
0x11d2, \
{0x97, 0xf0, 0x00, 0x80, 0x5f, 0x8a, 0x28, 0xd0} \
};
#endif // nsILiveconnect_h___

View File

@@ -1,539 +0,0 @@
/*
* 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 the elliptic curve math library for binary polynomial
* field curves.
*
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>
*
* Alternatively, the contents of this file may be used under the terms of
* either 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.
*
*/
#ifdef NSS_ENABLE_ECC
/*
* GF2m_ecl.c: Contains an implementation of elliptic curve math library
* for curves over GF2m.
*
* XXX Can be moved to a separate subdirectory later.
*
*/
#include "GF2m_ecl.h"
#include "mpi/mplogic.h"
#include "mpi/mp_gf2m.h"
#include <stdlib.h>
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
mp_err
GF2m_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py)
{
if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
return MP_YES;
} else {
return MP_NO;
}
}
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
mp_err
GF2m_ec_pt_set_inf_aff(mp_int *px, mp_int *py)
{
mp_zero(px);
mp_zero(py);
return MP_OKAY;
}
/* Computes R = P + Q based on IEEE P1363 A.10.2.
* Elliptic curve points P, Q, and R can all be identical.
* Uses affine coordinates.
*/
mp_err
GF2m_ec_pt_add_aff(const mp_int *pp, const mp_int *a, const mp_int *px,
const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int lambda, xtemp, ytemp;
unsigned int *p;
int p_size;
p_size = mp_bpoly2arr(pp, p, 0) + 1;
p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size));
if (p == NULL) goto cleanup;
mp_bpoly2arr(pp, p, p_size);
CHECK_MPI_OK( mp_init(&lambda) );
CHECK_MPI_OK( mp_init(&xtemp) );
CHECK_MPI_OK( mp_init(&ytemp) );
/* if P = inf, then R = Q */
if (GF2m_ec_pt_is_inf_aff(px, py) == 0) {
CHECK_MPI_OK( mp_copy(qx, rx) );
CHECK_MPI_OK( mp_copy(qy, ry) );
err = MP_OKAY;
goto cleanup;
}
/* if Q = inf, then R = P */
if (GF2m_ec_pt_is_inf_aff(qx, qy) == 0) {
CHECK_MPI_OK( mp_copy(px, rx) );
CHECK_MPI_OK( mp_copy(py, ry) );
err = MP_OKAY;
goto cleanup;
}
/* if px != qx, then lambda = (py+qy) / (px+qx),
* xtemp = a + lambda^2 + lambda + px + qx
*/
if (mp_cmp(px, qx) != 0) {
CHECK_MPI_OK( mp_badd(py, qy, &ytemp) );
CHECK_MPI_OK( mp_badd(px, qx, &xtemp) );
CHECK_MPI_OK( mp_bdivmod(&ytemp, &xtemp, pp, p, &lambda) );
CHECK_MPI_OK( mp_bsqrmod(&lambda, p, &xtemp) );
CHECK_MPI_OK( mp_badd(&xtemp, &lambda, &xtemp) );
CHECK_MPI_OK( mp_badd(&xtemp, a, &xtemp) );
CHECK_MPI_OK( mp_badd(&xtemp, px, &xtemp) );
CHECK_MPI_OK( mp_badd(&xtemp, qx, &xtemp) );
} else {
/* if py != qy or qx = 0, then R = inf */
if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qx) == 0)) {
mp_zero(rx);
mp_zero(ry);
err = MP_OKAY;
goto cleanup;
}
/* lambda = qx + qy / qx */
CHECK_MPI_OK( mp_bdivmod(qy, qx, pp, p, &lambda) );
CHECK_MPI_OK( mp_badd(&lambda, qx, &lambda) );
/* xtemp = a + lambda^2 + lambda */
CHECK_MPI_OK( mp_bsqrmod(&lambda, p, &xtemp) );
CHECK_MPI_OK( mp_badd(&xtemp, &lambda, &xtemp) );
CHECK_MPI_OK( mp_badd(&xtemp, a, &xtemp) );
}
/* ry = (qx + xtemp) * lambda + xtemp + qy */
CHECK_MPI_OK( mp_badd(qx, &xtemp, &ytemp) );
CHECK_MPI_OK( mp_bmulmod(&ytemp, &lambda, p, &ytemp) );
CHECK_MPI_OK( mp_badd(&ytemp, &xtemp, &ytemp) );
CHECK_MPI_OK( mp_badd(&ytemp, qy, ry) );
/* rx = xtemp */
CHECK_MPI_OK( mp_copy(&xtemp, rx) );
cleanup:
mp_clear(&lambda);
mp_clear(&xtemp);
mp_clear(&ytemp);
free(p);
return err;
}
/* Computes R = P - Q.
* Elliptic curve points P, Q, and R can all be identical.
* Uses affine coordinates.
*/
mp_err
GF2m_ec_pt_sub_aff(const mp_int *pp, const mp_int *a, const mp_int *px,
const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int nqy;
MP_DIGITS(&nqy) = 0;
CHECK_MPI_OK( mp_init(&nqy) );
/* nqy = qx+qy */
CHECK_MPI_OK( mp_badd(qx, qy, &nqy) );
err = GF2m_ec_pt_add_aff(pp, a, px, py, qx, &nqy, rx, ry);
cleanup:
mp_clear(&nqy);
return err;
}
/* Computes R = 2P.
* Elliptic curve points P and R can be identical.
* Uses affine coordinates.
*/
mp_err
GF2m_ec_pt_dbl_aff(const mp_int *pp, const mp_int *a, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry)
{
return GF2m_ec_pt_add_aff(pp, a, px, py, px, py, rx, ry);
}
/* Gets the i'th bit in the binary representation of a.
* If i >= length(a), then return 0.
* (The above behaviour differs from mpl_get_bit, which
* causes an error if i >= length(a).)
*/
#define MP_GET_BIT(a, i) \
((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
/* Computes R = nP based on IEEE P1363 A.10.3.
* Elliptic curve points P and R can be identical.
* Uses affine coordinates.
*/
mp_err
GF2m_ec_pt_mul_aff(const mp_int *pp, const mp_int *a, const mp_int *b,
const mp_int *px, const mp_int *py, const mp_int *n,
mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int k, k3, qx, qy, sx, sy;
int b1, b3, i, l;
unsigned int *p;
int p_size;
MP_DIGITS(&k) = 0;
MP_DIGITS(&k3) = 0;
MP_DIGITS(&qx) = 0;
MP_DIGITS(&qy) = 0;
MP_DIGITS(&sx) = 0;
MP_DIGITS(&sy) = 0;
CHECK_MPI_OK( mp_init(&k) );
CHECK_MPI_OK( mp_init(&k3) );
CHECK_MPI_OK( mp_init(&qx) );
CHECK_MPI_OK( mp_init(&qy) );
CHECK_MPI_OK( mp_init(&sx) );
CHECK_MPI_OK( mp_init(&sy) );
p_size = mp_bpoly2arr(pp, p, 0) + 1;
p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size));
if (p == NULL) goto cleanup;
mp_bpoly2arr(pp, p, p_size);
/* if n = 0 then r = inf */
if (mp_cmp_z(n) == 0) {
mp_zero(rx);
mp_zero(ry);
err = MP_OKAY;
goto cleanup;
}
/* Q = P, k = n */
CHECK_MPI_OK( mp_copy(px, &qx) );
CHECK_MPI_OK( mp_copy(py, &qy) );
CHECK_MPI_OK( mp_copy(n, &k) );
/* if n < 0 then Q = -Q, k = -k */
if (mp_cmp_z(n) < 0) {
CHECK_MPI_OK( mp_badd(&qx, &qy, &qy) );
CHECK_MPI_OK( mp_neg(&k, &k) );
}
#ifdef EC_DEBUG /* basic double and add method */
l = mpl_significant_bits(&k) - 1;
mp_zero(&sx);
mp_zero(&sy);
for (i = l; i >= 0; i--) {
/* if k_i = 1, then S = S + Q */
if (mpl_get_bit(&k, i) != 0) {
CHECK_MPI_OK( GF2m_ec_pt_add_aff(pp, a, &sx, &sy, &qx, &qy, &sx, &sy) );
}
if (i > 0) {
/* S = 2S */
CHECK_MPI_OK( GF2m_ec_pt_dbl_aff(pp, a, &sx, &sy, &sx, &sy) );
}
}
#else /* double and add/subtract method from standard */
/* k3 = 3 * k */
mp_set(&k3, 0x3);
CHECK_MPI_OK( mp_mul(&k, &k3, &k3) );
/* S = Q */
CHECK_MPI_OK( mp_copy(&qx, &sx) );
CHECK_MPI_OK( mp_copy(&qy, &sy) );
/* l = index of high order bit in binary representation of 3*k */
l = mpl_significant_bits(&k3) - 1;
/* for i = l-1 downto 1 */
for (i = l - 1; i >= 1; i--) {
/* S = 2S */
CHECK_MPI_OK( GF2m_ec_pt_dbl_aff(pp, a, &sx, &sy, &sx, &sy) );
b3 = MP_GET_BIT(&k3, i);
b1 = MP_GET_BIT(&k, i);
/* if k3_i = 1 and k_i = 0, then S = S + Q */
if ((b3 == 1) && (b1 == 0)) {
CHECK_MPI_OK( GF2m_ec_pt_add_aff(pp, a, &sx, &sy, &qx, &qy, &sx, &sy) );
/* if k3_i = 0 and k_i = 1, then S = S - Q */
} else if ((b3 == 0) && (b1 == 1)) {
CHECK_MPI_OK( GF2m_ec_pt_sub_aff(pp, a, &sx, &sy, &qx, &qy, &sx, &sy) );
}
}
#endif
/* output S */
CHECK_MPI_OK( mp_copy(&sx, rx) );
CHECK_MPI_OK( mp_copy(&sy, ry) );
cleanup:
mp_clear(&k);
mp_clear(&k3);
mp_clear(&qx);
mp_clear(&qy);
mp_clear(&sx);
mp_clear(&sy);
free(p);
return err;
}
/* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery projective
* coordinates.
* Uses algorithm Mdouble in appendix of
* Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over
* GF(2^m) without precomputation".
* modified to not require precomputation of c=b^{2^{m-1}}.
*/
static mp_err
gf2m_Mdouble(const mp_int *pp, const unsigned int p[], const mp_int *a,
const mp_int *b, mp_int *x, mp_int *z)
{
mp_err err = MP_OKAY;
mp_int t1;
MP_DIGITS(&t1) = 0;
CHECK_MPI_OK( mp_init(&t1) );
CHECK_MPI_OK( mp_bsqrmod(x, p, x) );
CHECK_MPI_OK( mp_bsqrmod(z, p, &t1) );
CHECK_MPI_OK( mp_bmulmod(x, &t1, p, z) );
CHECK_MPI_OK( mp_bsqrmod(x, p, x) );
CHECK_MPI_OK( mp_bsqrmod(&t1, p, &t1) );
CHECK_MPI_OK( mp_bmulmod(b, &t1, p, &t1) );
CHECK_MPI_OK( mp_badd(x, &t1, x) );
cleanup:
mp_clear(&t1);
return err;
}
/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in Montgomery
* projective coordinates.
* Uses algorithm Madd in appendix of
* Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
* GF(2^m) without precomputation".
*/
static mp_err
gf2m_Madd(const mp_int *pp, const unsigned int p[], const mp_int *a,
const mp_int *b, const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2,
mp_int *z2)
{
mp_err err = MP_OKAY;
mp_int t1, t2;
MP_DIGITS(&t1) = 0;
MP_DIGITS(&t2) = 0;
CHECK_MPI_OK( mp_init(&t1) );
CHECK_MPI_OK( mp_init(&t2) );
CHECK_MPI_OK( mp_copy(x, &t1) );
CHECK_MPI_OK( mp_bmulmod(x1, z2, p, x1) );
CHECK_MPI_OK( mp_bmulmod(z1, x2, p, z1) );
CHECK_MPI_OK( mp_bmulmod(x1, z1, p, &t2) );
CHECK_MPI_OK( mp_badd(z1, x1, z1) );
CHECK_MPI_OK( mp_bsqrmod(z1, p, z1) );
CHECK_MPI_OK( mp_bmulmod(z1, &t1, p, x1) );
CHECK_MPI_OK( mp_badd(x1, &t2, x1) );
cleanup:
mp_clear(&t1);
mp_clear(&t2);
return err;
}
/* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2)
* using Montgomery point multiplication algorithm Mxy() in appendix of
* Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
* GF(2^m) without precomputation".
* Returns:
* 0 on error
* 1 if return value should be the point at infinity
* 2 otherwise
*/
static int
gf2m_Mxy(const mp_int *pp, const unsigned int p[], const mp_int *a,
const mp_int *b, const mp_int *x, const mp_int *y, mp_int *x1, mp_int *z1,
mp_int *x2, mp_int *z2)
{
mp_err err = MP_OKAY;
int ret;
mp_int t3, t4, t5;
MP_DIGITS(&t3) = 0;
MP_DIGITS(&t4) = 0;
MP_DIGITS(&t5) = 0;
CHECK_MPI_OK( mp_init(&t3) );
CHECK_MPI_OK( mp_init(&t4) );
CHECK_MPI_OK( mp_init(&t5) );
if (mp_cmp_z(z1) == 0) {
mp_zero(x2);
mp_zero(z2);
ret = 1;
goto cleanup;
}
if (mp_cmp_z(z2) == 0) {
CHECK_MPI_OK( mp_copy(x, x2) );
CHECK_MPI_OK( mp_badd(x, y, z2) );
ret = 2;
goto cleanup;
}
mp_set(&t5, 0x1);
CHECK_MPI_OK( mp_bmulmod(z1, z2, p, &t3) );
CHECK_MPI_OK( mp_bmulmod(z1, x, p, z1) );
CHECK_MPI_OK( mp_badd(z1, x1, z1) );
CHECK_MPI_OK( mp_bmulmod(z2, x, p, z2) );
CHECK_MPI_OK( mp_bmulmod(z2, x1, p, x1) );
CHECK_MPI_OK( mp_badd(z2, x2, z2) );
CHECK_MPI_OK( mp_bmulmod(z2, z1, p, z2) );
CHECK_MPI_OK( mp_bsqrmod(x, p, &t4) );
CHECK_MPI_OK( mp_badd(&t4, y, &t4) );
CHECK_MPI_OK( mp_bmulmod(&t4, &t3, p, &t4) );
CHECK_MPI_OK( mp_badd(&t4, z2, &t4) );
CHECK_MPI_OK( mp_bmulmod(&t3, x, p, &t3) );
CHECK_MPI_OK( mp_bdivmod(&t5, &t3, pp, p, &t3) );
CHECK_MPI_OK( mp_bmulmod(&t3, &t4, p, &t4) );
CHECK_MPI_OK( mp_bmulmod(x1, &t3, p, x2) );
CHECK_MPI_OK( mp_badd(x2, x, z2) );
CHECK_MPI_OK( mp_bmulmod(z2, &t4, p, z2) );
CHECK_MPI_OK( mp_badd(z2, y, z2) );
ret = 2;
cleanup:
mp_clear(&t3);
mp_clear(&t4);
mp_clear(&t5);
if (err == MP_OKAY) {
return ret;
} else {
return 0;
}
}
/* Computes R = nP based on algorithm 2P of
* Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
* GF(2^m) without precomputation".
* Elliptic curve points P and R can be identical.
* Uses Montgomery projective coordinates.
*/
mp_err
GF2m_ec_pt_mul_mont(const mp_int *pp, const mp_int *a, const mp_int *b,
const mp_int *px, const mp_int *py, const mp_int *n,
mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int x1, x2, z1, z2;
int i, j;
mp_digit top_bit, mask;
unsigned int *p;
int p_size;
MP_DIGITS(&x1) = 0;
MP_DIGITS(&x2) = 0;
MP_DIGITS(&z1) = 0;
MP_DIGITS(&z2) = 0;
CHECK_MPI_OK( mp_init(&x1) );
CHECK_MPI_OK( mp_init(&x2) );
CHECK_MPI_OK( mp_init(&z1) );
CHECK_MPI_OK( mp_init(&z2) );
p_size = mp_bpoly2arr(pp, p, 0) + 1;
p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size));
if (p == NULL) goto cleanup;
mp_bpoly2arr(pp, p, p_size);
/* if result should be point at infinity */
if ((mp_cmp_z(n) == 0) || (GF2m_ec_pt_is_inf_aff(px, py) == MP_YES)) {
CHECK_MPI_OK( GF2m_ec_pt_set_inf_aff(rx, ry) );
goto cleanup;
}
CHECK_MPI_OK( mp_copy(rx, &x2) ); /* x2 = rx */
CHECK_MPI_OK( mp_copy(ry, &z2) ); /* z2 = ry */
CHECK_MPI_OK( mp_copy(px, &x1) ); /* x1 = px */
mp_set(&z1, 0x1); /* z1 = 1 */
CHECK_MPI_OK( mp_bsqrmod(&x1, p, &z2) ); /* z2 = x1^2 = x2^2 */
CHECK_MPI_OK( mp_bsqrmod(&z2, p, &x2) );
CHECK_MPI_OK( mp_badd(&x2, b, &x2) ); /* x2 = px^4 + b */
/* find top-most bit and go one past it */
i = MP_USED(n) - 1;
j = MP_DIGIT_BIT - 1;
top_bit = 1;
top_bit <<= MP_DIGIT_BIT - 1;
mask = top_bit;
while (!(MP_DIGITS(n)[i] & mask)) {
mask >>= 1;
j--;
}
mask >>= 1; j--;
/* if top most bit was at word break, go to next word */
if (!mask) {
i--;
j = MP_DIGIT_BIT - 1;
mask = top_bit;
}
for (; i >= 0; i--) {
for (; j >= 0; j--) {
if (MP_DIGITS(n)[i] & mask) {
CHECK_MPI_OK( gf2m_Madd(pp, p, a, b, px, &x1, &z1, &x2, &z2) );
CHECK_MPI_OK( gf2m_Mdouble(pp, p, a, b, &x2, &z2) );
} else {
CHECK_MPI_OK( gf2m_Madd(pp, p, a, b, px, &x2, &z2, &x1, &z1) );
CHECK_MPI_OK( gf2m_Mdouble(pp, p, a, b, &x1, &z1) );
}
mask >>= 1;
}
j = MP_DIGIT_BIT - 1;
mask = top_bit;
}
/* convert out of "projective" coordinates */
i = gf2m_Mxy(pp, p, a, b, px, py, &x1, &z1, &x2, &z2);
if (i == 0) {
err = MP_BADARG;
goto cleanup;
} else if (i == 1) {
CHECK_MPI_OK( GF2m_ec_pt_set_inf_aff(rx, ry) );
} else {
CHECK_MPI_OK( mp_copy(&x2, rx) );
CHECK_MPI_OK( mp_copy(&z2, ry) );
}
cleanup:
mp_clear(&x1);
mp_clear(&x2);
mp_clear(&z1);
mp_clear(&z2);
free(p);
return err;
}
#endif /* NSS_ENABLE_ECC */

View File

@@ -1,96 +0,0 @@
/*
* 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 the elliptic curve math library for binary polynomial
* field curves.
*
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>
*
* Alternatively, the contents of this file may be used under the terms of
* either 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.
*
*/
#ifndef __gf2m_ecl_h_
#define __gf2m_ecl_h_
#ifdef NSS_ENABLE_ECC
#include "secmpi.h"
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
mp_err GF2m_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py);
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
mp_err GF2m_ec_pt_set_inf_aff(mp_int *px, mp_int *py);
/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx, qy).
* Uses affine coordinates.
*/
mp_err GF2m_ec_pt_add_aff(const mp_int *pp, const mp_int *a,
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry);
/* Computes R = P - Q. Uses affine coordinates. */
mp_err GF2m_ec_pt_sub_aff(const mp_int *pp, const mp_int *a,
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry);
/* Computes R = 2P. Uses affine coordinates. */
mp_err GF2m_ec_pt_dbl_aff(const mp_int *pp, const mp_int *a,
const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry);
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the irreducible that
* determines the field GF2m. Uses affine coordinates.
*/
mp_err GF2m_ec_pt_mul_aff(const mp_int *pp, const mp_int *a, const mp_int *b,
const mp_int *px, const mp_int *py, const mp_int *n,
mp_int *rx, mp_int *ry);
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the irreducible that
* determines the field GF2m. Uses Montgomery projective coordinates.
*/
mp_err GF2m_ec_pt_mul_mont(const mp_int *pp, const mp_int *a,
const mp_int *b, const mp_int *px, const mp_int *py,
const mp_int *n, mp_int *rx, mp_int *ry);
#define GF2m_ec_pt_is_inf(px, py) GF2m_ec_pt_is_inf_aff((px), (py))
#define GF2m_ec_pt_add(p, a, px, py, qx, qy, rx, ry) \
GF2m_ec_pt_add_aff((p), (a), (px), (py), (qx), (qy), (rx), (ry))
#define GF2m_ECL_MONTGOMERY
#ifdef GF2m_ECL_AFFINE
#define GF2m_ec_pt_mul(pp, a, b, px, py, n, rx, ry) \
GF2m_ec_pt_mul_aff((pp), (a), (b), (px), (py), (n), (rx), (ry))
#elif defined(GF2m_ECL_MONTGOMERY)
#define GF2m_ec_pt_mul(pp, a, b, px, py, n, rx, ry) \
GF2m_ec_pt_mul_mont((pp), (a), (b), (px), (py), (n), (rx), (ry))
#endif /* GF2m_ECL_AFFINE or GF2m_ECL_MONTGOMERY */
#endif /* NSS_ENABLE_ECC */
#endif /* __gf2m_ecl_h_ */

View File

@@ -1,647 +0,0 @@
/*
* 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 the elliptic curve math library for prime
* field curves.
*
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Sheueling Chang Shantz <sheueling.chang@sun.com> and
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
* Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>,
* Nils Larsch <nla@trustcenter.de>, and
* Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project.
*
* Alternatively, the contents of this file may be used under the terms of
* either 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.
*
*/
#ifdef NSS_ENABLE_ECC
/*
* GFp_ecl.c: Contains an implementation of elliptic curve math library
* for curves over GFp.
*
* XXX Can be moved to a separate subdirectory later.
*
*/
#include "GFp_ecl.h"
#include "mpi/mplogic.h"
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
mp_err
GFp_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py)
{
if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
return MP_YES;
} else {
return MP_NO;
}
}
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
mp_err
GFp_ec_pt_set_inf_aff(mp_int *px, mp_int *py)
{
mp_zero(px);
mp_zero(py);
return MP_OKAY;
}
/* Computes R = P + Q based on IEEE P1363 A.10.1.
* Elliptic curve points P, Q, and R can all be identical.
* Uses affine coordinates.
*/
mp_err
GFp_ec_pt_add_aff(const mp_int *p, const mp_int *a, const mp_int *px,
const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int lambda, temp, xtemp, ytemp;
CHECK_MPI_OK( mp_init(&lambda) );
CHECK_MPI_OK( mp_init(&temp) );
CHECK_MPI_OK( mp_init(&xtemp) );
CHECK_MPI_OK( mp_init(&ytemp) );
/* if P = inf, then R = Q */
if (GFp_ec_pt_is_inf_aff(px, py) == 0) {
CHECK_MPI_OK( mp_copy(qx, rx) );
CHECK_MPI_OK( mp_copy(qy, ry) );
err = MP_OKAY;
goto cleanup;
}
/* if Q = inf, then R = P */
if (GFp_ec_pt_is_inf_aff(qx, qy) == 0) {
CHECK_MPI_OK( mp_copy(px, rx) );
CHECK_MPI_OK( mp_copy(py, ry) );
err = MP_OKAY;
goto cleanup;
}
/* if px != qx, then lambda = (py-qy) / (px-qx) */
if (mp_cmp(px, qx) != 0) {
CHECK_MPI_OK( mp_submod(py, qy, p, &ytemp) );
CHECK_MPI_OK( mp_submod(px, qx, p, &xtemp) );
CHECK_MPI_OK( mp_invmod(&xtemp, p, &xtemp) );
CHECK_MPI_OK( mp_mulmod(&ytemp, &xtemp, p, &lambda) );
} else {
/* if py != qy or qy = 0, then R = inf */
if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) {
mp_zero(rx);
mp_zero(ry);
err = MP_OKAY;
goto cleanup;
}
/* lambda = (3qx^2+a) / (2qy) */
CHECK_MPI_OK( mp_sqrmod(qx, p, &xtemp) );
mp_set(&temp, 0x3);
CHECK_MPI_OK( mp_mulmod(&xtemp, &temp, p, &xtemp) );
CHECK_MPI_OK( mp_addmod(&xtemp, a, p, &xtemp) );
mp_set(&temp, 0x2);
CHECK_MPI_OK( mp_mulmod(qy, &temp, p, &ytemp) );
CHECK_MPI_OK( mp_invmod(&ytemp, p, &ytemp) );
CHECK_MPI_OK( mp_mulmod(&xtemp, &ytemp, p, &lambda) );
}
/* rx = lambda^2 - px - qx */
CHECK_MPI_OK( mp_sqrmod(&lambda, p, &xtemp) );
CHECK_MPI_OK( mp_submod(&xtemp, px, p, &xtemp) );
CHECK_MPI_OK( mp_submod(&xtemp, qx, p, &xtemp) );
/* ry = (x1-x2) * lambda - y1 */
CHECK_MPI_OK( mp_submod(qx, &xtemp, p, &ytemp) );
CHECK_MPI_OK( mp_mulmod(&ytemp, &lambda, p, &ytemp) );
CHECK_MPI_OK( mp_submod(&ytemp, qy, p, &ytemp) );
CHECK_MPI_OK( mp_copy(&xtemp, rx) );
CHECK_MPI_OK( mp_copy(&ytemp, ry) );
cleanup:
mp_clear(&lambda);
mp_clear(&temp);
mp_clear(&xtemp);
mp_clear(&ytemp);
return err;
}
/* Computes R = P - Q.
* Elliptic curve points P, Q, and R can all be identical.
* Uses affine coordinates.
*/
mp_err
GFp_ec_pt_sub_aff(const mp_int *p, const mp_int *a, const mp_int *px,
const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int nqy;
MP_DIGITS(&nqy) = 0;
CHECK_MPI_OK( mp_init(&nqy) );
/* nqy = -qy */
CHECK_MPI_OK( mp_neg(qy, &nqy) );
err = GFp_ec_pt_add_aff(p, a, px, py, qx, &nqy, rx, ry);
cleanup:
mp_clear(&nqy);
return err;
}
/* Computes R = 2P.
* Elliptic curve points P and R can be identical.
* Uses affine coordinates.
*/
mp_err
GFp_ec_pt_dbl_aff(const mp_int *p, const mp_int *a, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry)
{
return GFp_ec_pt_add_aff(p, a, px, py, px, py, rx, ry);
}
/* Gets the i'th bit in the binary representation of a.
* If i >= length(a), then return 0.
* (The above behaviour differs from mpl_get_bit, which
* causes an error if i >= length(a).)
*/
#define MP_GET_BIT(a, i) \
((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
/* Computes R = nP based on IEEE P1363 A.10.3.
* Elliptic curve points P and R can be identical.
* Uses affine coordinates.
*/
mp_err
GFp_ec_pt_mul_aff(const mp_int *p, const mp_int *a, const mp_int *b,
const mp_int *px, const mp_int *py, const mp_int *n, mp_int *rx,
mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int k, k3, qx, qy, sx, sy;
int b1, b3, i, l;
MP_DIGITS(&k) = 0;
MP_DIGITS(&k3) = 0;
MP_DIGITS(&qx) = 0;
MP_DIGITS(&qy) = 0;
MP_DIGITS(&sx) = 0;
MP_DIGITS(&sy) = 0;
CHECK_MPI_OK( mp_init(&k) );
CHECK_MPI_OK( mp_init(&k3) );
CHECK_MPI_OK( mp_init(&qx) );
CHECK_MPI_OK( mp_init(&qy) );
CHECK_MPI_OK( mp_init(&sx) );
CHECK_MPI_OK( mp_init(&sy) );
/* if n = 0 then r = inf */
if (mp_cmp_z(n) == 0) {
mp_zero(rx);
mp_zero(ry);
err = MP_OKAY;
goto cleanup;
}
/* Q = P, k = n */
CHECK_MPI_OK( mp_copy(px, &qx) );
CHECK_MPI_OK( mp_copy(py, &qy) );
CHECK_MPI_OK( mp_copy(n, &k) );
/* if n < 0 Q = -Q, k = -k */
if (mp_cmp_z(n) < 0) {
CHECK_MPI_OK( mp_neg(&qy, &qy) );
CHECK_MPI_OK( mp_mod(&qy, p, &qy) );
CHECK_MPI_OK( mp_neg(&k, &k) );
CHECK_MPI_OK( mp_mod(&k, p, &k) );
}
#ifdef EC_DEBUG /* basic double and add method */
l = mpl_significant_bits(&k) - 1;
mp_zero(&sx);
mp_zero(&sy);
for (i = l; i >= 0; i--) {
/* if k_i = 1, then S = S + Q */
if (mpl_get_bit(&k, i) != 0) {
CHECK_MPI_OK( GFp_ec_pt_add_aff(p, a, &sx, &sy,
&qx, &qy, &sx, &sy) );
}
if (i > 0) {
/* S = 2S */
CHECK_MPI_OK( GFp_ec_pt_dbl_aff(p, a, &sx, &sy, &sx, &sy) );
}
}
#else /* double and add/subtract method from standard */
/* k3 = 3 * k */
mp_set(&k3, 0x3);
CHECK_MPI_OK( mp_mul(&k, &k3, &k3) );
/* S = Q */
CHECK_MPI_OK( mp_copy(&qx, &sx) );
CHECK_MPI_OK( mp_copy(&qy, &sy) );
/* l = index of high order bit in binary representation of 3*k */
l = mpl_significant_bits(&k3) - 1;
/* for i = l-1 downto 1 */
for (i = l - 1; i >= 1; i--) {
/* S = 2S */
CHECK_MPI_OK( GFp_ec_pt_dbl_aff(p, a, &sx, &sy, &sx, &sy) );
b3 = MP_GET_BIT(&k3, i);
b1 = MP_GET_BIT(&k, i);
/* if k3_i = 1 and k_i = 0, then S = S + Q */
if ((b3 == 1) && (b1 == 0)) {
CHECK_MPI_OK( GFp_ec_pt_add_aff(p, a, &sx, &sy,
&qx, &qy, &sx, &sy) );
/* if k3_i = 0 and k_i = 1, then S = S - Q */
} else if ((b3 == 0) && (b1 == 1)) {
CHECK_MPI_OK( GFp_ec_pt_sub_aff(p, a, &sx, &sy,
&qx, &qy, &sx, &sy) );
}
}
#endif
/* output S */
CHECK_MPI_OK( mp_copy(&sx, rx) );
CHECK_MPI_OK( mp_copy(&sy, ry) );
cleanup:
mp_clear(&k);
mp_clear(&k3);
mp_clear(&qx);
mp_clear(&qy);
mp_clear(&sx);
mp_clear(&sy);
return err;
}
/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
* affine coordinates R(rx, ry). P and R can share x and y coordinates.
*/
mp_err
GFp_ec_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz,
const mp_int *p, mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int z1, z2, z3;
MP_DIGITS(&z1) = 0;
MP_DIGITS(&z2) = 0;
MP_DIGITS(&z3) = 0;
CHECK_MPI_OK( mp_init(&z1) );
CHECK_MPI_OK( mp_init(&z2) );
CHECK_MPI_OK( mp_init(&z3) );
/* if point at infinity, then set point at infinity and exit */
if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) {
CHECK_MPI_OK( GFp_ec_pt_set_inf_aff(rx, ry) );
goto cleanup;
}
/* transform (px, py, pz) into (px / pz^2, py / pz^3) */
if (mp_cmp_d(pz, 1) == 0) {
CHECK_MPI_OK( mp_copy(px, rx) );
CHECK_MPI_OK( mp_copy(py, ry) );
} else {
CHECK_MPI_OK( mp_invmod(pz, p, &z1) );
CHECK_MPI_OK( mp_sqrmod(&z1, p, &z2) );
CHECK_MPI_OK( mp_mulmod(&z1, &z2, p, &z3) );
CHECK_MPI_OK( mp_mulmod(px, &z2, p, rx) );
CHECK_MPI_OK( mp_mulmod(py, &z3, p, ry) );
}
cleanup:
mp_clear(&z1);
mp_clear(&z2);
mp_clear(&z3);
return err;
}
/* Checks if point P(px, py, pz) is at infinity.
* Uses Jacobian coordinates.
*/
mp_err
GFp_ec_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz)
{
return mp_cmp_z(pz);
}
/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
* coordinates.
*/
mp_err
GFp_ec_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz)
{
mp_zero(pz);
return MP_OKAY;
}
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and
* Q is (qx, qy, qz). Elliptic curve points P, Q, and R can all be
* identical. Uses Jacobian coordinates.
*
* This routine implements Point Addition in the Jacobian Projective
* space as described in the paper "Efficient elliptic curve exponentiation
* using mixed coordinates", by H. Cohen, A Miyaji, T. Ono.
*/
mp_err
GFp_ec_pt_add_jac(const mp_int *p, const mp_int *a, const mp_int *px,
const mp_int *py, const mp_int *pz, const mp_int *qx,
const mp_int *qy, const mp_int *qz, mp_int *rx, mp_int *ry, mp_int *rz)
{
mp_err err = MP_OKAY;
mp_int n0, u1, u2, s1, s2, H, G;
MP_DIGITS(&n0) = 0;
MP_DIGITS(&u1) = 0;
MP_DIGITS(&u2) = 0;
MP_DIGITS(&s1) = 0;
MP_DIGITS(&s2) = 0;
MP_DIGITS(&H) = 0;
MP_DIGITS(&G) = 0;
CHECK_MPI_OK( mp_init(&n0) );
CHECK_MPI_OK( mp_init(&u1) );
CHECK_MPI_OK( mp_init(&u2) );
CHECK_MPI_OK( mp_init(&s1) );
CHECK_MPI_OK( mp_init(&s2) );
CHECK_MPI_OK( mp_init(&H) );
CHECK_MPI_OK( mp_init(&G) );
/* Use point double if pointers are equal. */
if ((px == qx) && (py == qy) && (pz == qz)) {
err = GFp_ec_pt_dbl_jac(p, a, px, py, pz, rx, ry, rz);
goto cleanup;
}
/* If either P or Q is the point at infinity, then return
* the other point
*/
if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) {
CHECK_MPI_OK( mp_copy(qx, rx) );
CHECK_MPI_OK( mp_copy(qy, ry) );
CHECK_MPI_OK( mp_copy(qz, rz) );
goto cleanup;
}
if (GFp_ec_pt_is_inf_jac(qx, qy, qz) == MP_YES) {
CHECK_MPI_OK( mp_copy(px, rx) );
CHECK_MPI_OK( mp_copy(py, ry) );
CHECK_MPI_OK( mp_copy(pz, rz) );
goto cleanup;
}
/* Compute u1 = px * qz^2, s1 = py * qz^3 */
if (mp_cmp_d(qz, 1) == 0) {
CHECK_MPI_OK( mp_copy(px, &u1) );
CHECK_MPI_OK( mp_copy(py, &s1) );
} else {
CHECK_MPI_OK( mp_sqrmod(qz, p, &n0) );
CHECK_MPI_OK( mp_mulmod(px, &n0, p, &u1) );
CHECK_MPI_OK( mp_mulmod(&n0, qz, p, &n0) );
CHECK_MPI_OK( mp_mulmod(py, &n0, p, &s1) );
}
/* Compute u2 = qx * pz^2, s2 = qy * pz^3 */
if (mp_cmp_d(pz, 1) == 0) {
CHECK_MPI_OK( mp_copy(qx, &u2) );
CHECK_MPI_OK( mp_copy(qy, &s2) );
} else {
CHECK_MPI_OK( mp_sqrmod(pz, p, &n0) );
CHECK_MPI_OK( mp_mulmod(qx, &n0, p, &u2) );
CHECK_MPI_OK( mp_mulmod(&n0, pz, p, &n0) );
CHECK_MPI_OK( mp_mulmod(qy, &n0, p, &s2) );
}
/* Compute H = u2 - u1 ; G = s2 - s1 */
CHECK_MPI_OK( mp_submod(&u2, &u1, p, &H) );
CHECK_MPI_OK( mp_submod(&s2, &s1, p, &G) );
if (mp_cmp_z(&H) == 0) {
if (mp_cmp_z(&G) == 0) {
/* P = Q; double */
err = GFp_ec_pt_dbl_jac(p, a, px, py, pz,
rx, ry, rz);
goto cleanup;
} else {
/* P = -Q; return point at infinity */
CHECK_MPI_OK( GFp_ec_pt_set_inf_jac(rx, ry, rz) );
goto cleanup;
}
}
/* rz = pz * qz * H */
if (mp_cmp_d(pz, 1) == 0) {
if (mp_cmp_d(qz, 1) == 0) {
/* if pz == qz == 1, then rz = H */
CHECK_MPI_OK( mp_copy(&H, rz) );
} else {
CHECK_MPI_OK( mp_mulmod(qz, &H, p, rz) );
}
} else {
if (mp_cmp_d(qz, 1) == 0) {
CHECK_MPI_OK( mp_mulmod(pz, &H, p, rz) );
} else {
CHECK_MPI_OK( mp_mulmod(pz, qz, p, &n0) );
CHECK_MPI_OK( mp_mulmod(&n0, &H, p, rz) );
}
}
/* rx = G^2 - H^3 - 2 * u1 * H^2 */
CHECK_MPI_OK( mp_sqrmod(&G, p, rx) );
CHECK_MPI_OK( mp_sqrmod(&H, p, &n0) );
CHECK_MPI_OK( mp_mulmod(&n0, &u1, p, &u1) );
CHECK_MPI_OK( mp_addmod(&u1, &u1, p, &u2) );
CHECK_MPI_OK( mp_mulmod(&H, &n0, p, &H) );
CHECK_MPI_OK( mp_submod(rx, &H, p, rx) );
CHECK_MPI_OK( mp_submod(rx, &u2, p, rx) );
/* ry = - s1 * H^3 + G * (u1 * H^2 - rx) */
/* (formula based on values of variables before block above) */
CHECK_MPI_OK( mp_submod(&u1, rx, p, &u1) );
CHECK_MPI_OK( mp_mulmod(&G, &u1, p, ry) );
CHECK_MPI_OK( mp_mulmod(&s1, &H, p, &s1) );
CHECK_MPI_OK( mp_submod(ry, &s1, p, ry) );
cleanup:
mp_clear(&n0);
mp_clear(&u1);
mp_clear(&u2);
mp_clear(&s1);
mp_clear(&s2);
mp_clear(&H);
mp_clear(&G);
return err;
}
/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
* Jacobian coordinates.
*
* This routine implements Point Doubling in the Jacobian Projective
* space as described in the paper "Efficient elliptic curve exponentiation
* using mixed coordinates", by H. Cohen, A Miyaji, T. Ono.
*/
mp_err
GFp_ec_pt_dbl_jac(const mp_int *p, const mp_int *a, const mp_int *px,
const mp_int *py, const mp_int *pz, mp_int *rx, mp_int *ry, mp_int *rz)
{
mp_err err = MP_OKAY;
mp_int t0, t1, M, S;
MP_DIGITS(&t0) = 0;
MP_DIGITS(&t1) = 0;
MP_DIGITS(&M) = 0;
MP_DIGITS(&S) = 0;
CHECK_MPI_OK( mp_init(&t0) );
CHECK_MPI_OK( mp_init(&t1) );
CHECK_MPI_OK( mp_init(&M) );
CHECK_MPI_OK( mp_init(&S) );
if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) {
CHECK_MPI_OK( GFp_ec_pt_set_inf_jac(rx, ry, rz) );
goto cleanup;
}
if (mp_cmp_d(pz, 1) == 0) {
/* M = 3 * px^2 + a */
CHECK_MPI_OK( mp_sqrmod(px, p, &t0) );
CHECK_MPI_OK( mp_addmod(&t0, &t0, p, &M) );
CHECK_MPI_OK( mp_addmod(&t0, &M, p, &t0) );
CHECK_MPI_OK( mp_addmod(&t0, a, p, &M) );
} else if (mp_cmp_int(a, -3) == 0) {
/* M = 3 * (px + pz^2) * (px - pz) */
CHECK_MPI_OK( mp_sqrmod(pz, p, &M) );
CHECK_MPI_OK( mp_addmod(px, &M, p, &t0) );
CHECK_MPI_OK( mp_submod(px, &M, p, &t1) );
CHECK_MPI_OK( mp_mulmod(&t0, &t1, p, &M) );
CHECK_MPI_OK( mp_addmod(&M, &M, p, &t0) );
CHECK_MPI_OK( mp_addmod(&t0, &M, p, &M) );
} else {
CHECK_MPI_OK( mp_sqrmod(px, p, &t0) );
CHECK_MPI_OK( mp_addmod(&t0, &t0, p, &M) );
CHECK_MPI_OK( mp_addmod(&t0, &M, p, &t0) );
CHECK_MPI_OK( mp_sqrmod(pz, p, &M) );
CHECK_MPI_OK( mp_sqrmod(&M, p, &M) );
CHECK_MPI_OK( mp_mulmod(&M, a, p, &M) );
CHECK_MPI_OK( mp_addmod(&M, &t0, p, &M) );
}
/* rz = 2 * py * pz */
if (mp_cmp_d(pz, 1) == 0) {
CHECK_MPI_OK( mp_addmod(py, py, p, rz) );
CHECK_MPI_OK( mp_sqrmod(rz, p, &t0) );
} else {
CHECK_MPI_OK( mp_addmod(py, py, p, &t0) );
CHECK_MPI_OK( mp_mulmod(&t0, pz, p, rz) );
CHECK_MPI_OK( mp_sqrmod(&t0, p, &t0) );
}
/* S = 4 * px * py^2 = pz * (2 * py)^2 */
CHECK_MPI_OK( mp_mulmod(px, &t0, p, &S) );
/* rx = M^2 - 2 * S */
CHECK_MPI_OK( mp_addmod(&S, &S, p, &t1) );
CHECK_MPI_OK( mp_sqrmod(&M, p, rx) );
CHECK_MPI_OK( mp_submod(rx, &t1, p, rx) );
/* ry = M * (S - rx) - 8 * py^4 */
CHECK_MPI_OK( mp_sqrmod(&t0, p, &t1) );
if (mp_isodd(&t1)) {
CHECK_MPI_OK( mp_add(&t1, p, &t1) );
}
CHECK_MPI_OK( mp_div_2(&t1, &t1) );
CHECK_MPI_OK( mp_submod(&S, rx, p, &S) );
CHECK_MPI_OK( mp_mulmod(&M, &S, p, &M) );
CHECK_MPI_OK( mp_submod(&M, &t1, p, ry) );
cleanup:
mp_clear(&t0);
mp_clear(&t1);
mp_clear(&M);
mp_clear(&S);
return err;
}
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the prime that
* determines the field GFp. Elliptic curve points P and R can be
* identical. Uses Jacobian coordinates.
*/
mp_err
GFp_ec_pt_mul_jac(const mp_int *p, const mp_int *a, const mp_int *b,
const mp_int *px, const mp_int *py, const mp_int *n,
mp_int *rx, mp_int *ry)
{
mp_err err = MP_OKAY;
mp_int k, qx, qy, qz, sx, sy, sz;
int i, l;
MP_DIGITS(&k) = 0;
MP_DIGITS(&qx) = 0;
MP_DIGITS(&qy) = 0;
MP_DIGITS(&qz) = 0;
MP_DIGITS(&sx) = 0;
MP_DIGITS(&sy) = 0;
MP_DIGITS(&sz) = 0;
CHECK_MPI_OK( mp_init(&k) );
CHECK_MPI_OK( mp_init(&qx) );
CHECK_MPI_OK( mp_init(&qy) );
CHECK_MPI_OK( mp_init(&qz) );
CHECK_MPI_OK( mp_init(&sx) );
CHECK_MPI_OK( mp_init(&sy) );
CHECK_MPI_OK( mp_init(&sz) );
/* if n = 0 then r = inf */
if (mp_cmp_z(n) == 0) {
mp_zero(rx);
mp_zero(ry);
err = MP_OKAY;
goto cleanup;
/* if n < 0 then out of range error */
} else if (mp_cmp_z(n) < 0) {
err = MP_RANGE;
goto cleanup;
}
/* Q = P, k = n */
CHECK_MPI_OK( mp_copy(px, &qx) );
CHECK_MPI_OK( mp_copy(py, &qy) );
CHECK_MPI_OK( mp_set_int(&qz, 1) );
CHECK_MPI_OK( mp_copy(n, &k) );
/* double and add method */
l = mpl_significant_bits(&k) - 1;
mp_zero(&sx);
mp_zero(&sy);
mp_zero(&sz);
for (i = l; i >= 0; i--) {
/* if k_i = 1, then S = S + Q */
if (MP_GET_BIT(&k, i) != 0) {
CHECK_MPI_OK( GFp_ec_pt_add_jac(p, a, &sx, &sy, &sz,
&qx, &qy, &qz, &sx, &sy, &sz) );
}
if (i > 0) {
/* S = 2S */
CHECK_MPI_OK( GFp_ec_pt_dbl_jac(p, a, &sx, &sy, &sz,
&sx, &sy, &sz) );
}
}
/* convert result S to affine coordinates */
CHECK_MPI_OK( GFp_ec_pt_jac2aff(&sx, &sy, &sz, p, rx, ry) );
cleanup:
mp_clear(&k);
mp_clear(&qx);
mp_clear(&qy);
mp_clear(&qz);
mp_clear(&sx);
mp_clear(&sy);
mp_clear(&sz);
return err;
}
#endif /* NSS_ENABLE_ECC */

View File

@@ -1,126 +0,0 @@
/*
* 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 the elliptic curve math library for prime
* field curves.
*
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
*
* Alternatively, the contents of this file may be used under the terms of
* either 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.
*
*/
#ifndef __gfp_ecl_h_
#define __gfp_ecl_h_
#ifdef NSS_ENABLE_ECC
#include "secmpi.h"
/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
extern mp_err GFp_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py);
/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
extern mp_err GFp_ec_pt_set_inf_aff(mp_int *px, mp_int *py);
/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx, qy).
* Uses affine coordinates.
*/
extern mp_err GFp_ec_pt_add_aff(const mp_int *p, const mp_int *a,
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry);
/* Computes R = P - Q. Uses affine coordinates. */
extern mp_err GFp_ec_pt_sub_aff(const mp_int *p, const mp_int *a,
const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy,
mp_int *rx, mp_int *ry);
/* Computes R = 2P. Uses affine coordinates. */
extern mp_err GFp_ec_pt_dbl_aff(const mp_int *p, const mp_int *a,
const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry);
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the prime that
* determines the field GFp. Uses affine coordinates.
*/
extern mp_err GFp_ec_pt_mul_aff(const mp_int *p, const mp_int *a,
const mp_int *b, const mp_int *px, const mp_int *py, const mp_int *n,
mp_int *rx, mp_int *ry);
/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
* affine coordinates R(rx, ry).
*/
extern mp_err GFp_ec_pt_jac2aff(const mp_int *px, const mp_int *py,
const mp_int *pz, const mp_int *p, mp_int *rx, mp_int *ry);
/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
* coordinates.
*/
extern mp_err GFp_ec_pt_is_inf_jac(const mp_int *px, const mp_int *py,
const mp_int *pz);
/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
* coordinates.
*/
extern mp_err GFp_ec_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz);
/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and
* Q is (qx, qy, qz). Uses Jacobian coordinates.
*/
extern mp_err GFp_ec_pt_add_jac(const mp_int *p, const mp_int *a,
const mp_int *px, const mp_int *py, const mp_int *pz,
const mp_int *qx, const mp_int *qy, const mp_int *qz,
mp_int *rx, mp_int *ry, mp_int *rz);
/* Computes R = 2P. Uses Jacobian coordinates. */
extern mp_err GFp_ec_pt_dbl_jac(const mp_int *p, const mp_int *a,
const mp_int *px, const mp_int *py, const mp_int *pz,
mp_int *rx, mp_int *ry, mp_int *rz);
/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
* a, b and p are the elliptic curve coefficients and the prime that
* determines the field GFp. Uses Jacobian coordinates.
*/
mp_err GFp_ec_pt_mul_jac(const mp_int *p, const mp_int *a, const mp_int *b,
const mp_int *px, const mp_int *py, const mp_int *n,
mp_int *rx, mp_int *ry);
#define GFp_ec_pt_is_inf(px, py) GFp_ec_pt_is_inf_aff((px), (py))
#define GFp_ec_pt_add(p, a, px, py, qx, qy, rx, ry) \
GFp_ec_pt_add_aff((p), (a), (px), (py), (qx), (qy), (rx), (ry))
#define GFp_ECL_JACOBIAN
#ifdef GFp_ECL_AFFINE
#define GFp_ec_pt_mul(p, a, b, px, py, n, rx, ry) \
GFp_ec_pt_mul_aff((p), (a), (b), (px), (py), (n), (rx), (ry))
#elif defined(GFp_ECL_JACOBIAN)
#define GFp_ec_pt_mul(p, a, b, px, py, n, rx, ry) \
GFp_ec_pt_mul_jac((p), (a), (b), (px), (py), (n), (rx), (ry))
#endif /* GFp_ECL_AFFINE or GFp_ECL_JACOBIAN*/
#endif /* NSS_ENABLE_ECC */
#endif /* __gfp_ecl_h_ */

View File

@@ -1,339 +0,0 @@
#! gmake
#
# 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 the Netscape security libraries.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU General Public License Version 2 or later (the
# "GPL"), in which case the provisions of the GPL are applicable
# instead of those above. If you wish to allow use of your
# version of this file only under the terms of the GPL and not to
# allow others to use your version of this file under the MPL,
# indicate your decision by deleting the provisions above and
# replace them with the notice and other provisions required by
# the GPL. If you do not delete the provisions above, a recipient
# may use your version of this file under either the MPL or the
# GPL.
#
#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################
include manifest.mn
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
-include config.mk
ifdef USE_64
DEFINES += -DNSS_USE_64
endif
ifdef USE_HYBRID
DEFINES += -DNSS_USE_HYBRID
endif
# des.c wants _X86_ defined for intel CPUs.
# coreconf does this for windows, but not for Linux, FreeBSD, etc.
ifeq ($(CPU_ARCH),x86)
ifneq (,$(filter-out WIN%,$(OS_TARGET)))
OS_REL_CFLAGS += -D_X86_
endif
endif
ifeq ($(OS_TARGET),OSF1)
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_NO_MP_WORD
MPI_SRCS += mpvalpha.c
endif
ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET))) #omits WIN16 and WINCE
ifdef NS_USE_GCC
# Ideally, we want to use assembler
# ASFILES = mpi_x86.s
# DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE \
# -DMP_ASSEMBLY_DIV_2DX1D
# but we haven't figured out how to make it work, so we are not
# using assembler right now.
ASFILES =
DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT
else
ASFILES = mpi_x86.asm
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
endif
ifdef BUILD_OPT
ifndef NS_USE_GCC
OPTIMIZER += -Ox # maximum optimization for freebl
endif
endif
endif
ifeq ($(OS_TARGET),WINCE)
DEFINES += -DMP_ARGCHK=0 # no assert in WinCE
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
endif
ifdef XP_OS2_VACPP
ASFILES = mpi_x86.asm
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
endif
ifeq ($(OS_TARGET),IRIX)
ifeq ($(USE_N32),1)
ASFILES = mpi_mips.s
ifeq ($(NS_USE_GCC),1)
ASFLAGS = -Wp,-P -Wp,-traditional -O -mips3
else
ASFLAGS = -O -OPT:Olimit=4000 -dollar -fullwarn -xansi -n32 -mips3
endif
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
DEFINES += -DMP_USE_UINT_DIGIT
else
endif
endif
ifeq ($(OS_TARGET),Linux)
ifeq ($(CPU_ARCH),x86)
ASFILES = mpi_x86.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
endif
endif
ifeq ($(OS_TARGET),AIX)
DEFINES += -DMP_USE_UINT_DIGIT
ifndef USE_64
DEFINES += -DMP_NO_DIV_WORD -DMP_NO_ADD_WORD -DMP_NO_SUB_WORD
endif
endif
ifeq ($(OS_TARGET), HP-UX)
ifneq ($(OS_TEST), ia64)
MKSHLIB += +k +vshlibunsats -u FREEBL_GetVector +e FREEBL_GetVector
ifndef FREEBL_EXTENDED_BUILD
ifdef USE_PURE_32
# build for DA1.1 (HP PA 1.1) pure 32 bit model
DEFINES += -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
else
ifdef USE_64
# this builds for DA2.0W (HP PA 2.0 Wide), the LP64 ABI, using 32-bit digits
MPI_SRCS += mpi_hp.c
ASFILES += hpma512.s hppa20.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
else
# this builds for DA2.0 (HP PA 2.0 Narrow) hybrid model
# (the 32-bit ABI with 64-bit registers) using 32-bit digits
MPI_SRCS += mpi_hp.c
ASFILES += hpma512.s hppa20.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE
# This is done in coreconf by defining USE_LONG_LONGS
# OS_CFLAGS += -Aa +e +DA2.0 +DS2.0
endif
endif
endif
endif
endif
# Note: -xarch=v8 or v9 is now done in coreconf
ifeq ($(OS_TARGET),SunOS)
ifeq ($(CPU_ARCH),sparc)
ifndef NS_USE_GCC
ifdef USE_HYBRID
OS_CFLAGS += -xchip=ultra2
endif
endif
ifeq (5.5.1,$(firstword $(sort 5.5.1 $(OS_RELEASE))))
SYSV_SPARC = 1
endif
ifeq ($(SYSV_SPARC),1)
SOLARIS_AS = /usr/ccs/bin/as
ifdef NS_USE_GCC
ifdef GCC_USE_GNU_LD
MKSHLIB += -Wl,-Bsymbolic,-z,defs,-z,now,-z,text,--version-script,mapfile.Solaris
else
MKSHLIB += -Wl,-B,symbolic,-z,defs,-z,now,-z,text,-M,mapfile.Solaris
endif
else
MKSHLIB += -B symbolic -z defs -z now -z text -M mapfile.Solaris
endif
ifdef USE_PURE_32
# this builds for Sparc v8 pure 32-bit architecture
DEFINES += -DMP_USE_LONG_LONG_MULTIPLY -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD
DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512
else
ifdef USE_64
# this builds for Sparc v9a pure 64-bit architecture
MPI_SRCS += mpi_sparc.c
ASFILES = mpv_sparcv9.s montmulfv9.s
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_USING_MONT_MULF
DEFINES += -DMP_USE_UINT_DIGIT
# MPI_SRCS += mpv_sparc.c
# removed -xdepend from the following line
SOLARIS_FLAGS = -fast -xO5 -xrestrict=%all -xchip=ultra -xarch=v9a -KPIC -mt
SOLARIS_AS_FLAGS = -xarch=v9a -K PIC
else
# this builds for Sparc v8+a hybrid architecture, 64-bit registers, 32-bit ABI
MPI_SRCS += mpi_sparc.c
ASFILES = mpv_sparcv8.s montmulfv8.s
DEFINES += -DMP_NO_MP_WORD -DMP_ASSEMBLY_MULTIPLY -DMP_USING_MONT_MULF
DEFINES += -DMP_USE_UINT_DIGIT
SOLARIS_AS_FLAGS = -xarch=v8plusa -K PIC
# ASM_SUFFIX = .S
endif
endif
endif
else
# Solaris x86
DEFINES += -D_X86_
DEFINES += -DMP_USE_UINT_DIGIT
DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D
ASFILES = mpi_i86pc.s
ifdef NS_USE_GCC
LD = gcc
AS = gcc
ASFLAGS =
endif
endif
endif
$(OBJDIR)/sysrand$(OBJ_SUFFIX): sysrand.c unix_rand.c win_rand.c mac_rand.c os2_rand.c
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
export:: private_export
rijndael_tables:
$(CC) -o $(OBJDIR)/make_rijndael_tab rijndael_tables.c \
$(DEFINES) $(INCLUDES) $(OBJDIR)/libfreebl.a
$(OBJDIR)/make_rijndael_tab
ifdef MOZILLA_BSAFE_BUILD
private_export::
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
rm -f $(DIST)/lib/bsafe$(BSAFEVER).lib
endif
$(NSINSTALL) -R $(BSAFEPATH) $(DIST)/lib
endif
ifdef USE_PURE_32
vpath %.h $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
vpath %.c $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
vpath %.S $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
vpath %.s $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
vpath %.asm $(FREEBL_PARENT)/mpi:$(FREEBL_PARENT)
INCLUDES += -I$(FREEBL_PARENT) -I$(FREEBL_PARENT)/mpi
else
vpath %.h mpi
vpath %.c mpi
vpath %.S mpi
vpath %.s mpi
vpath %.asm mpi
INCLUDES += -Impi
endif
DEFINES += -DMP_API_COMPATIBLE
MPI_USERS = dh.c pqg.c dsa.c rsa.c ec.c GFp_ecl.c
MPI_OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_SRCS:.c=$(OBJ_SUFFIX)))
MPI_OBJS += $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_USERS:.c=$(OBJ_SUFFIX)))
$(MPI_OBJS): $(MPI_HDRS)
$(OBJDIR)/$(PROG_PREFIX)mpprime$(OBJ_SUFFIX): primes.c
$(OBJDIR)/ldvector$(OBJ_SUFFIX) $(OBJDIR)/loader$(OBJ_SUFFIX) : loader.h
ifeq ($(SYSV_SPARC),1)
$(OBJDIR)/mpv_sparcv8.o $(OBJDIR)/montmulfv8.o : $(OBJDIR)/%.o : %.s
@$(MAKE_OBJDIR)
$(SOLARIS_AS) -o $@ $(SOLARIS_AS_FLAGS) $<
$(OBJDIR)/mpv_sparcv9.o $(OBJDIR)/montmulfv9.o : $(OBJDIR)/%.o : %.s
@$(MAKE_OBJDIR)
$(SOLARIS_AS) -o $@ $(SOLARIS_AS_FLAGS) $<
$(OBJDIR)/mpmontg.o: mpmontg.c montmulf.h
endif
ifdef FREEBL_EXTENDED_BUILD
PURE32DIR = $(OBJDIR)/$(OS_TARGET)pure32
ALL_TRASH += $(PURE32DIR)
FILES2LN = \
$(wildcard *.tab) \
$(wildcard mapfile.*) \
Makefile manifest.mn config.mk
LINKEDFILES = $(addprefix $(PURE32DIR)/, $(FILES2LN))
CDDIR := $(shell pwd)
$(PURE32DIR):
-mkdir $(PURE32DIR)
-ln -s $(CDDIR)/mpi $(PURE32DIR)
$(LINKEDFILES) : $(PURE32DIR)/% : %
ln -s $(CDDIR)/$* $(PURE32DIR)
libs::
$(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_HYBRID=1 libs
libs:: $(PURE32DIR) $(LINKEDFILES)
cd $(PURE32DIR) && $(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_PURE_32=1 FREEBL_PARENT=$(CDDIR) CORE_DEPTH=$(CDDIR)/$(CORE_DEPTH) libs
release_md::
$(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_HYBRID=1 $@
cd $(PURE32DIR) && $(MAKE) FREEBL_RECURSIVE_BUILD=1 USE_PURE_32=1 FREEBL_PARENT=$(CDDIR) CORE_DEPTH=$(CDDIR)/$(CORE_DEPTH) $@
endif

View File

@@ -1,383 +0,0 @@
/*
* aeskeywrap.c - implement AES Key Wrap algorithm from RFC 3394
*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2002, 2003 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: aeskeywrap.c,v 1.1 2003-01-14 22:16:04 nelsonb%netscape.com Exp $
*/
#include "prcpucfg.h"
#if defined(IS_LITTLE_ENDIAN) || defined(SHA_NO_LONG_LONG)
#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 0
#else
#define BIG_ENDIAN_WITH_64_BIT_REGISTERS 1
#endif
#include "prtypes.h" /* for PRUintXX */
#include "secport.h" /* for PORT_XXX */
#include "secerr.h"
#include "blapi.h" /* for AES_ functions */
struct AESKeyWrapContextStr {
AESContext * aescx;
unsigned char iv[AES_KEY_WRAP_IV_BYTES];
};
/******************************************/
/*
** AES key wrap algorithm, RFC 3394
*/
/*
** Create a new AES context suitable for AES encryption/decryption.
** "key" raw key data
** "keylen" the number of bytes of key data (16, 24, or 32)
*/
extern AESKeyWrapContext *
AESKeyWrap_CreateContext(const unsigned char *key, const unsigned char *iv,
int encrypt, unsigned int keylen)
{
AESKeyWrapContext * cx = PORT_ZNew(AESKeyWrapContext);
if (!cx)
return NULL; /* error is already set */
cx->aescx = AES_CreateContext(key, NULL, NSS_AES, encrypt, keylen,
AES_BLOCK_SIZE);
if (!cx->aescx) {
PORT_Free(cx);
return NULL; /* error should already be set */
}
if (iv) {
memcpy(cx->iv, iv, AES_KEY_WRAP_IV_BYTES);
} else {
memset(cx->iv, 0xA6, AES_KEY_WRAP_IV_BYTES);
}
return cx;
}
/*
** Destroy a AES KeyWrap context.
** "cx" the context
** "freeit" if PR_TRUE then free the object as well as its sub-objects
*/
extern void
AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
{
if (cx) {
if (cx->aescx)
AES_DestroyContext(cx->aescx, PR_TRUE);
memset(cx, 0, sizeof *cx);
if (freeit)
PORT_Free(cx);
}
}
#if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
/* The AES Key Wrap algorithm has 64-bit values that are ALWAYS big-endian
** (Most significant byte first) in memory. The only ALU operations done
** on them are increment, decrement, and XOR. So, on little-endian CPUs,
** and on CPUs that lack 64-bit registers, these big-endian 64-bit operations
** are simulated in the following code. This is thought to be faster and
** simpler than trying to convert the data to little-endian and back.
*/
/* A and T point to two 64-bit values stored most signficant byte first
** (big endian). This function increments the 64-bit value T, and then
** XORs it with A, changing A.
*/
static void
increment_and_xor(unsigned char *A, unsigned char *T)
{
if (!++T[7])
if (!++T[6])
if (!++T[5])
if (!++T[4])
if (!++T[3])
if (!++T[2])
if (!++T[1])
++T[0];
A[0] ^= T[0];
A[1] ^= T[1];
A[2] ^= T[2];
A[3] ^= T[3];
A[4] ^= T[4];
A[5] ^= T[5];
A[6] ^= T[6];
A[7] ^= T[7];
}
/* A and T point to two 64-bit values stored most signficant byte first
** (big endian). This function XORs T with A, giving a new A, then
** decrements the 64-bit value T.
*/
static void
xor_and_decrement(unsigned char *A, unsigned char *T)
{
A[0] ^= T[0];
A[1] ^= T[1];
A[2] ^= T[2];
A[3] ^= T[3];
A[4] ^= T[4];
A[5] ^= T[5];
A[6] ^= T[6];
A[7] ^= T[7];
if (!T[7]--)
if (!T[6]--)
if (!T[5]--)
if (!T[4]--)
if (!T[3]--)
if (!T[2]--)
if (!T[1]--)
T[0]--;
}
/* Given an unsigned long t (in host byte order), store this value as a
** 64-bit big-endian value (MSB first) in *pt.
*/
static void
set_t(unsigned char *pt, unsigned long t)
{
pt[7] = (unsigned char)t; t >>= 8;
pt[6] = (unsigned char)t; t >>= 8;
pt[5] = (unsigned char)t; t >>= 8;
pt[4] = (unsigned char)t; t >>= 8;
pt[3] = (unsigned char)t; t >>= 8;
pt[2] = (unsigned char)t; t >>= 8;
pt[1] = (unsigned char)t; t >>= 8;
pt[0] = (unsigned char)t;
}
#endif
/*
** Perform AES key wrap.
** "cx" the context
** "output" the output buffer to store the encrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
extern SECStatus
AESKeyWrap_Encrypt(AESKeyWrapContext *cx, unsigned char *output,
unsigned int *pOutputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint64 * R = NULL;
unsigned int nBlocks;
unsigned int i, j;
unsigned int aesLen = AES_BLOCK_SIZE;
unsigned int outLen = inputLen + AES_KEY_WRAP_BLOCK_SIZE;
SECStatus s = SECFailure;
/* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
PRUint64 t;
PRUint64 B[2];
#define A B[0]
/* Check args */
if (!inputLen || 0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return s;
}
#ifdef maybe
if (!output && pOutputLen) { /* caller is asking for output size */
*pOutputLen = outLen;
return SECSuccess;
}
#endif
if (maxOutputLen < outLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return s;
}
if (cx == NULL || output == NULL || input == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return s;
}
nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
R = PORT_NewArray(PRUint64, nBlocks + 1);
if (!R)
return s; /* error is already set. */
/*
** 1) Initialize variables.
*/
memcpy(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
memcpy(&R[1], input, inputLen);
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
t = 0;
#else
memset(&t, 0, sizeof t);
#endif
/*
** 2) Calculate intermediate values.
*/
for (j = 0; j < 6; ++j) {
for (i = 1; i <= nBlocks; ++i) {
B[1] = R[i];
s = AES_Encrypt(cx->aescx, (unsigned char *)B, &aesLen,
sizeof B, (unsigned char *)B, sizeof B);
if (s != SECSuccess)
break;
R[i] = B[1];
/* here, increment t and XOR A with t (in big endian order); */
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
A ^= ++t;
#else
increment_and_xor((unsigned char *)&A, (unsigned char *)&t);
#endif
}
}
/*
** 3) Output the results.
*/
if (s == SECSuccess) {
R[0] = A;
memcpy(output, &R[0], outLen);
if (pOutputLen)
*pOutputLen = outLen;
} else if (pOutputLen) {
*pOutputLen = 0;
}
PORT_ZFree(R, outLen);
return s;
}
#undef A
/*
** Perform AES key unwrap.
** "cx" the context
** "output" the output buffer to store the decrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
extern SECStatus
AESKeyWrap_Decrypt(AESKeyWrapContext *cx, unsigned char *output,
unsigned int *pOutputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint64 * R = NULL;
unsigned int nBlocks;
unsigned int i, j;
unsigned int aesLen = AES_BLOCK_SIZE;
unsigned int outLen;
SECStatus s = SECFailure;
/* These PRUint64s are ALWAYS big endian, regardless of CPU orientation. */
PRUint64 t;
PRUint64 B[2];
#define A B[0]
/* Check args */
if (inputLen < 3 * AES_KEY_WRAP_BLOCK_SIZE ||
0 != inputLen % AES_KEY_WRAP_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return s;
}
outLen = inputLen - AES_KEY_WRAP_BLOCK_SIZE;
#ifdef maybe
if (!output && pOutputLen) { /* caller is asking for output size */
*pOutputLen = outLen;
return SECSuccess;
}
#endif
if (maxOutputLen < outLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return s;
}
if (cx == NULL || output == NULL || input == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return s;
}
nBlocks = inputLen / AES_KEY_WRAP_BLOCK_SIZE;
R = PORT_NewArray(PRUint64, nBlocks);
if (!R)
return s; /* error is already set. */
nBlocks--;
/*
** 1) Initialize variables.
*/
memcpy(&R[0], input, inputLen);
A = R[0];
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
t = 6UL * nBlocks;
#else
set_t((unsigned char *)&t, 6UL * nBlocks);
#endif
/*
** 2) Calculate intermediate values.
*/
for (j = 0; j < 6; ++j) {
for (i = nBlocks; i; --i) {
/* here, XOR A with t (in big endian order) and decrement t; */
#if BIG_ENDIAN_WITH_64_BIT_REGISTERS
A ^= t--;
#else
xor_and_decrement((unsigned char *)&A, (unsigned char *)&t);
#endif
B[1] = R[i];
s = AES_Decrypt(cx->aescx, (unsigned char *)B, &aesLen,
sizeof B, (unsigned char *)B, sizeof B);
if (s != SECSuccess)
break;
R[i] = B[1];
}
}
/*
** 3) Output the results.
*/
if (s == SECSuccess) {
int bad = memcmp(&A, cx->iv, AES_KEY_WRAP_IV_BYTES);
if (!bad) {
memcpy(output, &R[1], outLen);
if (pOutputLen)
*pOutputLen = outLen;
} else {
PORT_SetError(SEC_ERROR_BAD_DATA);
if (pOutputLen)
*pOutputLen = 0;
}
} else if (pOutputLen) {
*pOutputLen = 0;
}
PORT_ZFree(R, inputLen);
return s;
}
#undef A

View File

@@ -1,493 +0,0 @@
/*
* alg2268.c - implementation of the algorithm in RFC 2268
*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: alg2268.c,v 1.4 2002-11-16 06:09:57 nelsonb%netscape.com Exp $
*/
#include "blapi.h"
#include "secerr.h"
#ifdef XP_UNIX_XXX
#include <stddef.h> /* for ptrdiff_t */
#endif
/*
** RC2 symmetric block cypher
*/
typedef SECStatus (rc2Func)(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen);
/* forward declarations */
static rc2Func rc2_EncryptECB;
static rc2Func rc2_DecryptECB;
static rc2Func rc2_EncryptCBC;
static rc2Func rc2_DecryptCBC;
typedef union {
PRUint32 l[2];
PRUint16 s[4];
PRUint8 b[8];
} RC2Block;
struct RC2ContextStr {
union {
PRUint8 Kb[128];
PRUint16 Kw[64];
} u;
RC2Block iv;
rc2Func *enc;
rc2Func *dec;
};
#define B u.Kb
#define K u.Kw
#define BYTESWAP(x) ((x) << 8 | (x) >> 8)
#define SWAPK(i) cx->K[i] = (tmpS = cx->K[i], BYTESWAP(tmpS))
#define RC2_BLOCK_SIZE 8
#define LOAD_HARD(R) \
R[0] = (PRUint16)input[1] << 8 | input[0]; \
R[1] = (PRUint16)input[3] << 8 | input[2]; \
R[2] = (PRUint16)input[5] << 8 | input[4]; \
R[3] = (PRUint16)input[7] << 8 | input[6];
#define LOAD_EASY(R) \
R[0] = ((PRUint16 *)input)[0]; \
R[1] = ((PRUint16 *)input)[1]; \
R[2] = ((PRUint16 *)input)[2]; \
R[3] = ((PRUint16 *)input)[3];
#define STORE_HARD(R) \
output[0] = (PRUint8)(R[0]); output[1] = (PRUint8)(R[0] >> 8); \
output[2] = (PRUint8)(R[1]); output[3] = (PRUint8)(R[1] >> 8); \
output[4] = (PRUint8)(R[2]); output[5] = (PRUint8)(R[2] >> 8); \
output[6] = (PRUint8)(R[3]); output[7] = (PRUint8)(R[3] >> 8);
#define STORE_EASY(R) \
((PRUint16 *)output)[0] = R[0]; \
((PRUint16 *)output)[1] = R[1]; \
((PRUint16 *)output)[2] = R[2]; \
((PRUint16 *)output)[3] = R[3];
#if defined (_X86_)
#define LOAD(R) LOAD_EASY(R)
#define STORE(R) STORE_EASY(R)
#elif !defined(IS_LITTLE_ENDIAN)
#define LOAD(R) LOAD_HARD(R)
#define STORE(R) STORE_HARD(R)
#else
#define LOAD(R) if ((ptrdiff_t)input & 1) { LOAD_HARD(R) } else { LOAD_EASY(R) }
#define STORE(R) if ((ptrdiff_t)input & 1) { STORE_HARD(R) } else { STORE_EASY(R) }
#endif
static const PRUint8 S[256] = {
0331,0170,0371,0304,0031,0335,0265,0355,0050,0351,0375,0171,0112,0240,0330,0235,
0306,0176,0067,0203,0053,0166,0123,0216,0142,0114,0144,0210,0104,0213,0373,0242,
0027,0232,0131,0365,0207,0263,0117,0023,0141,0105,0155,0215,0011,0201,0175,0062,
0275,0217,0100,0353,0206,0267,0173,0013,0360,0225,0041,0042,0134,0153,0116,0202,
0124,0326,0145,0223,0316,0140,0262,0034,0163,0126,0300,0024,0247,0214,0361,0334,
0022,0165,0312,0037,0073,0276,0344,0321,0102,0075,0324,0060,0243,0074,0266,0046,
0157,0277,0016,0332,0106,0151,0007,0127,0047,0362,0035,0233,0274,0224,0103,0003,
0370,0021,0307,0366,0220,0357,0076,0347,0006,0303,0325,0057,0310,0146,0036,0327,
0010,0350,0352,0336,0200,0122,0356,0367,0204,0252,0162,0254,0065,0115,0152,0052,
0226,0032,0322,0161,0132,0025,0111,0164,0113,0237,0320,0136,0004,0030,0244,0354,
0302,0340,0101,0156,0017,0121,0313,0314,0044,0221,0257,0120,0241,0364,0160,0071,
0231,0174,0072,0205,0043,0270,0264,0172,0374,0002,0066,0133,0045,0125,0227,0061,
0055,0135,0372,0230,0343,0212,0222,0256,0005,0337,0051,0020,0147,0154,0272,0311,
0323,0000,0346,0317,0341,0236,0250,0054,0143,0026,0001,0077,0130,0342,0211,0251,
0015,0070,0064,0033,0253,0063,0377,0260,0273,0110,0014,0137,0271,0261,0315,0056,
0305,0363,0333,0107,0345,0245,0234,0167,0012,0246,0040,0150,0376,0177,0301,0255
};
/*
** Create a new RC2 context suitable for RC2 encryption/decryption.
** "key" raw key data
** "len" the number of bytes of key data
** "iv" is the CBC initialization vector (if mode is NSS_RC2_CBC)
** "mode" one of NSS_RC2 or NSS_RC2_CBC
** "effectiveKeyLen" in bytes, not bits.
**
** When mode is set to NSS_RC2_CBC the RC2 cipher is run in "cipher block
** chaining" mode.
*/
RC2Context *
RC2_CreateContext(const unsigned char *key, unsigned int len,
const unsigned char *input, int mode, unsigned efLen8)
{
RC2Context *cx;
PRUint8 *L,*L2;
int i;
#if !defined(IS_LITTLE_ENDIAN)
PRUint16 tmpS;
#endif
PRUint8 tmpB;
if (!key || len == 0 || len > (sizeof cx->B) || efLen8 > (sizeof cx->B)) {
return NULL;
}
if (mode == NSS_RC2) {
/* groovy */
} else if (mode == NSS_RC2_CBC) {
if (!input) {
return NULL; /* not groovy */
}
} else {
return NULL;
}
cx = PORT_ZNew(RC2Context);
if (!cx)
return cx;
if (mode == NSS_RC2_CBC) {
cx->enc = & rc2_EncryptCBC;
cx->dec = & rc2_DecryptCBC;
LOAD(cx->iv.s);
} else {
cx->enc = & rc2_EncryptECB;
cx->dec = & rc2_DecryptECB;
}
/* Step 0. Copy key into table. */
memcpy(cx->B, key, len);
/* Step 1. Compute all values to the right of the key. */
L2 = cx->B;
L = L2 + len;
tmpB = L[-1];
for (i = (sizeof cx->B) - len; i > 0; --i) {
*L++ = tmpB = S[ (PRUint8)(tmpB + *L2++) ];
}
/* step 2. Adjust left most byte of effective key. */
i = (sizeof cx->B) - efLen8;
L = cx->B + i;
*L = tmpB = S[*L]; /* mask is always 0xff */
/* step 3. Recompute all values to the left of effective key. */
L2 = --L + efLen8;
while(L >= cx->B) {
*L-- = tmpB = S[ tmpB ^ *L2-- ];
}
#if !defined(IS_LITTLE_ENDIAN)
for (i = 63; i >= 0; --i) {
SWAPK(i); /* candidate for unrolling */
}
#endif
return cx;
}
/*
** Destroy an RC2 encryption/decryption context.
** "cx" the context
** "freeit" if PR_TRUE then free the object as well as its sub-objects
*/
void
RC2_DestroyContext(RC2Context *cx, PRBool freeit)
{
if (cx) {
memset(cx, 0, sizeof *cx);
if (freeit) {
PORT_Free(cx);
}
}
}
#define ROL(x,k) (x << k | x >> (16-k))
#define MIX(j) \
R0 = R0 + cx->K[ 4*j+0] + (R3 & R2) + (~R3 & R1); R0 = ROL(R0,1);\
R1 = R1 + cx->K[ 4*j+1] + (R0 & R3) + (~R0 & R2); R1 = ROL(R1,2);\
R2 = R2 + cx->K[ 4*j+2] + (R1 & R0) + (~R1 & R3); R2 = ROL(R2,3);\
R3 = R3 + cx->K[ 4*j+3] + (R2 & R1) + (~R2 & R0); R3 = ROL(R3,5)
#define MASH \
R0 = R0 + cx->K[R3 & 63];\
R1 = R1 + cx->K[R0 & 63];\
R2 = R2 + cx->K[R1 & 63];\
R3 = R3 + cx->K[R2 & 63]
/* Encrypt one block */
static void
rc2_Encrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
{
register PRUint16 R0, R1, R2, R3;
/* step 1. Initialize input. */
R0 = input->s[0];
R1 = input->s[1];
R2 = input->s[2];
R3 = input->s[3];
/* step 2. Expand Key (already done, in context) */
/* step 3. j = 0 */
/* step 4. Perform 5 mixing rounds. */
MIX(0);
MIX(1);
MIX(2);
MIX(3);
MIX(4);
/* step 5. Perform 1 mashing round. */
MASH;
/* step 6. Perform 6 mixing rounds. */
MIX(5);
MIX(6);
MIX(7);
MIX(8);
MIX(9);
MIX(10);
/* step 7. Perform 1 mashing round. */
MASH;
/* step 8. Perform 5 mixing rounds. */
MIX(11);
MIX(12);
MIX(13);
MIX(14);
MIX(15);
/* output results */
output->s[0] = R0;
output->s[1] = R1;
output->s[2] = R2;
output->s[3] = R3;
}
#define ROR(x,k) (x >> k | x << (16-k))
#define R_MIX(j) \
R3 = ROR(R3,5); R3 = R3 - cx->K[ 4*j+3] - (R2 & R1) - (~R2 & R0); \
R2 = ROR(R2,3); R2 = R2 - cx->K[ 4*j+2] - (R1 & R0) - (~R1 & R3); \
R1 = ROR(R1,2); R1 = R1 - cx->K[ 4*j+1] - (R0 & R3) - (~R0 & R2); \
R0 = ROR(R0,1); R0 = R0 - cx->K[ 4*j+0] - (R3 & R2) - (~R3 & R1)
#define R_MASH \
R3 = R3 - cx->K[R2 & 63];\
R2 = R2 - cx->K[R1 & 63];\
R1 = R1 - cx->K[R0 & 63];\
R0 = R0 - cx->K[R3 & 63]
/* Encrypt one block */
static void
rc2_Decrypt1Block(RC2Context *cx, RC2Block *output, RC2Block *input)
{
register PRUint16 R0, R1, R2, R3;
/* step 1. Initialize input. */
R0 = input->s[0];
R1 = input->s[1];
R2 = input->s[2];
R3 = input->s[3];
/* step 2. Expand Key (already done, in context) */
/* step 3. j = 63 */
/* step 4. Perform 5 r_mixing rounds. */
R_MIX(15);
R_MIX(14);
R_MIX(13);
R_MIX(12);
R_MIX(11);
/* step 5. Perform 1 r_mashing round. */
R_MASH;
/* step 6. Perform 6 r_mixing rounds. */
R_MIX(10);
R_MIX(9);
R_MIX(8);
R_MIX(7);
R_MIX(6);
R_MIX(5);
/* step 7. Perform 1 r_mashing round. */
R_MASH;
/* step 8. Perform 5 r_mixing rounds. */
R_MIX(4);
R_MIX(3);
R_MIX(2);
R_MIX(1);
R_MIX(0);
/* output results */
output->s[0] = R0;
output->s[1] = R1;
output->s[2] = R2;
output->s[3] = R3;
}
static SECStatus
rc2_EncryptECB(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
rc2_Encrypt1Block(cx, &iBlock, &iBlock);
STORE(iBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
static SECStatus
rc2_DecryptECB(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
rc2_Decrypt1Block(cx, &iBlock, &iBlock);
STORE(iBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
static SECStatus
rc2_EncryptCBC(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
iBlock.l[0] ^= cx->iv.l[0];
iBlock.l[1] ^= cx->iv.l[1];
rc2_Encrypt1Block(cx, &iBlock, &iBlock);
cx->iv = iBlock;
STORE(iBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
static SECStatus
rc2_DecryptCBC(RC2Context *cx, unsigned char *output,
const unsigned char *input, unsigned int inputLen)
{
RC2Block iBlock;
RC2Block oBlock;
while (inputLen > 0) {
LOAD(iBlock.s)
rc2_Decrypt1Block(cx, &oBlock, &iBlock);
oBlock.l[0] ^= cx->iv.l[0];
oBlock.l[1] ^= cx->iv.l[1];
cx->iv = iBlock;
STORE(oBlock.s)
output += RC2_BLOCK_SIZE;
input += RC2_BLOCK_SIZE;
inputLen -= RC2_BLOCK_SIZE;
}
return SECSuccess;
}
/*
** Perform RC2 encryption.
** "cx" the context
** "output" the output buffer to store the encrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus RC2_Encrypt(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
SECStatus rv = SECSuccess;
if (inputLen) {
if (inputLen % RC2_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
rv = (*cx->enc)(cx, output, input, inputLen);
}
if (rv == SECSuccess) {
*outputLen = inputLen;
}
return rv;
}
/*
** Perform RC2 decryption.
** "cx" the context
** "output" the output buffer to store the decrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus RC2_Decrypt(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
SECStatus rv = SECSuccess;
if (inputLen) {
if (inputLen % RC2_BLOCK_SIZE) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
rv = (*cx->dec)(cx, output, input, inputLen);
}
if (rv == SECSuccess) {
*outputLen = inputLen;
}
return rv;
}

View File

@@ -1,114 +0,0 @@
/*
* arcfive.c - stubs for RC5 - NOT a working implementation!
*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: arcfive.c,v 1.3 2002-11-16 06:09:57 nelsonb%netscape.com Exp $
*/
#include "blapi.h"
#include "prerror.h"
/******************************************/
/*
** RC5 symmetric block cypher -- 64-bit block size
*/
/*
** Create a new RC5 context suitable for RC5 encryption/decryption.
** "key" raw key data
** "len" the number of bytes of key data
** "iv" is the CBC initialization vector (if mode is NSS_RC5_CBC)
** "mode" one of NSS_RC5 or NSS_RC5_CBC
**
** When mode is set to NSS_RC5_CBC the RC5 cipher is run in "cipher block
** chaining" mode.
*/
RC5Context *
RC5_CreateContext(const SECItem *key, unsigned int rounds,
unsigned int wordSize, const unsigned char *iv, int mode)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return NULL;
}
/*
** Destroy an RC5 encryption/decryption context.
** "cx" the context
** "freeit" if PR_TRUE then free the object as well as its sub-objects
*/
void
RC5_DestroyContext(RC5Context *cx, PRBool freeit)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
}
/*
** Perform RC5 encryption.
** "cx" the context
** "output" the output buffer to store the encrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus
RC5_Encrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
/*
** Perform RC5 decryption.
** "cx" the context
** "output" the output buffer to store the decrypted data.
** "outputLen" how much data is stored in "output". Set by the routine
** after some data is stored in output.
** "maxOutputLen" the maximum amount of data that can ever be
** stored in "output"
** "input" the input data
** "inputLen" the amount of input data
*/
SECStatus
RC5_Decrypt(RC5Context *cx, unsigned char *output, unsigned int *outputLen,
unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}

View File

@@ -1,567 +0,0 @@
/*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#include "prerr.h"
#include "secerr.h"
#include "prtypes.h"
#include "blapi.h"
/* Architecture-dependent defines */
#if defined(SOLARIS) || defined(HPUX) || defined(i386) || defined(IRIX)
/* Convert the byte-stream to a word-stream */
#define CONVERT_TO_WORDS
#endif
#if defined(AIX) || defined(OSF1)
/* Treat array variables as longs, not bytes */
#define USE_LONG
#endif
#if defined(_WIN32_WCE)
#undef WORD
#define WORD ARC4WORD
#endif
#if defined(NSS_USE_HYBRID) && !defined(SOLARIS) && !defined(NSS_USE_64)
typedef unsigned long long WORD;
#else
typedef unsigned long WORD;
#endif
#define WORDSIZE sizeof(WORD)
#ifdef USE_LONG
typedef unsigned long Stype;
#else
typedef PRUint8 Stype;
#endif
#define ARCFOUR_STATE_SIZE 256
#define MASK1BYTE (WORD)(0xff)
#define SWAP(a, b) \
tmp = a; \
a = b; \
b = tmp;
/*
* State information for stream cipher.
*/
struct RC4ContextStr
{
Stype S[ARCFOUR_STATE_SIZE];
PRUint8 i;
PRUint8 j;
};
/*
* array indices [0..255] to initialize cx->S array (faster than loop).
*/
static const Stype Kinit[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
/*
* Initialize a new generator.
*/
RC4Context *
RC4_CreateContext(const unsigned char *key, int len)
{
int i;
PRUint8 j, tmp;
RC4Context *cx;
PRUint8 K[256];
PRUint8 *L;
/* verify the key length. */
PORT_Assert(len > 0 && len < ARCFOUR_STATE_SIZE);
if (len < 0 || len >= ARCFOUR_STATE_SIZE) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
/* Create space for the context. */
cx = (RC4Context *)PORT_ZAlloc(sizeof(RC4Context));
if (cx == NULL) {
PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
return NULL;
}
/* Initialize the state using array indices. */
memcpy(cx->S, Kinit, sizeof cx->S);
/* Fill in K repeatedly with values from key. */
L = K;
for (i = sizeof K; i > len; i-= len) {
memcpy(L, key, len);
L += len;
}
memcpy(L, key, i);
/* Stir the state of the generator. At this point it is assumed
* that the key is the size of the state buffer. If this is not
* the case, the key bytes are repeated to fill the buffer.
*/
j = 0;
#define ARCFOUR_STATE_STIR(ii) \
j = j + cx->S[ii] + K[ii]; \
SWAP(cx->S[ii], cx->S[j]);
for (i=0; i<ARCFOUR_STATE_SIZE; i++) {
ARCFOUR_STATE_STIR(i);
}
cx->i = 0;
cx->j = 0;
return cx;
}
void
RC4_DestroyContext(RC4Context *cx, PRBool freeit)
{
if (freeit)
PORT_ZFree(cx, sizeof(*cx));
}
/*
* Generate the next byte in the stream.
*/
#define ARCFOUR_NEXT_BYTE() \
tmpSi = cx->S[++tmpi]; \
tmpj += tmpSi; \
tmpSj = cx->S[tmpj]; \
cx->S[tmpi] = tmpSj; \
cx->S[tmpj] = tmpSi; \
t = tmpSi + tmpSj;
#ifdef CONVERT_TO_WORDS
/*
* Straight RC4 op. No optimization.
*/
static SECStatus
rc4_no_opt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint8 t;
Stype tmpSi, tmpSj;
register PRUint8 tmpi = cx->i;
register PRUint8 tmpj = cx->j;
unsigned int index;
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
for (index=0; index < inputLen; index++) {
/* Generate next byte from stream. */
ARCFOUR_NEXT_BYTE();
/* output = next stream byte XOR next input byte */
output[index] = cx->S[t] ^ input[index];
}
*outputLen = inputLen;
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
}
#endif
#ifndef CONVERT_TO_WORDS
/*
* Byte-at-a-time RC4, unrolling the loop into 8 pieces.
*/
static SECStatus
rc4_unrolled(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PRUint8 t;
Stype tmpSi, tmpSj;
register PRUint8 tmpi = cx->i;
register PRUint8 tmpj = cx->j;
int index;
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
for (index = inputLen / 8; index-- > 0; input += 8, output += 8) {
ARCFOUR_NEXT_BYTE();
output[0] = cx->S[t] ^ input[0];
ARCFOUR_NEXT_BYTE();
output[1] = cx->S[t] ^ input[1];
ARCFOUR_NEXT_BYTE();
output[2] = cx->S[t] ^ input[2];
ARCFOUR_NEXT_BYTE();
output[3] = cx->S[t] ^ input[3];
ARCFOUR_NEXT_BYTE();
output[4] = cx->S[t] ^ input[4];
ARCFOUR_NEXT_BYTE();
output[5] = cx->S[t] ^ input[5];
ARCFOUR_NEXT_BYTE();
output[6] = cx->S[t] ^ input[6];
ARCFOUR_NEXT_BYTE();
output[7] = cx->S[t] ^ input[7];
}
index = inputLen % 8;
if (index) {
input += index;
output += index;
switch (index) {
case 7:
ARCFOUR_NEXT_BYTE();
output[-7] = cx->S[t] ^ input[-7]; /* FALLTHRU */
case 6:
ARCFOUR_NEXT_BYTE();
output[-6] = cx->S[t] ^ input[-6]; /* FALLTHRU */
case 5:
ARCFOUR_NEXT_BYTE();
output[-5] = cx->S[t] ^ input[-5]; /* FALLTHRU */
case 4:
ARCFOUR_NEXT_BYTE();
output[-4] = cx->S[t] ^ input[-4]; /* FALLTHRU */
case 3:
ARCFOUR_NEXT_BYTE();
output[-3] = cx->S[t] ^ input[-3]; /* FALLTHRU */
case 2:
ARCFOUR_NEXT_BYTE();
output[-2] = cx->S[t] ^ input[-2]; /* FALLTHRU */
case 1:
ARCFOUR_NEXT_BYTE();
output[-1] = cx->S[t] ^ input[-1]; /* FALLTHRU */
default:
/* FALLTHRU */
; /* hp-ux build breaks without this */
}
}
cx->i = tmpi;
cx->j = tmpj;
*outputLen = inputLen;
return SECSuccess;
}
#endif
#ifdef IS_LITTLE_ENDIAN
#define ARCFOUR_NEXT4BYTES_L(n) \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n ); \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 8); \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24);
#else
#define ARCFOUR_NEXT4BYTES_B(n) \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 24); \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 16); \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n + 8); \
ARCFOUR_NEXT_BYTE(); streamWord |= (WORD)cx->S[t] << (n );
#endif
#if (defined(NSS_USE_HYBRID) && !defined(SOLARIS)) || defined(NSS_USE_64)
/* 64-bit wordsize */
#ifdef IS_LITTLE_ENDIAN
#define ARCFOUR_NEXT_WORD() \
{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); ARCFOUR_NEXT4BYTES_L(32); }
#else
#define ARCFOUR_NEXT_WORD() \
{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(32); ARCFOUR_NEXT4BYTES_B(0); }
#endif
#else
/* 32-bit wordsize */
#ifdef IS_LITTLE_ENDIAN
#define ARCFOUR_NEXT_WORD() \
{ streamWord = 0; ARCFOUR_NEXT4BYTES_L(0); }
#else
#define ARCFOUR_NEXT_WORD() \
{ streamWord = 0; ARCFOUR_NEXT4BYTES_B(0); }
#endif
#endif
#ifdef IS_LITTLE_ENDIAN
#define RSH <<
#define LSH >>
#else
#define RSH >>
#define LSH <<
#endif
#ifdef CONVERT_TO_WORDS
/*
* Convert input and output buffers to words before performing
* RC4 operations.
*/
static SECStatus
rc4_wordconv(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
ptrdiff_t inOffset = (ptrdiff_t)input % WORDSIZE;
ptrdiff_t outOffset = (ptrdiff_t)output % WORDSIZE;
register WORD streamWord, mask;
register WORD *pInWord, *pOutWord;
register WORD inWord, nextInWord;
PRUint8 t;
register Stype tmpSi, tmpSj;
register PRUint8 tmpi = cx->i;
register PRUint8 tmpj = cx->j;
unsigned int byteCount;
unsigned int bufShift, invBufShift;
int i;
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (inputLen < 2*WORDSIZE) {
/* Ignore word conversion, do byte-at-a-time */
return rc4_no_opt(cx, output, outputLen, maxOutputLen, input, inputLen);
}
*outputLen = inputLen;
pInWord = (WORD *)(input - inOffset);
if (inOffset < outOffset) {
bufShift = 8*(outOffset - inOffset);
invBufShift = 8*WORDSIZE - bufShift;
} else {
invBufShift = 8*(inOffset - outOffset);
bufShift = 8*WORDSIZE - invBufShift;
}
/*****************************************************************/
/* Step 1: */
/* If the first output word is partial, consume the bytes in the */
/* first partial output word by loading one or two words of */
/* input and shifting them accordingly. Otherwise, just load */
/* in the first word of input. At the end of this block, at */
/* least one partial word of input should ALWAYS be loaded. */
/*****************************************************************/
if (outOffset) {
/* Generate input and stream words aligned relative to the
* partial output buffer.
*/
byteCount = WORDSIZE - outOffset;
pOutWord = (WORD *)(output - outOffset);
mask = streamWord = 0;
#ifdef IS_LITTLE_ENDIAN
for (i = WORDSIZE - byteCount; i < WORDSIZE; i++) {
#else
for (i = byteCount - 1; i >= 0; --i) {
#endif
ARCFOUR_NEXT_BYTE();
streamWord |= (WORD)(cx->S[t]) << 8*i;
mask |= MASK1BYTE << 8*i;
} /* } */
inWord = *pInWord++;
/* If buffers are relatively misaligned, shift the bytes in inWord
* to be aligned to the output buffer.
*/
nextInWord = 0;
if (inOffset < outOffset) {
/* Have more bytes than needed, shift remainder into nextInWord */
nextInWord = inWord LSH 8*(inOffset + byteCount);
inWord = inWord RSH bufShift;
} else if (inOffset > outOffset) {
/* Didn't get enough bytes from current input word, load another
* word and then shift remainder into nextInWord.
*/
nextInWord = *pInWord++;
inWord = (inWord LSH invBufShift) |
(nextInWord RSH bufShift);
nextInWord = nextInWord LSH invBufShift;
}
/* Store output of first partial word */
*pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
/* Consumed byteCount bytes of input */
inputLen -= byteCount;
/* move to next word of output */
pOutWord++;
/* inWord has been consumed, but there may be bytes in nextInWord */
inWord = nextInWord;
} else {
/* output is word-aligned */
pOutWord = (WORD *)output;
if (inOffset) {
/* Input is not word-aligned. The first word load of input
* will not produce a full word of input bytes, so one word
* must be pre-loaded. The main loop below will load in the
* next input word and shift some of its bytes into inWord
* in order to create a full input word. Note that the main
* loop must execute at least once because the input must
* be at least two words.
*/
inWord = *pInWord++;
inWord = inWord LSH invBufShift;
} else {
/* Input is word-aligned. The first word load of input
* will produce a full word of input bytes, so nothing
* needs to be loaded here.
*/
inWord = 0;
}
}
/* Output buffer is aligned, inOffset is now measured relative to
* outOffset (and not a word boundary).
*/
inOffset = (inOffset + WORDSIZE - outOffset) % WORDSIZE;
/*****************************************************************/
/* Step 2: main loop */
/* At this point the output buffer is word-aligned. Any unused */
/* bytes from above will be in inWord (shifted correctly). If */
/* the input buffer is unaligned relative to the output buffer, */
/* shifting has to be done. */
/*****************************************************************/
if (inOffset) {
for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
nextInWord = *pInWord++;
inWord |= nextInWord RSH bufShift;
nextInWord = nextInWord LSH invBufShift;
ARCFOUR_NEXT_WORD();
*pOutWord++ = inWord ^ streamWord;
inWord = nextInWord;
}
if (inputLen == 0) {
/* Nothing left to do. */
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
}
/* If the amount of remaining input is greater than the amount
* bytes pulled from the current input word, need to do another
* word load. What's left in inWord will be consumed in step 3.
*/
if (inputLen > WORDSIZE - inOffset)
inWord |= *pInWord RSH bufShift;
} else {
for (; inputLen >= WORDSIZE; inputLen -= WORDSIZE) {
inWord = *pInWord++;
ARCFOUR_NEXT_WORD();
*pOutWord++ = inWord ^ streamWord;
}
if (inputLen == 0) {
/* Nothing left to do. */
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
} else {
/* A partial input word remains at the tail. Load it. The
* relevant bytes will be consumed in step 3.
*/
inWord = *pInWord;
}
}
/*****************************************************************/
/* Step 3: */
/* A partial word of input remains, and it is already loaded */
/* into nextInWord. Shift appropriately and consume the bytes */
/* used in the partial word. */
/*****************************************************************/
mask = streamWord = 0;
#ifdef IS_LITTLE_ENDIAN
for (i = 0; i < inputLen; ++i) {
#else
for (i = WORDSIZE - 1; i >= WORDSIZE - inputLen; --i) {
#endif
ARCFOUR_NEXT_BYTE();
streamWord |= (WORD)(cx->S[t]) << 8*i;
mask |= MASK1BYTE << 8*i;
} /* } */
*pOutWord = (*pOutWord & ~mask) | ((inWord ^ streamWord) & mask);
cx->i = tmpi;
cx->j = tmpj;
return SECSuccess;
}
#endif
SECStatus
RC4_Encrypt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
#ifdef CONVERT_TO_WORDS
/* Convert the byte-stream to a word-stream */
return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
#else
/* Operate on bytes, but unroll the main loop */
return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
#endif
}
SECStatus RC4_Decrypt(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PORT_Assert(maxOutputLen >= inputLen);
if (maxOutputLen < inputLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* decrypt and encrypt are same operation. */
#ifdef CONVERT_TO_WORDS
/* Convert the byte-stream to a word-stream */
return rc4_wordconv(cx, output, outputLen, maxOutputLen, input, inputLen);
#else
/* Operate on bytes, but unroll the main loop */
return rc4_unrolled(cx, output, outputLen, maxOutputLen, input, inputLen);
#endif
}
#undef CONVERT_TO_WORDS
#undef USE_LONG

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,336 +0,0 @@
/*
* blapit.h - public data structures for the crypto library
*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: blapit.h,v 1.10 2003-03-29 00:18:18 nelsonb%netscape.com Exp $
*/
#ifndef _BLAPIT_H_
#define _BLAPIT_H_
#include "seccomon.h"
#include "prlink.h"
#include "plarena.h"
/* RC2 operation modes */
#define NSS_RC2 0
#define NSS_RC2_CBC 1
/* RC5 operation modes */
#define NSS_RC5 0
#define NSS_RC5_CBC 1
/* DES operation modes */
#define NSS_DES 0
#define NSS_DES_CBC 1
#define NSS_DES_EDE3 2
#define NSS_DES_EDE3_CBC 3
#define DES_KEY_LENGTH 8 /* Bytes */
/* AES operation modes */
#define NSS_AES 0
#define NSS_AES_CBC 1
#define DSA_SIGNATURE_LEN 40 /* Bytes */
#define DSA_SUBPRIME_LEN 20 /* Bytes */
/* XXX We shouldn't have to hard code this limit. For
* now, this is the quickest way to support ECDSA signature
* processing (ECDSA signature lengths depend on curve
* size). This limit is sufficient for curves upto
* 576 bits.
*/
#define MAX_ECKEY_LEN 72 /* Bytes */
/*
* Number of bytes each hash algorithm produces
*/
#define MD2_LENGTH 16 /* Bytes */
#define MD5_LENGTH 16 /* Bytes */
#define SHA1_LENGTH 20 /* Bytes */
#define SHA256_LENGTH 32 /* bytes */
#define SHA384_LENGTH 48 /* bytes */
#define SHA512_LENGTH 64 /* bytes */
#define HASH_LENGTH_MAX SHA512_LENGTH
/*
* Input block size for each hash algorithm.
*/
#define SHA256_BLOCK_LENGTH 64 /* bytes */
#define SHA384_BLOCK_LENGTH 128 /* bytes */
#define SHA512_BLOCK_LENGTH 128 /* bytes */
#define AES_KEY_WRAP_IV_BYTES 8
#define AES_KEY_WRAP_BLOCK_SIZE 8 /* bytes */
#define AES_BLOCK_SIZE 16 /* bytes */
#define NSS_FREEBL_DEFAULT_CHUNKSIZE 2048
/*
* The FIPS 186 algorithm for generating primes P and Q allows only 9
* distinct values for the length of P, and only one value for the
* length of Q.
* The algorithm uses a variable j to indicate which of the 9 lengths
* of P is to be used.
* The following table relates j to the lengths of P and Q in bits.
*
* j bits in P bits in Q
* _ _________ _________
* 0 512 160
* 1 576 160
* 2 640 160
* 3 704 160
* 4 768 160
* 5 832 160
* 6 896 160
* 7 960 160
* 8 1024 160
*
* The FIPS-186 compliant PQG generator takes j as an input parameter.
*/
#define DSA_Q_BITS 160
#define DSA_MAX_P_BITS 1024
#define DSA_MIN_P_BITS 512
/*
* function takes desired number of bits in P,
* returns index (0..8) or -1 if number of bits is invalid.
*/
#define PQG_PBITS_TO_INDEX(bits) ((((bits)-512) % 64) ? -1 : (int)((bits)-512)/64)
/*
* function takes index (0-8)
* returns number of bits in P for that index, or -1 if index is invalid.
*/
#define PQG_INDEX_TO_PBITS(j) (((unsigned)(j) > 8) ? -1 : (512 + 64 * (j)))
/***************************************************************************
** Opaque objects
*/
struct DESContextStr ;
struct RC2ContextStr ;
struct RC4ContextStr ;
struct RC5ContextStr ;
struct AESContextStr ;
struct MD2ContextStr ;
struct MD5ContextStr ;
struct SHA1ContextStr ;
struct SHA256ContextStr ;
struct SHA512ContextStr ;
struct AESKeyWrapContextStr ;
typedef struct DESContextStr DESContext;
typedef struct RC2ContextStr RC2Context;
typedef struct RC4ContextStr RC4Context;
typedef struct RC5ContextStr RC5Context;
typedef struct AESContextStr AESContext;
typedef struct MD2ContextStr MD2Context;
typedef struct MD5ContextStr MD5Context;
typedef struct SHA1ContextStr SHA1Context;
typedef struct SHA256ContextStr SHA256Context;
typedef struct SHA512ContextStr SHA512Context;
/* SHA384Context is really a SHA512ContextStr. This is not a mistake. */
typedef struct SHA512ContextStr SHA384Context;
typedef struct AESKeyWrapContextStr AESKeyWrapContext;
/***************************************************************************
** RSA Public and Private Key structures
*/
/* member names from PKCS#1, section 7.1 */
struct RSAPublicKeyStr {
PRArenaPool * arena;
SECItem modulus;
SECItem publicExponent;
};
typedef struct RSAPublicKeyStr RSAPublicKey;
/* member names from PKCS#1, section 7.2 */
struct RSAPrivateKeyStr {
PRArenaPool * arena;
SECItem version;
SECItem modulus;
SECItem publicExponent;
SECItem privateExponent;
SECItem prime1;
SECItem prime2;
SECItem exponent1;
SECItem exponent2;
SECItem coefficient;
};
typedef struct RSAPrivateKeyStr RSAPrivateKey;
/***************************************************************************
** DSA Public and Private Key and related structures
*/
struct PQGParamsStr {
PRArenaPool *arena;
SECItem prime; /* p */
SECItem subPrime; /* q */
SECItem base; /* g */
/* XXX chrisk: this needs to be expanded to hold j and validationParms (RFC2459 7.3.2) */
};
typedef struct PQGParamsStr PQGParams;
struct PQGVerifyStr {
PRArenaPool * arena; /* includes this struct, seed, & h. */
unsigned int counter;
SECItem seed;
SECItem h;
};
typedef struct PQGVerifyStr PQGVerify;
struct DSAPublicKeyStr {
PQGParams params;
SECItem publicValue;
};
typedef struct DSAPublicKeyStr DSAPublicKey;
struct DSAPrivateKeyStr {
PQGParams params;
SECItem publicValue;
SECItem privateValue;
};
typedef struct DSAPrivateKeyStr DSAPrivateKey;
/***************************************************************************
** Diffie-Hellman Public and Private Key and related structures
** Structure member names suggested by PKCS#3.
*/
struct DHParamsStr {
PRArenaPool * arena;
SECItem prime; /* p */
SECItem base; /* g */
};
typedef struct DHParamsStr DHParams;
struct DHPublicKeyStr {
PRArenaPool * arena;
SECItem prime;
SECItem base;
SECItem publicValue;
};
typedef struct DHPublicKeyStr DHPublicKey;
struct DHPrivateKeyStr {
PRArenaPool * arena;
SECItem prime;
SECItem base;
SECItem publicValue;
SECItem privateValue;
};
typedef struct DHPrivateKeyStr DHPrivateKey;
/***************************************************************************
** Data structures used for elliptic curve parameters and
** public and private keys.
*/
/*
** The ECParams data structures can encode elliptic curve
** parameters for both GFp and GF2m curves.
*/
typedef enum { ec_params_explicit,
ec_params_named
} ECParamsType;
typedef enum { ec_field_GFp = 1,
ec_field_GF2m
} ECFieldType;
struct ECFieldIDStr {
int size; /* field size in bits */
ECFieldType type;
union {
SECItem prime; /* prime p for (GFp) */
SECItem poly; /* irreducible binary polynomial for (GF2m) */
} u;
int k1; /* first coefficient of pentanomial or
* the only coefficient of trinomial
*/
int k2; /* two remaining coefficients of pentanomial */
int k3;
};
typedef struct ECFieldIDStr ECFieldID;
struct ECCurveStr {
SECItem a; /* contains octet stream encoding of
* field element (X9.62 section 4.3.3)
*/
SECItem b;
SECItem seed;
};
typedef struct ECCurveStr ECCurve;
struct ECParamsStr {
PRArenaPool * arena;
ECParamsType type;
ECFieldID fieldID;
ECCurve curve;
SECItem base;
SECItem order;
int cofactor;
SECItem DEREncoding;
};
typedef struct ECParamsStr ECParams;
struct ECPublicKeyStr {
ECParams ecParams;
SECItem publicValue; /* elliptic curve point encoded as
* octet stream.
*/
};
typedef struct ECPublicKeyStr ECPublicKey;
struct ECPrivateKeyStr {
ECParams ecParams;
SECItem publicValue; /* encoded ec point */
SECItem privateValue; /* private big integer */
};
typedef struct ECPrivateKeyStr ECPrivateKey;
#endif /* _BLAPIT_H_ */

View File

@@ -1,103 +0,0 @@
#
# 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 the Netscape security libraries.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU General Public License Version 2 or later (the
# "GPL"), in which case the provisions of the GPL are applicable
# instead of those above. If you wish to allow use of your
# version of this file only under the terms of the GPL and not to
# allow others to use your version of this file under the MPL,
# indicate your decision by deleting the provisions above and
# replace them with the notice and other provisions required by
# the GPL. If you do not delete the provisions above, a recipient
# may use your version of this file under either the MPL or the
# GPL.
#
# only do this in the outermost freebl build.
ifndef FREEBL_RECURSIVE_BUILD
# we only do this stuff for some of the 32-bit builds, no 64-bit builds
ifndef USE_64
ifeq ($(OS_TARGET), HP-UX)
ifneq ($(OS_TEST), ia64)
FREEBL_EXTENDED_BUILD = 1
endif
endif
ifeq ($(OS_TARGET),SunOS)
ifeq ($(CPU_ARCH),sparc)
FREEBL_EXTENDED_BUILD = 1
endif
endif
ifdef FREEBL_EXTENDED_BUILD
# We're going to change this build so that it builds libfreebl.a with
# just loader.c. Then we have to build this directory twice again to
# build the two DSOs.
# To build libfreebl.a with just loader.c, we must now override many
# of the make variables setup by the prior inclusion of CORECONF's config.mk
CSRCS = loader.c sysrand.c
SIMPLE_OBJS = $(CSRCS:.c=$(OBJ_SUFFIX))
OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(SIMPLE_OBJS))
ALL_TRASH := $(TARGETS) $(OBJS) $(OBJDIR) LOGS TAGS $(GARBAGE) \
$(NOSUCHFILE) so_locations
endif
#end of 32-bit only stuff.
endif
# Override the values defined in coreconf's ruleset.mk.
#
# - (1) LIBRARY: a static (archival) library
# - (2) SHARED_LIBRARY: a shared (dynamic link) library
# - (3) IMPORT_LIBRARY: an import library, used only on Windows
# - (4) PROGRAM: an executable binary
#
# override these variables to prevent building a DSO/DLL.
TARGETS = $(LIBRARY)
SHARED_LIBRARY =
IMPORT_LIBRARY =
PROGRAM =
else
# This is a recursive build.
TARGETS = $(SHARED_LIBRARY)
LIBRARY =
PROGRAM =
#ifeq ($(OS_TARGET), HP-UX)
EXTRA_LIBS += \
$(DIST)/lib/libsecutil.$(LIB_SUFFIX) \
$(NULL)
# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
EXTRA_SHARED_LIBS += \
-L$(DIST)/lib/ \
-lplc4 \
-lplds4 \
-lnspr4 \
-lc
#endif
endif

View File

@@ -1,683 +0,0 @@
/*
* des.c
*
* core source file for DES-150 library
* Make key schedule from DES key.
* Encrypt/Decrypt one 8-byte block.
*
* 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 the DES-150 library.
*
* The Initial Developer of the Original Code is Nelson B. Bolyard,
* nelsonb@iname.com. Portions created by Nelson B. Bolyard are
* Copyright (C) 1990, 2000 Nelson B. Bolyard, All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the GPL.
*/
#include "des.h"
#include <stddef.h> /* for ptrdiff_t */
/* #define USE_INDEXING 1 */
/*
* The tables below are the 8 sbox functions, with the 6-bit input permutation
* and the 32-bit output permutation pre-computed.
* They are shifted circularly to the left 3 bits, which removes 2 shifts
* and an or from each round by reducing the number of sboxes whose
* indices cross word broundaries from 2 to 1.
*/
static const HALF SP[8][64] = {
/* Box S1 */ {
0x04041000, 0x00000000, 0x00040000, 0x04041010,
0x04040010, 0x00041010, 0x00000010, 0x00040000,
0x00001000, 0x04041000, 0x04041010, 0x00001000,
0x04001010, 0x04040010, 0x04000000, 0x00000010,
0x00001010, 0x04001000, 0x04001000, 0x00041000,
0x00041000, 0x04040000, 0x04040000, 0x04001010,
0x00040010, 0x04000010, 0x04000010, 0x00040010,
0x00000000, 0x00001010, 0x00041010, 0x04000000,
0x00040000, 0x04041010, 0x00000010, 0x04040000,
0x04041000, 0x04000000, 0x04000000, 0x00001000,
0x04040010, 0x00040000, 0x00041000, 0x04000010,
0x00001000, 0x00000010, 0x04001010, 0x00041010,
0x04041010, 0x00040010, 0x04040000, 0x04001010,
0x04000010, 0x00001010, 0x00041010, 0x04041000,
0x00001010, 0x04001000, 0x04001000, 0x00000000,
0x00040010, 0x00041000, 0x00000000, 0x04040010
},
/* Box S2 */ {
0x00420082, 0x00020002, 0x00020000, 0x00420080,
0x00400000, 0x00000080, 0x00400082, 0x00020082,
0x00000082, 0x00420082, 0x00420002, 0x00000002,
0x00020002, 0x00400000, 0x00000080, 0x00400082,
0x00420000, 0x00400080, 0x00020082, 0x00000000,
0x00000002, 0x00020000, 0x00420080, 0x00400002,
0x00400080, 0x00000082, 0x00000000, 0x00420000,
0x00020080, 0x00420002, 0x00400002, 0x00020080,
0x00000000, 0x00420080, 0x00400082, 0x00400000,
0x00020082, 0x00400002, 0x00420002, 0x00020000,
0x00400002, 0x00020002, 0x00000080, 0x00420082,
0x00420080, 0x00000080, 0x00020000, 0x00000002,
0x00020080, 0x00420002, 0x00400000, 0x00000082,
0x00400080, 0x00020082, 0x00000082, 0x00400080,
0x00420000, 0x00000000, 0x00020002, 0x00020080,
0x00000002, 0x00400082, 0x00420082, 0x00420000
},
/* Box S3 */ {
0x00000820, 0x20080800, 0x00000000, 0x20080020,
0x20000800, 0x00000000, 0x00080820, 0x20000800,
0x00080020, 0x20000020, 0x20000020, 0x00080000,
0x20080820, 0x00080020, 0x20080000, 0x00000820,
0x20000000, 0x00000020, 0x20080800, 0x00000800,
0x00080800, 0x20080000, 0x20080020, 0x00080820,
0x20000820, 0x00080800, 0x00080000, 0x20000820,
0x00000020, 0x20080820, 0x00000800, 0x20000000,
0x20080800, 0x20000000, 0x00080020, 0x00000820,
0x00080000, 0x20080800, 0x20000800, 0x00000000,
0x00000800, 0x00080020, 0x20080820, 0x20000800,
0x20000020, 0x00000800, 0x00000000, 0x20080020,
0x20000820, 0x00080000, 0x20000000, 0x20080820,
0x00000020, 0x00080820, 0x00080800, 0x20000020,
0x20080000, 0x20000820, 0x00000820, 0x20080000,
0x00080820, 0x00000020, 0x20080020, 0x00080800
},
/* Box S4 */ {
0x02008004, 0x00008204, 0x00008204, 0x00000200,
0x02008200, 0x02000204, 0x02000004, 0x00008004,
0x00000000, 0x02008000, 0x02008000, 0x02008204,
0x00000204, 0x00000000, 0x02000200, 0x02000004,
0x00000004, 0x00008000, 0x02000000, 0x02008004,
0x00000200, 0x02000000, 0x00008004, 0x00008200,
0x02000204, 0x00000004, 0x00008200, 0x02000200,
0x00008000, 0x02008200, 0x02008204, 0x00000204,
0x02000200, 0x02000004, 0x02008000, 0x02008204,
0x00000204, 0x00000000, 0x00000000, 0x02008000,
0x00008200, 0x02000200, 0x02000204, 0x00000004,
0x02008004, 0x00008204, 0x00008204, 0x00000200,
0x02008204, 0x00000204, 0x00000004, 0x00008000,
0x02000004, 0x00008004, 0x02008200, 0x02000204,
0x00008004, 0x00008200, 0x02000000, 0x02008004,
0x00000200, 0x02000000, 0x00008000, 0x02008200
},
/* Box S5 */ {
0x00000400, 0x08200400, 0x08200000, 0x08000401,
0x00200000, 0x00000400, 0x00000001, 0x08200000,
0x00200401, 0x00200000, 0x08000400, 0x00200401,
0x08000401, 0x08200001, 0x00200400, 0x00000001,
0x08000000, 0x00200001, 0x00200001, 0x00000000,
0x00000401, 0x08200401, 0x08200401, 0x08000400,
0x08200001, 0x00000401, 0x00000000, 0x08000001,
0x08200400, 0x08000000, 0x08000001, 0x00200400,
0x00200000, 0x08000401, 0x00000400, 0x08000000,
0x00000001, 0x08200000, 0x08000401, 0x00200401,
0x08000400, 0x00000001, 0x08200001, 0x08200400,
0x00200401, 0x00000400, 0x08000000, 0x08200001,
0x08200401, 0x00200400, 0x08000001, 0x08200401,
0x08200000, 0x00000000, 0x00200001, 0x08000001,
0x00200400, 0x08000400, 0x00000401, 0x00200000,
0x00000000, 0x00200001, 0x08200400, 0x00000401
},
/* Box S6 */ {
0x80000040, 0x81000000, 0x00010000, 0x81010040,
0x81000000, 0x00000040, 0x81010040, 0x01000000,
0x80010000, 0x01010040, 0x01000000, 0x80000040,
0x01000040, 0x80010000, 0x80000000, 0x00010040,
0x00000000, 0x01000040, 0x80010040, 0x00010000,
0x01010000, 0x80010040, 0x00000040, 0x81000040,
0x81000040, 0x00000000, 0x01010040, 0x81010000,
0x00010040, 0x01010000, 0x81010000, 0x80000000,
0x80010000, 0x00000040, 0x81000040, 0x01010000,
0x81010040, 0x01000000, 0x00010040, 0x80000040,
0x01000000, 0x80010000, 0x80000000, 0x00010040,
0x80000040, 0x81010040, 0x01010000, 0x81000000,
0x01010040, 0x81010000, 0x00000000, 0x81000040,
0x00000040, 0x00010000, 0x81000000, 0x01010040,
0x00010000, 0x01000040, 0x80010040, 0x00000000,
0x81010000, 0x80000000, 0x01000040, 0x80010040
},
/* Box S7 */ {
0x00800000, 0x10800008, 0x10002008, 0x00000000,
0x00002000, 0x10002008, 0x00802008, 0x10802000,
0x10802008, 0x00800000, 0x00000000, 0x10000008,
0x00000008, 0x10000000, 0x10800008, 0x00002008,
0x10002000, 0x00802008, 0x00800008, 0x10002000,
0x10000008, 0x10800000, 0x10802000, 0x00800008,
0x10800000, 0x00002000, 0x00002008, 0x10802008,
0x00802000, 0x00000008, 0x10000000, 0x00802000,
0x10000000, 0x00802000, 0x00800000, 0x10002008,
0x10002008, 0x10800008, 0x10800008, 0x00000008,
0x00800008, 0x10000000, 0x10002000, 0x00800000,
0x10802000, 0x00002008, 0x00802008, 0x10802000,
0x00002008, 0x10000008, 0x10802008, 0x10800000,
0x00802000, 0x00000000, 0x00000008, 0x10802008,
0x00000000, 0x00802008, 0x10800000, 0x00002000,
0x10000008, 0x10002000, 0x00002000, 0x00800008
},
/* Box S8 */ {
0x40004100, 0x00004000, 0x00100000, 0x40104100,
0x40000000, 0x40004100, 0x00000100, 0x40000000,
0x00100100, 0x40100000, 0x40104100, 0x00104000,
0x40104000, 0x00104100, 0x00004000, 0x00000100,
0x40100000, 0x40000100, 0x40004000, 0x00004100,
0x00104000, 0x00100100, 0x40100100, 0x40104000,
0x00004100, 0x00000000, 0x00000000, 0x40100100,
0x40000100, 0x40004000, 0x00104100, 0x00100000,
0x00104100, 0x00100000, 0x40104000, 0x00004000,
0x00000100, 0x40100100, 0x00004000, 0x00104100,
0x40004000, 0x00000100, 0x40000100, 0x40100000,
0x40100100, 0x40000000, 0x00100000, 0x40004100,
0x00000000, 0x40104100, 0x00100100, 0x40000100,
0x40100000, 0x40004000, 0x40004100, 0x00000000,
0x40104100, 0x00104000, 0x00104000, 0x00004100,
0x00004100, 0x00100100, 0x40000000, 0x40104000
}
};
static const HALF PC2[8][64] = {
/* table 0 */ {
0x00000000, 0x00001000, 0x04000000, 0x04001000,
0x00100000, 0x00101000, 0x04100000, 0x04101000,
0x00008000, 0x00009000, 0x04008000, 0x04009000,
0x00108000, 0x00109000, 0x04108000, 0x04109000,
0x00000004, 0x00001004, 0x04000004, 0x04001004,
0x00100004, 0x00101004, 0x04100004, 0x04101004,
0x00008004, 0x00009004, 0x04008004, 0x04009004,
0x00108004, 0x00109004, 0x04108004, 0x04109004,
0x08000000, 0x08001000, 0x0c000000, 0x0c001000,
0x08100000, 0x08101000, 0x0c100000, 0x0c101000,
0x08008000, 0x08009000, 0x0c008000, 0x0c009000,
0x08108000, 0x08109000, 0x0c108000, 0x0c109000,
0x08000004, 0x08001004, 0x0c000004, 0x0c001004,
0x08100004, 0x08101004, 0x0c100004, 0x0c101004,
0x08008004, 0x08009004, 0x0c008004, 0x0c009004,
0x08108004, 0x08109004, 0x0c108004, 0x0c109004
},
/* table 1 */ {
0x00000000, 0x00002000, 0x80000000, 0x80002000,
0x00000008, 0x00002008, 0x80000008, 0x80002008,
0x00200000, 0x00202000, 0x80200000, 0x80202000,
0x00200008, 0x00202008, 0x80200008, 0x80202008,
0x20000000, 0x20002000, 0xa0000000, 0xa0002000,
0x20000008, 0x20002008, 0xa0000008, 0xa0002008,
0x20200000, 0x20202000, 0xa0200000, 0xa0202000,
0x20200008, 0x20202008, 0xa0200008, 0xa0202008,
0x00000400, 0x00002400, 0x80000400, 0x80002400,
0x00000408, 0x00002408, 0x80000408, 0x80002408,
0x00200400, 0x00202400, 0x80200400, 0x80202400,
0x00200408, 0x00202408, 0x80200408, 0x80202408,
0x20000400, 0x20002400, 0xa0000400, 0xa0002400,
0x20000408, 0x20002408, 0xa0000408, 0xa0002408,
0x20200400, 0x20202400, 0xa0200400, 0xa0202400,
0x20200408, 0x20202408, 0xa0200408, 0xa0202408
},
/* table 2 */ {
0x00000000, 0x00004000, 0x00000020, 0x00004020,
0x00080000, 0x00084000, 0x00080020, 0x00084020,
0x00000800, 0x00004800, 0x00000820, 0x00004820,
0x00080800, 0x00084800, 0x00080820, 0x00084820,
0x00000010, 0x00004010, 0x00000030, 0x00004030,
0x00080010, 0x00084010, 0x00080030, 0x00084030,
0x00000810, 0x00004810, 0x00000830, 0x00004830,
0x00080810, 0x00084810, 0x00080830, 0x00084830,
0x00400000, 0x00404000, 0x00400020, 0x00404020,
0x00480000, 0x00484000, 0x00480020, 0x00484020,
0x00400800, 0x00404800, 0x00400820, 0x00404820,
0x00480800, 0x00484800, 0x00480820, 0x00484820,
0x00400010, 0x00404010, 0x00400030, 0x00404030,
0x00480010, 0x00484010, 0x00480030, 0x00484030,
0x00400810, 0x00404810, 0x00400830, 0x00404830,
0x00480810, 0x00484810, 0x00480830, 0x00484830
},
/* table 3 */ {
0x00000000, 0x40000000, 0x00000080, 0x40000080,
0x00040000, 0x40040000, 0x00040080, 0x40040080,
0x00000040, 0x40000040, 0x000000c0, 0x400000c0,
0x00040040, 0x40040040, 0x000400c0, 0x400400c0,
0x10000000, 0x50000000, 0x10000080, 0x50000080,
0x10040000, 0x50040000, 0x10040080, 0x50040080,
0x10000040, 0x50000040, 0x100000c0, 0x500000c0,
0x10040040, 0x50040040, 0x100400c0, 0x500400c0,
0x00800000, 0x40800000, 0x00800080, 0x40800080,
0x00840000, 0x40840000, 0x00840080, 0x40840080,
0x00800040, 0x40800040, 0x008000c0, 0x408000c0,
0x00840040, 0x40840040, 0x008400c0, 0x408400c0,
0x10800000, 0x50800000, 0x10800080, 0x50800080,
0x10840000, 0x50840000, 0x10840080, 0x50840080,
0x10800040, 0x50800040, 0x108000c0, 0x508000c0,
0x10840040, 0x50840040, 0x108400c0, 0x508400c0
},
/* table 4 */ {
0x00000000, 0x00000008, 0x08000000, 0x08000008,
0x00040000, 0x00040008, 0x08040000, 0x08040008,
0x00002000, 0x00002008, 0x08002000, 0x08002008,
0x00042000, 0x00042008, 0x08042000, 0x08042008,
0x80000000, 0x80000008, 0x88000000, 0x88000008,
0x80040000, 0x80040008, 0x88040000, 0x88040008,
0x80002000, 0x80002008, 0x88002000, 0x88002008,
0x80042000, 0x80042008, 0x88042000, 0x88042008,
0x00080000, 0x00080008, 0x08080000, 0x08080008,
0x000c0000, 0x000c0008, 0x080c0000, 0x080c0008,
0x00082000, 0x00082008, 0x08082000, 0x08082008,
0x000c2000, 0x000c2008, 0x080c2000, 0x080c2008,
0x80080000, 0x80080008, 0x88080000, 0x88080008,
0x800c0000, 0x800c0008, 0x880c0000, 0x880c0008,
0x80082000, 0x80082008, 0x88082000, 0x88082008,
0x800c2000, 0x800c2008, 0x880c2000, 0x880c2008
},
/* table 5 */ {
0x00000000, 0x00400000, 0x00008000, 0x00408000,
0x40000000, 0x40400000, 0x40008000, 0x40408000,
0x00000020, 0x00400020, 0x00008020, 0x00408020,
0x40000020, 0x40400020, 0x40008020, 0x40408020,
0x00001000, 0x00401000, 0x00009000, 0x00409000,
0x40001000, 0x40401000, 0x40009000, 0x40409000,
0x00001020, 0x00401020, 0x00009020, 0x00409020,
0x40001020, 0x40401020, 0x40009020, 0x40409020,
0x00100000, 0x00500000, 0x00108000, 0x00508000,
0x40100000, 0x40500000, 0x40108000, 0x40508000,
0x00100020, 0x00500020, 0x00108020, 0x00508020,
0x40100020, 0x40500020, 0x40108020, 0x40508020,
0x00101000, 0x00501000, 0x00109000, 0x00509000,
0x40101000, 0x40501000, 0x40109000, 0x40509000,
0x00101020, 0x00501020, 0x00109020, 0x00509020,
0x40101020, 0x40501020, 0x40109020, 0x40509020
},
/* table 6 */ {
0x00000000, 0x00000040, 0x04000000, 0x04000040,
0x00000800, 0x00000840, 0x04000800, 0x04000840,
0x00800000, 0x00800040, 0x04800000, 0x04800040,
0x00800800, 0x00800840, 0x04800800, 0x04800840,
0x10000000, 0x10000040, 0x14000000, 0x14000040,
0x10000800, 0x10000840, 0x14000800, 0x14000840,
0x10800000, 0x10800040, 0x14800000, 0x14800040,
0x10800800, 0x10800840, 0x14800800, 0x14800840,
0x00000080, 0x000000c0, 0x04000080, 0x040000c0,
0x00000880, 0x000008c0, 0x04000880, 0x040008c0,
0x00800080, 0x008000c0, 0x04800080, 0x048000c0,
0x00800880, 0x008008c0, 0x04800880, 0x048008c0,
0x10000080, 0x100000c0, 0x14000080, 0x140000c0,
0x10000880, 0x100008c0, 0x14000880, 0x140008c0,
0x10800080, 0x108000c0, 0x14800080, 0x148000c0,
0x10800880, 0x108008c0, 0x14800880, 0x148008c0
},
/* table 7 */ {
0x00000000, 0x00000010, 0x00000400, 0x00000410,
0x00000004, 0x00000014, 0x00000404, 0x00000414,
0x00004000, 0x00004010, 0x00004400, 0x00004410,
0x00004004, 0x00004014, 0x00004404, 0x00004414,
0x20000000, 0x20000010, 0x20000400, 0x20000410,
0x20000004, 0x20000014, 0x20000404, 0x20000414,
0x20004000, 0x20004010, 0x20004400, 0x20004410,
0x20004004, 0x20004014, 0x20004404, 0x20004414,
0x00200000, 0x00200010, 0x00200400, 0x00200410,
0x00200004, 0x00200014, 0x00200404, 0x00200414,
0x00204000, 0x00204010, 0x00204400, 0x00204410,
0x00204004, 0x00204014, 0x00204404, 0x00204414,
0x20200000, 0x20200010, 0x20200400, 0x20200410,
0x20200004, 0x20200014, 0x20200404, 0x20200414,
0x20204000, 0x20204010, 0x20204400, 0x20204410,
0x20204004, 0x20204014, 0x20204404, 0x20204414
}
};
/*
* The PC-1 Permutation
* If we number the bits of the 8 bytes of key input like this (in octal):
* 00 01 02 03 04 05 06 07
* 10 11 12 13 14 15 16 17
* 20 21 22 23 24 25 26 27
* 30 31 32 33 34 35 36 37
* 40 41 42 43 44 45 46 47
* 50 51 52 53 54 55 56 57
* 60 61 62 63 64 65 66 67
* 70 71 72 73 74 75 76 77
* then after the PC-1 permutation,
* C0 is
* 70 60 50 40 30 20 10 00
* 71 61 51 41 31 21 11 01
* 72 62 52 42 32 22 12 02
* 73 63 53 43
* D0 is
* 76 66 56 46 36 26 16 06
* 75 65 55 45 35 25 15 05
* 74 64 54 44 34 24 14 04
* 33 23 13 03
* and these parity bits have been discarded:
* 77 67 57 47 37 27 17 07
*
* We achieve this by flipping the input matrix about the diagonal from 70-07,
* getting left =
* 77 67 57 47 37 27 17 07 (these are the parity bits)
* 76 66 56 46 36 26 16 06
* 75 65 55 45 35 25 15 05
* 74 64 54 44 34 24 14 04
* right =
* 73 63 53 43 33 23 13 03
* 72 62 52 42 32 22 12 02
* 71 61 51 41 31 21 11 01
* 70 60 50 40 30 20 10 00
* then byte swap right, ala htonl() on a little endian machine.
* right =
* 70 60 50 40 30 20 10 00
* 71 67 57 47 37 27 11 07
* 72 62 52 42 32 22 12 02
* 73 63 53 43 33 23 13 03
* then
* c0 = right >> 4;
* d0 = ((left & 0x00ffffff) << 4) | (right & 0xf);
*/
#define FLIP_RIGHT_DIAGONAL(word, temp) \
temp = (word ^ (word >> 18)) & 0x00003333; \
word ^= temp | (temp << 18); \
temp = (word ^ (word >> 9)) & 0x00550055; \
word ^= temp | (temp << 9);
#define BYTESWAP(word, temp) \
word = (word >> 16) | (word << 16); \
temp = 0x00ff00ff; \
word = ((word & temp) << 8) | ((word >> 8) & temp);
#define PC1(left, right, c0, d0, temp) \
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
left ^= temp << 4; \
FLIP_RIGHT_DIAGONAL(left, temp); \
FLIP_RIGHT_DIAGONAL(right, temp); \
BYTESWAP(right, temp); \
c0 = right >> 4; \
d0 = ((left & 0x00ffffff) << 4) | (right & 0xf);
#define LEFT_SHIFT_1( reg ) (((reg << 1) | (reg >> 27)) & 0x0FFFFFFF)
#define LEFT_SHIFT_2( reg ) (((reg << 2) | (reg >> 26)) & 0x0FFFFFFF)
/*
* setup key schedules from key
*/
void
DES_MakeSchedule( HALF * ks, const BYTE * key, DESDirection direction)
{
register HALF left, right;
register HALF c0, d0;
register HALF temp;
int delta;
unsigned int ls;
#if defined(_X86_)
left = HALFPTR(key)[0];
right = HALFPTR(key)[1];
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#else
if (((ptrdiff_t)key & 0x03) == 0) {
left = HALFPTR(key)[0];
right = HALFPTR(key)[1];
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
} else {
left = ((HALF)key[0] << 24) | ((HALF)key[1] << 16) |
((HALF)key[2] << 8) | key[3];
right = ((HALF)key[4] << 24) | ((HALF)key[5] << 16) |
((HALF)key[6] << 8) | key[7];
}
#endif
PC1(left, right, c0, d0, temp);
if (direction == DES_ENCRYPT) {
delta = 2 * (int)sizeof(HALF);
} else {
ks += 30;
delta = (-2) * (int)sizeof(HALF);
}
for (ls = 0x8103; ls; ls >>= 1) {
if ( ls & 1 ) {
c0 = LEFT_SHIFT_1( c0 );
d0 = LEFT_SHIFT_1( d0 );
} else {
c0 = LEFT_SHIFT_2( c0 );
d0 = LEFT_SHIFT_2( d0 );
}
#ifdef USE_INDEXING
#define PC2LOOKUP(b,c) PC2[b][c]
left = PC2LOOKUP(0, ((c0 >> 22) & 0x3F) );
left |= PC2LOOKUP(1, ((c0 >> 13) & 0x3F) );
left |= PC2LOOKUP(2, ((c0 >> 4) & 0x38) | (c0 & 0x7) );
left |= PC2LOOKUP(3, ((c0>>18)&0xC) | ((c0>>11)&0x3) | (c0&0x30));
right = PC2LOOKUP(4, ((d0 >> 22) & 0x3F) );
right |= PC2LOOKUP(5, ((d0 >> 15) & 0x30) | ((d0 >> 14) & 0xf) );
right |= PC2LOOKUP(6, ((d0 >> 7) & 0x3F) );
right |= PC2LOOKUP(7, ((d0 >> 1) & 0x3C) | (d0 & 0x3));
#else
#define PC2LOOKUP(b,c) *(HALF *)((BYTE *)&PC2[b][0]+(c))
left = PC2LOOKUP(0, ((c0 >> 20) & 0xFC) );
left |= PC2LOOKUP(1, ((c0 >> 11) & 0xFC) );
left |= PC2LOOKUP(2, ((c0 >> 2) & 0xE0) | ((c0 << 2) & 0x1C) );
left |= PC2LOOKUP(3, ((c0>>16)&0x30)|((c0>>9)&0xC)|((c0<<2)&0xC0));
right = PC2LOOKUP(4, ((d0 >> 20) & 0xFC) );
right |= PC2LOOKUP(5, ((d0 >> 13) & 0xC0) | ((d0 >> 12) & 0x3C) );
right |= PC2LOOKUP(6, ((d0 >> 5) & 0xFC) );
right |= PC2LOOKUP(7, ((d0 << 1) & 0xF0) | ((d0 << 2) & 0x0C));
#endif
/* left contains key bits for S1 S3 S2 S4 */
/* right contains key bits for S6 S8 S5 S7 */
temp = (left << 16) /* S2 S4 XX XX */
| (right >> 16); /* XX XX S6 S8 */
ks[0] = temp;
temp = (left & 0xffff0000) /* S1 S3 XX XX */
| (right & 0x0000ffff);/* XX XX S5 S7 */
ks[1] = temp;
ks = (HALF*)((BYTE *)ks + delta);
}
}
/*
* The DES Initial Permutation
* if we number the bits of the 8 bytes of input like this (in octal):
* 00 01 02 03 04 05 06 07
* 10 11 12 13 14 15 16 17
* 20 21 22 23 24 25 26 27
* 30 31 32 33 34 35 36 37
* 40 41 42 43 44 45 46 47
* 50 51 52 53 54 55 56 57
* 60 61 62 63 64 65 66 67
* 70 71 72 73 74 75 76 77
* then after the initial permutation, they will be in this order.
* 71 61 51 41 31 21 11 01
* 73 63 53 43 33 23 13 03
* 75 65 55 45 35 25 15 05
* 77 67 57 47 37 27 17 07
* 70 60 50 40 30 20 10 00
* 72 62 52 42 32 22 12 02
* 74 64 54 44 34 24 14 04
* 76 66 56 46 36 26 16 06
*
* One way to do this is in two steps:
* 1. Flip this matrix about the diagonal from 70-07 as done for PC1.
* 2. Rearrange the bytes (rows in the matrix above) with the following code.
*
* #define swapHiLo(word, temp) \
* temp = (word ^ (word >> 24)) & 0x000000ff; \
* word ^= temp | (temp << 24);
*
* right ^= temp = ((left << 8) ^ right) & 0xff00ff00;
* left ^= temp >> 8;
* swapHiLo(left, temp);
* swapHiLo(right,temp);
*
* However, the two steps can be combined, so that the rows are rearranged
* while the matrix is being flipped, reducing the number of bit exchange
* operations from 8 ot 5.
*
* Initial Permutation */
#define IP(left, right, temp) \
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
left ^= temp << 4; \
right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
left ^= temp << 16; \
right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
left ^= temp >> 2; \
right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
left ^= temp >> 8; \
right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
left ^= temp << 1;
/* The Final (Inverse Initial) permutation is done by reversing the
** steps of the Initital Permutation
*/
#define FP(left, right, temp) \
right ^= temp = ((left >> 1) ^ right) & 0x55555555; \
left ^= temp << 1; \
right ^= temp = ((left << 8) ^ right) & 0xff00ff00; \
left ^= temp >> 8; \
right ^= temp = ((left << 2) ^ right) & 0xcccccccc; \
left ^= temp >> 2; \
right ^= temp = ((left >> 16) ^ right) & 0x0000ffff; \
left ^= temp << 16; \
right ^= temp = ((left >> 4) ^ right) & 0x0f0f0f0f; \
left ^= temp << 4;
void
DES_Do1Block(HALF * ks, const BYTE * inbuf, BYTE * outbuf)
{
register HALF left, right;
register HALF temp;
#if defined(_X86_)
left = HALFPTR(inbuf)[0];
right = HALFPTR(inbuf)[1];
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#else
if (((ptrdiff_t)inbuf & 0x03) == 0) {
left = HALFPTR(inbuf)[0];
right = HALFPTR(inbuf)[1];
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
} else {
left = ((HALF)inbuf[0] << 24) | ((HALF)inbuf[1] << 16) |
((HALF)inbuf[2] << 8) | inbuf[3];
right = ((HALF)inbuf[4] << 24) | ((HALF)inbuf[5] << 16) |
((HALF)inbuf[6] << 8) | inbuf[7];
}
#endif
IP(left, right, temp);
/* shift the values left circularly 3 bits. */
left = (left << 3) | (left >> 29);
right = (right << 3) | (right >> 29);
#ifdef USE_INDEXING
#define KSLOOKUP(s,b) SP[s][((temp >> (b+2)) & 0x3f)]
#else
#define KSLOOKUP(s,b) *(HALF*)((BYTE*)&SP[s][0]+((temp >> b) & 0xFC))
#endif
#define ROUND(out, in, r) \
temp = in ^ ks[2*r]; \
out ^= KSLOOKUP( 1, 24 ); \
out ^= KSLOOKUP( 3, 16 ); \
out ^= KSLOOKUP( 5, 8 ); \
out ^= KSLOOKUP( 7, 0 ); \
temp = ((in >> 4) | (in << 28)) ^ ks[2*r+1]; \
out ^= KSLOOKUP( 0, 24 ); \
out ^= KSLOOKUP( 2, 16 ); \
out ^= KSLOOKUP( 4, 8 ); \
out ^= KSLOOKUP( 6, 0 );
/* Do the 16 Feistel rounds */
ROUND(left, right, 0)
ROUND(right, left, 1)
ROUND(left, right, 2)
ROUND(right, left, 3)
ROUND(left, right, 4)
ROUND(right, left, 5)
ROUND(left, right, 6)
ROUND(right, left, 7)
ROUND(left, right, 8)
ROUND(right, left, 9)
ROUND(left, right, 10)
ROUND(right, left, 11)
ROUND(left, right, 12)
ROUND(right, left, 13)
ROUND(left, right, 14)
ROUND(right, left, 15)
/* now shift circularly right 3 bits to undo the shifting done
** above. switch left and right here.
*/
temp = (left >> 3) | (left << 29);
left = (right >> 3) | (right << 29);
right = temp;
FP(left, right, temp);
#if defined(_X86_)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
HALFPTR(outbuf)[0] = left;
HALFPTR(outbuf)[1] = right;
#else
if (((ptrdiff_t)inbuf & 0x03) == 0) {
#if defined(IS_LITTLE_ENDIAN)
BYTESWAP(left, temp);
BYTESWAP(right, temp);
#endif
HALFPTR(outbuf)[0] = left;
HALFPTR(outbuf)[1] = right;
} else {
outbuf[0] = (BYTE)(left >> 24);
outbuf[1] = (BYTE)(left >> 16);
outbuf[2] = (BYTE)(left >> 8);
outbuf[3] = (BYTE)(left );
outbuf[4] = (BYTE)(right >> 24);
outbuf[5] = (BYTE)(right >> 16);
outbuf[6] = (BYTE)(right >> 8);
outbuf[7] = (BYTE)(right );
}
#endif
}
/* Ackowledgements:
** Two ideas used in this implementation were shown to me by Dennis Ferguson
** in 1990. He credits them to Richard Outerbridge and Dan Hoey. They were:
** 1. The method of computing the Initial and Final permutations.
** 2. Circularly rotating the SP tables and the initial values of left and
** right to reduce the number of shifts required during the 16 rounds.
*/

View File

@@ -1,69 +0,0 @@
/*
* des.h
*
* header file for DES-150 library
*
* 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 the DES-150 library.
*
* The Initial Developer of the Original Code is Nelson B. Bolyard,
* nelsonb@iname.com. Portions created by Nelson B. Bolyard are
* Copyright (C) 1990, 2000 Nelson B. Bolyard, All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the GPL.
*/
#ifndef _DES_H_
#define _DES_H_ 1
#include "blapi.h"
typedef unsigned char BYTE;
typedef unsigned int HALF;
#define HALFPTR(x) ((HALF *)(x))
#define SHORTPTR(x) ((unsigned short *)(x))
#define BYTEPTR(x) ((BYTE *)(x))
typedef enum {
DES_ENCRYPT = 0x5555,
DES_DECRYPT = 0xAAAA
} DESDirection;
typedef void DESFunc(struct DESContextStr *cx, BYTE *out, const BYTE *in,
unsigned int len);
struct DESContextStr {
/* key schedule, 16 internal keys, each with 8 6-bit parts */
HALF ks0 [32];
HALF ks1 [32];
HALF ks2 [32];
HALF iv [2];
DESDirection direction;
DESFunc *worker;
};
void DES_MakeSchedule( HALF * ks, const BYTE * key, DESDirection direction);
void DES_Do1Block( HALF * ks, const BYTE * inbuf, BYTE * outbuf);
#endif

View File

@@ -1,275 +0,0 @@
/*
* desblapi.c
*
* core source file for DES-150 library
* Implement DES Modes of Operation and Triple-DES.
* Adapt DES-150 to blapi API.
*
* 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 the DES-150 library.
*
* The Initial Developer of the Original Code is Nelson B. Bolyard,
* nelsonb@iname.com. Portions created by Nelson B. Bolyard are
* Copyright (C) 1990, 2000 Nelson B. Bolyard, All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the GPL.
*/
#include "des.h"
#include <stddef.h>
#include "secerr.h"
#if defined(_X86_)
/* Intel X86 CPUs do unaligned loads and stores without complaint. */
#define COPY8B(to, from, ptr) \
HALFPTR(to)[0] = HALFPTR(from)[0]; \
HALFPTR(to)[1] = HALFPTR(from)[1];
#elif defined(USE_MEMCPY)
#define COPY8B(to, from, ptr) memcpy(to, from, 8)
#else
#define COPY8B(to, from, ptr) \
if (((ptrdiff_t)(ptr) & 0x3) == 0) { \
HALFPTR(to)[0] = HALFPTR(from)[0]; \
HALFPTR(to)[1] = HALFPTR(from)[1]; \
} else if (((ptrdiff_t)(ptr) & 0x1) == 0) { \
SHORTPTR(to)[0] = SHORTPTR(from)[0]; \
SHORTPTR(to)[1] = SHORTPTR(from)[1]; \
SHORTPTR(to)[2] = SHORTPTR(from)[2]; \
SHORTPTR(to)[3] = SHORTPTR(from)[3]; \
} else { \
BYTEPTR(to)[0] = BYTEPTR(from)[0]; \
BYTEPTR(to)[1] = BYTEPTR(from)[1]; \
BYTEPTR(to)[2] = BYTEPTR(from)[2]; \
BYTEPTR(to)[3] = BYTEPTR(from)[3]; \
BYTEPTR(to)[4] = BYTEPTR(from)[4]; \
BYTEPTR(to)[5] = BYTEPTR(from)[5]; \
BYTEPTR(to)[6] = BYTEPTR(from)[6]; \
BYTEPTR(to)[7] = BYTEPTR(from)[7]; \
}
#endif
#define COPY8BTOHALF(to, from) COPY8B(to, from, from)
#define COPY8BFROMHALF(to, from) COPY8B(to, from, to)
static void
DES_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
while (len) {
DES_Do1Block(cx->ks0, in, out);
len -= 8;
in += 8;
out += 8;
}
}
static void
DES_EDE3_ECB(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
while (len) {
DES_Do1Block(cx->ks0, in, out);
len -= 8;
in += 8;
DES_Do1Block(cx->ks1, out, out);
DES_Do1Block(cx->ks2, out, out);
out += 8;
}
}
static void
DES_CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE * bufend = in + len;
HALF vec[2];
while (in != bufend) {
COPY8BTOHALF(vec, in);
in += 8;
vec[0] ^= cx->iv[0];
vec[1] ^= cx->iv[1];
DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
COPY8BFROMHALF(out, cx->iv);
out += 8;
}
}
static void
DES_CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE * bufend;
HALF oldciphertext[2];
HALF plaintext [2];
for (bufend = in + len; in != bufend; ) {
oldciphertext[0] = cx->iv[0];
oldciphertext[1] = cx->iv[1];
COPY8BTOHALF(cx->iv, in);
in += 8;
DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
plaintext[0] ^= oldciphertext[0];
plaintext[1] ^= oldciphertext[1];
COPY8BFROMHALF(out, plaintext);
out += 8;
}
}
static void
DES_EDE3CBCEn(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE * bufend = in + len;
HALF vec[2];
while (in != bufend) {
COPY8BTOHALF(vec, in);
in += 8;
vec[0] ^= cx->iv[0];
vec[1] ^= cx->iv[1];
DES_Do1Block( cx->ks0, (BYTE *)vec, (BYTE *)cx->iv);
DES_Do1Block( cx->ks1, (BYTE *)cx->iv, (BYTE *)cx->iv);
DES_Do1Block( cx->ks2, (BYTE *)cx->iv, (BYTE *)cx->iv);
COPY8BFROMHALF(out, cx->iv);
out += 8;
}
}
static void
DES_EDE3CBCDe(DESContext *cx, BYTE *out, const BYTE *in, unsigned int len)
{
const BYTE * bufend;
HALF oldciphertext[2];
HALF plaintext [2];
for (bufend = in + len; in != bufend; ) {
oldciphertext[0] = cx->iv[0];
oldciphertext[1] = cx->iv[1];
COPY8BTOHALF(cx->iv, in);
in += 8;
DES_Do1Block(cx->ks0, (BYTE *)cx->iv, (BYTE *)plaintext);
DES_Do1Block(cx->ks1, (BYTE *)plaintext, (BYTE *)plaintext);
DES_Do1Block(cx->ks2, (BYTE *)plaintext, (BYTE *)plaintext);
plaintext[0] ^= oldciphertext[0];
plaintext[1] ^= oldciphertext[1];
COPY8BFROMHALF(out, plaintext);
out += 8;
}
}
DESContext *
DES_CreateContext(const BYTE * key, const BYTE *iv, int mode, PRBool encrypt)
{
DESContext *cx = PORT_ZNew(DESContext);
DESDirection opposite;
if (!cx)
return 0;
cx->direction = encrypt ? DES_ENCRYPT : DES_DECRYPT;
opposite = encrypt ? DES_DECRYPT : DES_ENCRYPT;
switch (mode) {
case NSS_DES: /* DES ECB */
DES_MakeSchedule( cx->ks0, key, cx->direction);
cx->worker = &DES_ECB;
break;
case NSS_DES_EDE3: /* DES EDE ECB */
cx->worker = &DES_EDE3_ECB;
if (encrypt) {
DES_MakeSchedule(cx->ks0, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
} else {
DES_MakeSchedule(cx->ks2, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
}
break;
case NSS_DES_CBC: /* DES CBC */
COPY8BTOHALF(cx->iv, iv);
cx->worker = encrypt ? &DES_CBCEn : &DES_CBCDe;
DES_MakeSchedule(cx->ks0, key, cx->direction);
break;
case NSS_DES_EDE3_CBC: /* DES EDE CBC */
COPY8BTOHALF(cx->iv, iv);
if (encrypt) {
cx->worker = &DES_EDE3CBCEn;
DES_MakeSchedule(cx->ks0, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks2, key + 16, cx->direction);
} else {
cx->worker = &DES_EDE3CBCDe;
DES_MakeSchedule(cx->ks2, key, cx->direction);
DES_MakeSchedule(cx->ks1, key + 8, opposite);
DES_MakeSchedule(cx->ks0, key + 16, cx->direction);
}
break;
default:
PORT_Free(cx);
cx = 0;
PORT_SetError(SEC_ERROR_INVALID_ARGS);
break;
}
return cx;
}
void
DES_DestroyContext(DESContext *cx, PRBool freeit)
{
if (cx) {
memset(cx, 0, sizeof *cx);
if (freeit)
PORT_Free(cx);
}
}
SECStatus
DES_Encrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
{
if (inLen < 0 || (inLen % 8) != 0 || maxOutLen < inLen || !cx ||
cx->direction != DES_ENCRYPT) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
cx->worker(cx, out, in, inLen);
if (outLen)
*outLen = inLen;
return SECSuccess;
}
SECStatus
DES_Decrypt(DESContext *cx, BYTE *out, unsigned int *outLen,
unsigned int maxOutLen, const BYTE *in, unsigned int inLen)
{
if (inLen < 0 || (inLen % 8) != 0 || maxOutLen < inLen || !cx ||
cx->direction != DES_DECRYPT) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
cx->worker(cx, out, in, inLen);
if (outLen)
*outLen = inLen;
return SECSuccess;
}

View File

@@ -1,385 +0,0 @@
/*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
/*
* Diffie-Hellman parameter generation, key generation, and secret derivation.
* KEA secret generation and verification.
*
* $Id: dh.c,v 1.6 2001-09-20 22:14:06 relyea%netscape.com Exp $
*/
#include "prerr.h"
#include "secerr.h"
#include "blapi.h"
#include "secitem.h"
#include "mpi.h"
#include "mpprime.h"
#include "secmpi.h"
#define DH_SECRET_KEY_LEN 20
#define KEA_DERIVED_SECRET_LEN 128
SECStatus
DH_GenParam(int primeLen, DHParams **params)
{
PRArenaPool *arena;
DHParams *dhparams;
unsigned char *pb = NULL;
unsigned char *ab = NULL;
unsigned long counter = 0;
mp_int p, q, a, h, psub1, test;
mp_err err = MP_OKAY;
SECStatus rv = SECSuccess;
if (!params || primeLen < 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (!arena) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams));
if (!dhparams) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
dhparams->arena = arena;
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&a) = 0;
MP_DIGITS(&h) = 0;
MP_DIGITS(&psub1) = 0;
MP_DIGITS(&test) = 0;
CHECK_MPI_OK( mp_init(&p) );
CHECK_MPI_OK( mp_init(&q) );
CHECK_MPI_OK( mp_init(&a) );
CHECK_MPI_OK( mp_init(&h) );
CHECK_MPI_OK( mp_init(&psub1) );
CHECK_MPI_OK( mp_init(&test) );
/* generate prime with MPI, uses Miller-Rabin to generate strong prime. */
pb = PORT_Alloc(primeLen);
CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) );
pb[0] |= 0x80; /* set high-order bit */
pb[primeLen-1] |= 0x01; /* set low-order bit */
CHECK_MPI_OK( mp_read_unsigned_octets(&p, pb, primeLen) );
CHECK_MPI_OK( mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter) );
/* construct Sophie-Germain prime q = (p-1)/2. */
CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) );
CHECK_MPI_OK( mp_div_2(&psub1, &q) );
/* construct a generator from the prime. */
ab = PORT_Alloc(primeLen);
/* generate a candidate number a in p's field */
CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(ab, primeLen) );
CHECK_MPI_OK( mp_read_unsigned_octets(&a, ab, primeLen) );
/* force a < p (note that quot(a/p) <= 1) */
if ( mp_cmp(&a, &p) > 0 )
CHECK_MPI_OK( mp_sub(&a, &p, &a) );
do {
/* check that a is in the range [2..p-1] */
if ( mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) {
/* a is outside of the allowed range. Set a=3 and keep going. */
mp_set(&a, 3);
}
/* if a**q mod p != 1 then a is a generator */
CHECK_MPI_OK( mp_exptmod(&a, &q, &p, &test) );
if ( mp_cmp_d(&test, 1) != 0 )
break;
/* increment the candidate and try again. */
CHECK_MPI_OK( mp_add_d(&a, 1, &a) );
} while (PR_TRUE);
MPINT_TO_SECITEM(&p, &dhparams->prime, arena);
MPINT_TO_SECITEM(&a, &dhparams->base, arena);
*params = dhparams;
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&a);
mp_clear(&h);
mp_clear(&psub1);
mp_clear(&test);
if (pb) PORT_ZFree(pb, primeLen);
if (ab) PORT_ZFree(ab, primeLen);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
if (rv)
PORT_FreeArena(arena, PR_TRUE);
return rv;
}
SECStatus
DH_NewKey(DHParams *params, DHPrivateKey **privKey)
{
PRArenaPool *arena;
DHPrivateKey *key;
mp_int g, xa, p, Ya;
mp_err err = MP_OKAY;
SECStatus rv = SECSuccess;
if (!params || !privKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
if (!arena) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey));
if (!key) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
key->arena = arena;
MP_DIGITS(&g) = 0;
MP_DIGITS(&xa) = 0;
MP_DIGITS(&p) = 0;
MP_DIGITS(&Ya) = 0;
CHECK_MPI_OK( mp_init(&g) );
CHECK_MPI_OK( mp_init(&xa) );
CHECK_MPI_OK( mp_init(&p) );
CHECK_MPI_OK( mp_init(&Ya) );
/* Set private key's p */
CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, &params->prime) );
SECITEM_TO_MPINT(key->prime, &p);
/* Set private key's g */
CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, &params->base) );
SECITEM_TO_MPINT(key->base, &g);
/* Generate private key xa */
SECITEM_AllocItem(arena, &key->privateValue, DH_SECRET_KEY_LEN);
RNG_GenerateGlobalRandomBytes(key->privateValue.data,
key->privateValue.len);
SECITEM_TO_MPINT( key->privateValue, &xa );
/* xa < p */
CHECK_MPI_OK( mp_mod(&xa, &p, &xa) );
/* Compute public key Ya = g ** xa mod p */
CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) );
MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena);
*privKey = key;
cleanup:
mp_clear(&g);
mp_clear(&xa);
mp_clear(&p);
mp_clear(&Ya);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
if (rv)
PORT_FreeArena(arena, PR_TRUE);
return rv;
}
SECStatus
DH_Derive(SECItem *publicValue,
SECItem *prime,
SECItem *privateValue,
SECItem *derivedSecret,
unsigned int maxOutBytes)
{
mp_int p, Xa, Yb, ZZ;
mp_err err = MP_OKAY;
unsigned int len = 0, nb;
unsigned char *secret = NULL;
if (!publicValue || !prime || !privateValue || !derivedSecret) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
memset(derivedSecret, 0, sizeof *derivedSecret);
MP_DIGITS(&p) = 0;
MP_DIGITS(&Xa) = 0;
MP_DIGITS(&Yb) = 0;
MP_DIGITS(&ZZ) = 0;
CHECK_MPI_OK( mp_init(&p) );
CHECK_MPI_OK( mp_init(&Xa) );
CHECK_MPI_OK( mp_init(&Yb) );
CHECK_MPI_OK( mp_init(&ZZ) );
SECITEM_TO_MPINT(*publicValue, &Yb);
SECITEM_TO_MPINT(*privateValue, &Xa);
SECITEM_TO_MPINT(*prime, &p);
/* ZZ = (Yb)**Xa mod p */
CHECK_MPI_OK( mp_exptmod(&Yb, &Xa, &p, &ZZ) );
/* number of bytes in the derived secret */
len = mp_unsigned_octet_size(&ZZ);
/* allocate a buffer which can hold the entire derived secret. */
secret = PORT_Alloc(len);
/* grab the derived secret */
err = mp_to_unsigned_octets(&ZZ, secret, len);
if (err >= 0) err = MP_OKAY;
/* Take minimum of bytes requested and bytes in derived secret,
** if maxOutBytes is 0 take all of the bytes from the derived secret.
*/
if (maxOutBytes > 0)
nb = PR_MIN(len, maxOutBytes);
else
nb = len;
SECITEM_AllocItem(NULL, derivedSecret, nb);
memcpy(derivedSecret->data, secret, nb);
cleanup:
mp_clear(&p);
mp_clear(&Xa);
mp_clear(&Yb);
mp_clear(&ZZ);
if (secret) {
/* free the buffer allocated for the full secret. */
PORT_ZFree(secret, len);
}
if (err) {
MP_TO_SEC_ERROR(err);
if (derivedSecret->data)
PORT_ZFree(derivedSecret->data, derivedSecret->len);
return SECFailure;
}
return SECSuccess;
}
SECStatus
KEA_Derive(SECItem *prime,
SECItem *public1,
SECItem *public2,
SECItem *private1,
SECItem *private2,
SECItem *derivedSecret)
{
mp_int p, Y, R, r, x, t, u, w;
mp_err err;
unsigned char *secret = NULL;
unsigned int len = 0, offset;
if (!prime || !public1 || !public2 || !private1 || !private2 ||
!derivedSecret) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
memset(derivedSecret, 0, sizeof *derivedSecret);
MP_DIGITS(&p) = 0;
MP_DIGITS(&Y) = 0;
MP_DIGITS(&R) = 0;
MP_DIGITS(&r) = 0;
MP_DIGITS(&x) = 0;
MP_DIGITS(&t) = 0;
MP_DIGITS(&u) = 0;
MP_DIGITS(&w) = 0;
CHECK_MPI_OK( mp_init(&p) );
CHECK_MPI_OK( mp_init(&Y) );
CHECK_MPI_OK( mp_init(&R) );
CHECK_MPI_OK( mp_init(&r) );
CHECK_MPI_OK( mp_init(&x) );
CHECK_MPI_OK( mp_init(&t) );
CHECK_MPI_OK( mp_init(&u) );
CHECK_MPI_OK( mp_init(&w) );
SECITEM_TO_MPINT(*prime, &p);
SECITEM_TO_MPINT(*public1, &Y);
SECITEM_TO_MPINT(*public2, &R);
SECITEM_TO_MPINT(*private1, &r);
SECITEM_TO_MPINT(*private2, &x);
/* t = DH(Y, r, p) = Y ** r mod p */
CHECK_MPI_OK( mp_exptmod(&Y, &r, &p, &t) );
/* u = DH(R, x, p) = R ** x mod p */
CHECK_MPI_OK( mp_exptmod(&R, &x, &p, &u) );
/* w = (t + u) mod p */
CHECK_MPI_OK( mp_addmod(&t, &u, &p, &w) );
/* allocate a buffer for the full derived secret */
len = mp_unsigned_octet_size(&w);
secret = PORT_Alloc(len);
/* grab the secret */
err = mp_to_unsigned_octets(&w, secret, len);
if (err > 0) err = MP_OKAY;
/* allocate output buffer */
SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN);
memset(derivedSecret->data, 0, derivedSecret->len);
/* copy in the 128 lsb of the secret */
if (len >= KEA_DERIVED_SECRET_LEN) {
memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN),
KEA_DERIVED_SECRET_LEN);
} else {
offset = KEA_DERIVED_SECRET_LEN - len;
memcpy(derivedSecret->data + offset, secret, len);
}
cleanup:
mp_clear(&p);
mp_clear(&Y);
mp_clear(&R);
mp_clear(&r);
mp_clear(&x);
mp_clear(&t);
mp_clear(&u);
mp_clear(&w);
if (secret)
PORT_ZFree(secret, len);
if (err) {
MP_TO_SEC_ERROR(err);
return SECFailure;
}
return SECSuccess;
}
PRBool
KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
{
mp_int p, q, y, r;
mp_err err;
int cmp = 1; /* default is false */
if (!Y || !prime || !subPrime) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&y) = 0;
MP_DIGITS(&r) = 0;
CHECK_MPI_OK( mp_init(&p) );
CHECK_MPI_OK( mp_init(&q) );
CHECK_MPI_OK( mp_init(&y) );
CHECK_MPI_OK( mp_init(&r) );
SECITEM_TO_MPINT(*prime, &p);
SECITEM_TO_MPINT(*subPrime, &q);
SECITEM_TO_MPINT(*Y, &y);
/* compute r = y**q mod p */
CHECK_MPI_OK( mp_exptmod(&y, &q, &p, &r) );
/* compare to 1 */
cmp = mp_cmp_d(&r, 1);
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&y);
mp_clear(&r);
if (err) {
MP_TO_SEC_ERROR(err);
return PR_FALSE;
}
return (cmp == 0) ? PR_TRUE : PR_FALSE;
}

View File

@@ -1,82 +0,0 @@
/*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#include "prerr.h"
#include "secerr.h"
#include "blapi.h"
SECStatus
DH_GenParam(int primeLen, DHParams ** params)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
SECStatus
DH_NewKey(DHParams * params,
DHPrivateKey ** privKey)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
SECStatus
DH_Derive(SECItem * publicValue,
SECItem * prime,
SECItem * privateValue,
SECItem * derivedSecret,
unsigned int maxOutBytes)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
SECStatus
KEA_Derive(SECItem *prime,
SECItem *public1,
SECItem *public2,
SECItem *private1,
SECItem *private2,
SECItem *derivedSecret)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
PRBool
KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return PR_FALSE;
}

View File

@@ -1,420 +0,0 @@
/*
*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: dsa.c,v 1.11 2003-02-25 23:45:23 nelsonb%netscape.com Exp $
*/
#include "secerr.h"
#include "prtypes.h"
#include "prinit.h"
#include "blapi.h"
#include "nssilock.h"
#include "secitem.h"
#include "blapi.h"
#include "mpi.h"
/* XXX to be replaced by define in blapit.h */
#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048
#define CHECKOK(func) if (MP_OKAY > (err = func)) goto cleanup
#define SECITEM_TO_MPINT(it, mp) \
CHECKOK(mp_read_unsigned_octets((mp), (it).data, (it).len))
/* DSA-specific random number functions defined in prng_fips1861.c. */
extern SECStatus
DSA_RandomUpdate(void *data, size_t bytes, unsigned char *q);
extern SECStatus
DSA_GenerateGlobalRandomBytes(void *dest, size_t len, unsigned char *q);
static void translate_mpi_error(mp_err err)
{
switch (err) {
case MP_MEM: PORT_SetError(SEC_ERROR_NO_MEMORY); break;
case MP_RANGE: PORT_SetError(SEC_ERROR_BAD_DATA); break;
case MP_BADARG: PORT_SetError(SEC_ERROR_INVALID_ARGS); break;
default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); break;
}
}
SECStatus
dsa_NewKey(const PQGParams *params, DSAPrivateKey **privKey,
const unsigned char *xb)
{
unsigned int y_len;
mp_int p, g;
mp_int x, y;
mp_err err;
PRArenaPool *arena;
DSAPrivateKey *key;
/* Check args. */
if (!params || !privKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Initialize an arena for the DSA key. */
arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE);
if (!arena) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
if (!key) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
key->params.arena = arena;
/* Initialize MPI integers. */
MP_DIGITS(&p) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&x) = 0;
MP_DIGITS(&y) = 0;
CHECKOK( mp_init(&p) );
CHECKOK( mp_init(&g) );
CHECKOK( mp_init(&x) );
CHECKOK( mp_init(&y) );
/* Copy over the PQG params */
CHECKOK( SECITEM_CopyItem(arena, &key->params.prime, &params->prime) );
CHECKOK( SECITEM_CopyItem(arena, &key->params.subPrime, &params->subPrime));
CHECKOK( SECITEM_CopyItem(arena, &key->params.base, &params->base) );
/* Convert stored p, g, and received x into MPI integers. */
SECITEM_TO_MPINT(params->prime, &p);
SECITEM_TO_MPINT(params->base, &g);
CHECKOK( mp_read_unsigned_octets(&x, xb, DSA_SUBPRIME_LEN) );
/* Store x in private key */
SECITEM_AllocItem(arena, &key->privateValue, DSA_SUBPRIME_LEN);
memcpy(key->privateValue.data, xb, DSA_SUBPRIME_LEN);
/* Compute public key y = g**x mod p */
CHECKOK( mp_exptmod(&g, &x, &p, &y) );
/* Store y in public key */
y_len = mp_unsigned_octet_size(&y);
SECITEM_AllocItem(arena, &key->publicValue, y_len);
err = mp_to_unsigned_octets(&y, key->publicValue.data, y_len);
/* mp_to_unsigned_octets returns bytes written (y_len) if okay */
if (err < 0) goto cleanup; else err = MP_OKAY;
*privKey = key;
key = NULL;
cleanup:
mp_clear(&p);
mp_clear(&g);
mp_clear(&x);
mp_clear(&y);
if (key)
PORT_FreeArena(key->params.arena, PR_TRUE);
if (err) {
translate_mpi_error(err);
return SECFailure;
}
return SECSuccess;
}
/*
** Generate and return a new DSA public and private key pair,
** both of which are encoded into a single DSAPrivateKey struct.
** "params" is a pointer to the PQG parameters for the domain
** Uses a random seed.
*/
SECStatus
DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey)
{
SECStatus rv;
unsigned char seed[DSA_SUBPRIME_LEN];
/* Generate seed bytes for x according to FIPS 186-1 appendix 3 */
if (DSA_GenerateGlobalRandomBytes(seed, DSA_SUBPRIME_LEN,
params->subPrime.data))
return SECFailure;
/* Generate a new DSA key using random seed. */
rv = dsa_NewKey(params, privKey, seed);
return rv;
}
/* For FIPS compliance testing. Seed must be exactly 20 bytes long */
SECStatus
DSA_NewKeyFromSeed(const PQGParams *params,
const unsigned char *seed,
DSAPrivateKey **privKey)
{
SECStatus rv;
rv = dsa_NewKey(params, privKey, seed);
return rv;
}
static SECStatus
dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest,
const unsigned char *kb)
{
mp_int p, q, g; /* PQG parameters */
mp_int x, k; /* private key & pseudo-random integer */
mp_int r, s; /* tuple (r, s) is signature) */
mp_err err = MP_OKAY;
SECStatus rv = SECSuccess;
/* FIPS-compliance dictates that digest is a SHA1 hash. */
/* Check args. */
if (!key || !signature || !digest ||
(signature->len != DSA_SIGNATURE_LEN) ||
(digest->len != SHA1_LENGTH)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Initialize MPI integers. */
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&x) = 0;
MP_DIGITS(&k) = 0;
MP_DIGITS(&r) = 0;
MP_DIGITS(&s) = 0;
CHECKOK( mp_init(&p) );
CHECKOK( mp_init(&q) );
CHECKOK( mp_init(&g) );
CHECKOK( mp_init(&x) );
CHECKOK( mp_init(&k) );
CHECKOK( mp_init(&r) );
CHECKOK( mp_init(&s) );
/*
** Convert stored PQG and private key into MPI integers.
*/
SECITEM_TO_MPINT(key->params.prime, &p);
SECITEM_TO_MPINT(key->params.subPrime, &q);
SECITEM_TO_MPINT(key->params.base, &g);
SECITEM_TO_MPINT(key->privateValue, &x);
CHECKOK( mp_read_unsigned_octets(&k, kb, DSA_SUBPRIME_LEN) );
/*
** FIPS 186-1, Section 5, Step 1
**
** r = (g**k mod p) mod q
*/
CHECKOK( mp_exptmod(&g, &k, &p, &r) ); /* r = g**k mod p */
CHECKOK( mp_mod(&r, &q, &r) ); /* r = r mod q */
/*
** FIPS 186-1, Section 5, Step 2
**
** s = (k**-1 * (SHA1(M) + x*r)) mod q
*/
SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */
CHECKOK( mp_invmod(&k, &q, &k) ); /* k = k**-1 mod q */
CHECKOK( mp_mulmod(&x, &r, &q, &x) ); /* x = x * r mod q */
CHECKOK( mp_addmod(&s, &x, &q, &s) ); /* s = s + x mod q */
CHECKOK( mp_mulmod(&s, &k, &q, &s) ); /* s = s * k mod q */
/*
** verify r != 0 and s != 0
** mentioned as optional in FIPS 186-1.
*/
if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
rv = SECFailure;
goto cleanup;
}
/*
** Step 4
**
** Signature is tuple (r, s)
*/
err = mp_to_fixlen_octets(&r, signature->data, DSA_SUBPRIME_LEN);
if (err < 0) goto cleanup;
err = mp_to_fixlen_octets(&s, signature->data + DSA_SUBPRIME_LEN,
DSA_SUBPRIME_LEN);
if (err < 0) goto cleanup;
err = MP_OKAY;
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&g);
mp_clear(&x);
mp_clear(&k);
mp_clear(&r);
mp_clear(&s);
if (err) {
translate_mpi_error(err);
rv = SECFailure;
}
return rv;
}
/* signature is caller-supplied buffer of at least 20 bytes.
** On input, signature->len == size of buffer to hold signature.
** digest->len == size of digest.
** On output, signature->len == size of signature in buffer.
** Uses a random seed.
*/
SECStatus
DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest)
{
SECStatus rv;
int retries = 10;
unsigned char kSeed[DSA_SUBPRIME_LEN];
PORT_SetError(0);
do {
rv = DSA_GenerateGlobalRandomBytes(kSeed, DSA_SUBPRIME_LEN,
key->params.subPrime.data);
if (rv != SECSuccess)
break;
rv = dsa_SignDigest(key, signature, digest, kSeed);
} while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM &&
--retries > 0);
return rv;
}
/* For FIPS compliance testing. Seed must be exactly 20 bytes. */
SECStatus
DSA_SignDigestWithSeed(DSAPrivateKey * key,
SECItem * signature,
const SECItem * digest,
const unsigned char * seed)
{
SECStatus rv;
rv = dsa_SignDigest(key, signature, digest, seed);
return rv;
}
/* signature is caller-supplied buffer of at least 20 bytes.
** On input, signature->len == size of buffer to hold signature.
** digest->len == size of digest.
*/
SECStatus
DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature,
const SECItem *digest)
{
/* FIPS-compliance dictates that digest is a SHA1 hash. */
mp_int p, q, g; /* PQG parameters */
mp_int r_, s_; /* tuple (r', s') is received signature) */
mp_int u1, u2, v, w; /* intermediate values used in verification */
mp_int y; /* public key */
mp_err err;
SECStatus verified = SECFailure;
/* Check args. */
if (!key || !signature || !digest ||
(signature->len != DSA_SIGNATURE_LEN) ||
(digest->len != SHA1_LENGTH)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Initialize MPI integers. */
MP_DIGITS(&p) = 0;
MP_DIGITS(&q) = 0;
MP_DIGITS(&g) = 0;
MP_DIGITS(&y) = 0;
MP_DIGITS(&r_) = 0;
MP_DIGITS(&s_) = 0;
MP_DIGITS(&u1) = 0;
MP_DIGITS(&u2) = 0;
MP_DIGITS(&v) = 0;
MP_DIGITS(&w) = 0;
CHECKOK( mp_init(&p) );
CHECKOK( mp_init(&q) );
CHECKOK( mp_init(&g) );
CHECKOK( mp_init(&y) );
CHECKOK( mp_init(&r_) );
CHECKOK( mp_init(&s_) );
CHECKOK( mp_init(&u1) );
CHECKOK( mp_init(&u2) );
CHECKOK( mp_init(&v) );
CHECKOK( mp_init(&w) );
/*
** Convert stored PQG and public key into MPI integers.
*/
SECITEM_TO_MPINT(key->params.prime, &p);
SECITEM_TO_MPINT(key->params.subPrime, &q);
SECITEM_TO_MPINT(key->params.base, &g);
SECITEM_TO_MPINT(key->publicValue, &y);
/*
** Convert received signature (r', s') into MPI integers.
*/
CHECKOK( mp_read_unsigned_octets(&r_, signature->data, DSA_SUBPRIME_LEN) );
CHECKOK( mp_read_unsigned_octets(&s_, signature->data + DSA_SUBPRIME_LEN,
DSA_SUBPRIME_LEN) );
/*
** Verify that 0 < r' < q and 0 < s' < q
*/
if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0)
goto cleanup; /* will return verified == SECFailure */
/*
** FIPS 186-1, Section 6, Step 1
**
** w = (s')**-1 mod q
*/
CHECKOK( mp_invmod(&s_, &q, &w) ); /* w = (s')**-1 mod q */
/*
** FIPS 186-1, Section 6, Step 2
**
** u1 = ((SHA1(M')) * w) mod q
*/
SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */
CHECKOK( mp_mulmod(&u1, &w, &q, &u1) ); /* u1 = u1 * w mod q */
/*
** FIPS 186-1, Section 6, Step 3
**
** u2 = ((r') * w) mod q
*/
CHECKOK( mp_mulmod(&r_, &w, &q, &u2) );
/*
** FIPS 186-1, Section 6, Step 4
**
** v = ((g**u1 * y**u2) mod p) mod q
*/
CHECKOK( mp_exptmod(&g, &u1, &p, &g) ); /* g = g**u1 mod p */
CHECKOK( mp_exptmod(&y, &u2, &p, &y) ); /* y = y**u2 mod p */
CHECKOK( mp_mulmod(&g, &y, &p, &v) ); /* v = g * y mod p */
CHECKOK( mp_mod(&v, &q, &v) ); /* v = v mod q */
/*
** Verification: v == r'
*/
if (mp_cmp(&v, &r_)) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
verified = SECFailure; /* Signature failed to verify. */
} else {
verified = SECSuccess; /* Signature verified. */
}
cleanup:
mp_clear(&p);
mp_clear(&q);
mp_clear(&g);
mp_clear(&y);
mp_clear(&r_);
mp_clear(&s_);
mp_clear(&u1);
mp_clear(&u2);
mp_clear(&v);
mp_clear(&w);
if (err) {
translate_mpi_error(err);
}
return verified;
}

View File

@@ -1,977 +0,0 @@
/*
* 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 the Elliptic Curve Cryptography library.
*
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
*
* Alternatively, the contents of this file may be used under the terms of
* either 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.
*
*/
#include "blapi.h"
#include "prerr.h"
#include "secerr.h"
#include "secmpi.h"
#include "secitem.h"
#include "ec.h"
#include "GFp_ecl.h"
#include "GF2m_ecl.h"
#ifdef NSS_ENABLE_ECC
/*
* Returns true if pointP is the point at infinity, false otherwise
*/
PRBool
ec_point_at_infinity(SECItem *pointP)
{
int i;
for (i = 1; i < pointP->len; i++) {
if (pointP->data[i] != 0x00) return PR_FALSE;
}
return PR_TRUE;
}
/*
* Computes point addition R = P + Q for the curve whose
* parameters are encoded in params. Two or more of P, Q,
* R may point to the same memory location.
*/
SECStatus
ec_point_add(ECParams *params, SECItem *pointP,
SECItem *pointQ, SECItem *pointR)
{
mp_int Px, Py, Qx, Qy, Rx, Ry;
mp_int irreducible, a;
SECStatus rv = SECFailure;
mp_err err = MP_OKAY;
int len;
#if EC_DEBUG
int i;
printf("ec_point_add: params [len=%d]:", params->DEREncoding.len);
for (i = 0; i < params->DEREncoding.len; i++)
printf("%02x:", params->DEREncoding.data[i]);
printf("\n");
printf("ec_point_add: pointP [len=%d]:", pointP->len);
for (i = 0; i < pointP->len; i++)
printf("%02x:", pointP->data[i]);
printf("\n");
printf("ec_point_add: pointQ [len=%d]:", pointQ->len);
for (i = 0; i < pointQ->len; i++)
printf("%02x:", pointQ->data[i]);
printf("\n");
#endif
/* NOTE: We only support prime field curves for now */
len = (params->fieldID.size + 7) >> 3;
if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
(pointP->len != (2 * len + 1)) ||
(pointQ->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
(pointQ->len != (2 * len + 1))) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
MP_DIGITS(&Px) = 0;
MP_DIGITS(&Py) = 0;
MP_DIGITS(&Qx) = 0;
MP_DIGITS(&Qy) = 0;
MP_DIGITS(&Rx) = 0;
MP_DIGITS(&Ry) = 0;
MP_DIGITS(&irreducible) = 0;
MP_DIGITS(&a) = 0;
CHECK_MPI_OK( mp_init(&Px) );
CHECK_MPI_OK( mp_init(&Py) );
CHECK_MPI_OK( mp_init(&Qx) );
CHECK_MPI_OK( mp_init(&Qy) );
CHECK_MPI_OK( mp_init(&Rx) );
CHECK_MPI_OK( mp_init(&Ry) );
CHECK_MPI_OK( mp_init(&irreducible) );
CHECK_MPI_OK( mp_init(&a) );
/* Initialize Px and Py */
CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1,
(mp_size) len) );
CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len,
(mp_size) len) );
/* Initialize Qx and Qy */
CHECK_MPI_OK( mp_read_unsigned_octets(&Qx, pointQ->data + 1,
(mp_size) len) );
CHECK_MPI_OK( mp_read_unsigned_octets(&Qy, pointQ->data + 1 + len,
(mp_size) len) );
/* Set up the curve coefficient */
SECITEM_TO_MPINT( params->curve.a, &a );
/* Compute R = P + Q */
if (params->fieldID.type == ec_field_GFp) {
SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
if (GFp_ec_pt_add(&irreducible, &a, &Px, &Py, &Qx, &Qy,
&Rx, &Ry) != SECSuccess)
goto cleanup;
} else {
SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
if (GF2m_ec_pt_add(&irreducible, &a, &Px, &Py, &Qx, &Qy, &Rx, &Ry)
!= SECSuccess)
goto cleanup;
}
/* Construct the SECItem representation of the result */
pointR->data[0] = EC_POINT_FORM_UNCOMPRESSED;
CHECK_MPI_OK( mp_to_fixlen_octets(&Rx, pointR->data + 1,
(mp_size) len) );
CHECK_MPI_OK( mp_to_fixlen_octets(&Ry, pointR->data + 1 + len,
(mp_size) len) );
rv = SECSuccess;
#if EC_DEBUG
printf("ec_point_add: pointR [len=%d]:", pointR->len);
for (i = 0; i < pointR->len; i++)
printf("%02x:", pointR->data[i]);
printf("\n");
#endif
cleanup:
mp_clear(&Px);
mp_clear(&Py);
mp_clear(&Qx);
mp_clear(&Qy);
mp_clear(&Rx);
mp_clear(&Ry);
mp_clear(&irreducible);
mp_clear(&a);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
return rv;
}
/*
* Computes scalar point multiplication pointQ = k * pointP for
* the curve whose parameters are encoded in params.
*/
SECStatus
ec_point_mul(ECParams *params, mp_int *k,
SECItem *pointP, SECItem *pointQ)
{
mp_int Px, Py, Qx, Qy;
mp_int irreducible, a, b;
SECStatus rv = SECFailure;
mp_err err = MP_OKAY;
int len;
#if EC_DEBUG
int i;
char mpstr[256];
printf("ec_point_mul: params [len=%d]:", params->DEREncoding.len);
for (i = 0; i < params->DEREncoding.len; i++)
printf("%02x:", params->DEREncoding.data[i]);
printf("\n");
mp_tohex(k, mpstr);
printf("ec_point_mul: scalar : %s\n", mpstr);
mp_todecimal(k, mpstr);
printf("ec_point_mul: scalar : %s (dec)\n", mpstr);
printf("ec_point_mul: pointP [len=%d]:", pointP->len);
for (i = 0; i < pointP->len; i++)
printf("%02x:", pointP->data[i]);
printf("\n");
#endif
/* NOTE: We only support prime field curves for now */
len = (params->fieldID.size + 7) >> 3;
if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
(pointP->len != (2 * len + 1))) {
return SECFailure;
};
MP_DIGITS(&Px) = 0;
MP_DIGITS(&Py) = 0;
MP_DIGITS(&Qx) = 0;
MP_DIGITS(&Qy) = 0;
MP_DIGITS(&irreducible) = 0;
MP_DIGITS(&a) = 0;
MP_DIGITS(&b) = 0;
CHECK_MPI_OK( mp_init(&Px) );
CHECK_MPI_OK( mp_init(&Py) );
CHECK_MPI_OK( mp_init(&Qx) );
CHECK_MPI_OK( mp_init(&Qy) );
CHECK_MPI_OK( mp_init(&irreducible) );
CHECK_MPI_OK( mp_init(&a) );
CHECK_MPI_OK( mp_init(&b) );
/* Initialize Px and Py */
CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1,
(mp_size) len) );
CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len,
(mp_size) len) );
/* Set up mp_ints containing the curve coefficients */
SECITEM_TO_MPINT( params->curve.a, &a );
SECITEM_TO_MPINT( params->curve.b, &b );
/* Compute Q = k * P */
if (params->fieldID.type == ec_field_GFp) {
SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
if (GFp_ec_pt_mul(&irreducible, &a, &b, &Px, &Py, k, &Qx, &Qy)
!= SECSuccess)
goto cleanup;
} else {
SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
if (GF2m_ec_pt_mul(&irreducible, &a, &b, &Px, &Py, k, &Qx, &Qy)
!= SECSuccess) {
goto cleanup;
}
}
/* Construct the SECItem representation of point Q */
pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
(mp_size) len) );
CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
(mp_size) len) );
rv = SECSuccess;
#if EC_DEBUG
printf("ec_point_mul: pointQ [len=%d]:", pointQ->len);
for (i = 0; i < pointQ->len; i++)
printf("%02x:", pointQ->data[i]);
printf("\n");
#endif
cleanup:
mp_clear(&Px);
mp_clear(&Py);
mp_clear(&Qx);
mp_clear(&Qy);
mp_clear(&irreducible);
mp_clear(&a);
mp_clear(&b);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
return rv;
}
static unsigned char bitmask[] = {
0xff, 0x7f, 0x3f, 0x1f,
0x0f, 0x07, 0x03, 0x01
};
#endif /* NSS_ENABLE_ECC */
/* Generates a new EC key pair. The private key is a supplied
* random value (in seed) and the public key is the result of
* performing a scalar point multiplication of that value with
* the curve's base point.
*/
SECStatus
EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
const unsigned char *seed, int seedlen)
{
SECStatus rv = SECFailure;
#ifdef NSS_ENABLE_ECC
PRArenaPool *arena;
ECPrivateKey *key;
mp_int k;
mp_err err = MP_OKAY;
int len;
#if EC_DEBUG
printf("EC_NewKeyFromSeed called\n");
#endif
if (!ecParams || !privKey || !seed || (seedlen < 0)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Initialize an arena for the EC key. */
if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
return SECFailure;
key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
if (!key) {
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
/* Copy all of the fields from the ECParams argument to the
* ECParams structure within the private key.
*/
key->ecParams.arena = arena;
key->ecParams.type = ecParams->type;
key->ecParams.fieldID.size = ecParams->fieldID.size;
key->ecParams.fieldID.type = ecParams->fieldID.type;
if (ecParams->fieldID.type == ec_field_GFp) {
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
&ecParams->fieldID.u.prime));
} else {
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
&ecParams->fieldID.u.poly));
}
key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
&ecParams->curve.a));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
&ecParams->curve.b));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
&ecParams->curve.seed));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
&ecParams->base));
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
&ecParams->order));
key->ecParams.cofactor = ecParams->cofactor;
CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
&ecParams->DEREncoding));
len = (ecParams->fieldID.size + 7) >> 3;
SECITEM_AllocItem(arena, &key->privateValue, len);
SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1);
/* Copy private key */
if (seedlen >= len) {
memcpy(key->privateValue.data, seed, len);
} else {
memset(key->privateValue.data, 0, (len - seedlen));
memcpy(key->privateValue.data + (len - seedlen), seed, seedlen);
}
/* Compute corresponding public key */
MP_DIGITS(&k) = 0;
CHECK_MPI_OK( mp_init(&k) );
CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
(mp_size) len) );
rv = ec_point_mul(ecParams, &k, &(ecParams->base), &(key->publicValue));
if (rv != SECSuccess) goto cleanup;
*privKey = key;
cleanup:
mp_clear(&k);
if (rv)
PORT_FreeArena(arena, PR_TRUE);
#if EC_DEBUG
printf("EC_NewKeyFromSeed returning %s\n",
(rv == SECSuccess) ? "success" : "failure");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_ENABLE_ECC */
return rv;
}
/* Generates a new EC key pair. The private key is a random value and
* the public key is the result of performing a scalar point multiplication
* of that value with the curve's base point.
*/
SECStatus
EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
{
SECStatus rv = SECFailure;
#ifdef NSS_ENABLE_ECC
int len;
unsigned char *seed;
if (!ecParams || !privKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Generate random private key */
len = (ecParams->fieldID.size + 7) >> 3;
if ((seed = PORT_Alloc(len)) == NULL) goto cleanup;
if (RNG_GenerateGlobalRandomBytes(seed, len) != SECSuccess) goto cleanup;
/* Fit private key to the field size */
seed[0] &= bitmask[len * 8 - ecParams->fieldID.size];
rv = EC_NewKeyFromSeed(ecParams, privKey, seed, len);
cleanup:
if (!seed) {
PORT_ZFree(seed, len);
}
#if EC_DEBUG
printf("EC_NewKey returning %s\n",
(rv == SECSuccess) ? "success" : "failure");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_ENABLE_ECC */
return rv;
}
/* Validates an EC public key as described in Section 5.2.2 of
* X9.63. The ECDH primitive when used without the cofactor does
* not address small subgroup attacks, which may occur when the
* public key is not valid. These attacks can be prevented by
* validating the public key before using ECDH.
*/
SECStatus
EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
{
#ifdef NSS_ENABLE_ECC
if (!ecParams || !publicValue) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* XXX Add actual checks here. */
return SECSuccess;
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
return SECFailure;
#endif /* NSS_ENABLE_ECC */
}
/*
** Performs an ECDH key derivation by computing the scalar point
** multiplication of privateValue and publicValue (with or without the
** cofactor) and returns the x-coordinate of the resulting elliptic
** curve point in derived secret. If successful, derivedSecret->data
** is set to the address of the newly allocated buffer containing the
** derived secret, and derivedSecret->len is the size of the secret
** produced. It is the caller's responsibility to free the allocated
** buffer containing the derived secret.
*/
SECStatus
ECDH_Derive(SECItem *publicValue,
ECParams *ecParams,
SECItem *privateValue,
PRBool withCofactor,
SECItem *derivedSecret)
{
SECStatus rv = SECFailure;
#ifdef NSS_ENABLE_ECC
unsigned int len = 0;
SECItem pointQ = {siBuffer, NULL, 0};
mp_int k; /* to hold the private value */
mp_int cofactor;
mp_err err = MP_OKAY;
#if EC_DEBUG
int i;
#endif
if (!publicValue || !ecParams || !privateValue ||
!derivedSecret) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
memset(derivedSecret, 0, sizeof *derivedSecret);
len = (ecParams->fieldID.size + 7) >> 3;
pointQ.len = 2*len + 1;
if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup;
MP_DIGITS(&k) = 0;
CHECK_MPI_OK( mp_init(&k) );
CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
(mp_size) privateValue->len) );
if (withCofactor && (ecParams->cofactor != 1)) {
/* multiply k with the cofactor */
MP_DIGITS(&cofactor) = 0;
CHECK_MPI_OK( mp_init(&cofactor) );
mp_set(&cofactor, ecParams->cofactor);
CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
}
/* Multiply our private key and peer's public point */
if ((ec_point_mul(ecParams, &k, publicValue, &pointQ) != SECSuccess) ||
ec_point_at_infinity(&pointQ))
goto cleanup;
/* Allocate memory for the derived secret and copy
* the x co-ordinate of pointQ into it.
*/
SECITEM_AllocItem(NULL, derivedSecret, len);
memcpy(derivedSecret->data, pointQ.data + 1, len);
rv = SECSuccess;
#if EC_DEBUG
printf("derived_secret:\n");
for (i = 0; i < derivedSecret->len; i++)
printf("%02x:", derivedSecret->data[i]);
printf("\n");
#endif
cleanup:
mp_clear(&k);
if (pointQ.data) {
PORT_ZFree(pointQ.data, 2*len + 1);
}
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_ENABLE_ECC */
return rv;
}
/* Computes the ECDSA signature (a concatenation of two values r and s)
* on the digest using the given key and the random value kb (used in
* computing s).
*/
SECStatus
ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
const SECItem *digest, const unsigned char *kb, const int kblen)
{
SECStatus rv = SECFailure;
#ifdef NSS_ENABLE_ECC
mp_int x1;
mp_int d, k; /* private key, random integer */
mp_int r, s; /* tuple (r, s) is the signature */
mp_int n;
mp_err err = MP_OKAY;
ECParams *ecParams = NULL;
SECItem kGpoint = { siBuffer, NULL, 0};
int len = 0;
#if EC_DEBUG
char mpstr[256];
#endif
/* Check args */
if (!key || !signature || !digest || !kb || (kblen < 0) ||
(digest->len != SHA1_LENGTH)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto cleanup;
}
ecParams = &(key->ecParams);
len = (ecParams->fieldID.size + 7) >> 3;
if (signature->len < 2*len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto cleanup;
}
/* Initialize MPI integers. */
MP_DIGITS(&x1) = 0;
MP_DIGITS(&d) = 0;
MP_DIGITS(&k) = 0;
MP_DIGITS(&r) = 0;
MP_DIGITS(&s) = 0;
MP_DIGITS(&n) = 0;
CHECK_MPI_OK( mp_init(&x1) );
CHECK_MPI_OK( mp_init(&d) );
CHECK_MPI_OK( mp_init(&k) );
CHECK_MPI_OK( mp_init(&r) );
CHECK_MPI_OK( mp_init(&s) );
CHECK_MPI_OK( mp_init(&n) );
SECITEM_TO_MPINT( ecParams->order, &n );
SECITEM_TO_MPINT( key->privateValue, &d );
CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
/* Make sure k is in the interval [1, n-1] */
if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
goto cleanup;
}
/*
** ANSI X9.62, Section 5.3.2, Step 2
**
** Compute kG
*/
kGpoint.len = 2*len + 1;
kGpoint.data = PORT_Alloc(2*len + 1);
if ((kGpoint.data == NULL) ||
(ec_point_mul(ecParams, &k, &(ecParams->base), &kGpoint)
!= SECSuccess))
goto cleanup;
/*
** ANSI X9.62, Section 5.3.3, Step 1
**
** Extract the x co-ordinate of kG into x1
*/
CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
(mp_size) len) );
/*
** ANSI X9.62, Section 5.3.3, Step 2
**
** r = x1 mod n NOTE: n is the order of the curve
*/
CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
/*
** ANSI X9.62, Section 5.3.3, Step 3
**
** verify r != 0
*/
if (mp_cmp_z(&r) == 0) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
goto cleanup;
}
/*
** ANSI X9.62, Section 5.3.3, Step 4
**
** s = (k**-1 * (SHA1(M) + d*r)) mod n
*/
SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */
#if EC_DEBUG
mp_todecimal(&n, mpstr);
printf("n : %s (dec)\n", mpstr);
mp_todecimal(&d, mpstr);
printf("d : %s (dec)\n", mpstr);
mp_tohex(&x1, mpstr);
printf("x1: %s\n", mpstr);
mp_todecimal(&s, mpstr);
printf("digest: %s (decimal)\n", mpstr);
mp_todecimal(&r, mpstr);
printf("r : %s (dec)\n", mpstr);
#endif
CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */
#if EC_DEBUG
mp_todecimal(&s, mpstr);
printf("s : %s (dec)\n", mpstr);
#endif
/*
** ANSI X9.62, Section 5.3.3, Step 5
**
** verify s != 0
*/
if (mp_cmp_z(&s) == 0) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
goto cleanup;
}
/*
**
** Signature is tuple (r, s)
*/
CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, len) );
CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + len, len) );
signature->len = 2*len;
rv = SECSuccess;
err = MP_OKAY;
cleanup:
mp_clear(&x1);
mp_clear(&d);
mp_clear(&k);
mp_clear(&r);
mp_clear(&s);
mp_clear(&n);
if (kGpoint.data) {
PORT_ZFree(kGpoint.data, 2*len + 1);
}
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
#if EC_DEBUG
printf("ECDSA signing with seed %s\n",
(rv == SECSuccess) ? "succeeded" : "failed");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_ENABLE_ECC */
return rv;
}
/*
** Computes the ECDSA signature on the digest using the given key
** and a random seed.
*/
SECStatus
ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
{
SECStatus rv = SECFailure;
#ifdef NSS_ENABLE_ECC
int prerr = 0;
int n = (key->ecParams.fieldID.size + 7) >> 3;
unsigned char mask = bitmask[n * 8 - key->ecParams.fieldID.size];
unsigned char *kseed = NULL;
/* Generate random seed of appropriate size as dictated
* by field size.
*/
if ((kseed = PORT_Alloc(n)) == NULL) return SECFailure;
do {
if (RNG_GenerateGlobalRandomBytes(kseed, n) != SECSuccess)
goto cleanup;
*kseed &= mask;
rv = ECDSA_SignDigestWithSeed(key, signature, digest, kseed, n);
if (rv) prerr = PORT_GetError();
} while ((rv != SECSuccess) && (prerr == SEC_ERROR_NEED_RANDOM));
cleanup:
if (kseed) PORT_ZFree(kseed, n);
#if EC_DEBUG
printf("ECDSA signing %s\n",
(rv == SECSuccess) ? "succeeded" : "failed");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_ENABLE_ECC */
return rv;
}
/*
** Checks the signature on the given digest using the key provided.
*/
SECStatus
ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
const SECItem *digest)
{
SECStatus rv = SECFailure;
#ifdef NSS_ENABLE_ECC
mp_int r_, s_; /* tuple (r', s') is received signature) */
mp_int c, u1, u2, v; /* intermediate values used in verification */
mp_int x1, y1;
mp_int x2, y2;
mp_int n;
mp_err err = MP_OKAY;
PRArenaPool *arena = NULL;
ECParams *ecParams = NULL;
SECItem pointA = { siBuffer, NULL, 0 };
SECItem pointB = { siBuffer, NULL, 0 };
SECItem pointC = { siBuffer, NULL, 0 };
int len;
#if EC_DEBUG
char mpstr[256];
printf("ECDSA verification called\n");
#endif
/* Check args */
if (!key || !signature || !digest ||
(digest->len != SHA1_LENGTH)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto cleanup;
}
ecParams = &(key->ecParams);
len = (ecParams->fieldID.size + 7) >> 3;
if (signature->len < 2*len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto cleanup;
}
/* Initialize an arena for pointA, pointB and pointC */
if ((arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)) == NULL)
goto cleanup;
SECITEM_AllocItem(arena, &pointA, 2*len + 1);
SECITEM_AllocItem(arena, &pointB, 2*len + 1);
SECITEM_AllocItem(arena, &pointC, 2*len + 1);
if (pointA.data == NULL || pointB.data == NULL || pointC.data == NULL)
goto cleanup;
/* Initialize MPI integers. */
MP_DIGITS(&r_) = 0;
MP_DIGITS(&s_) = 0;
MP_DIGITS(&c) = 0;
MP_DIGITS(&u1) = 0;
MP_DIGITS(&u2) = 0;
MP_DIGITS(&x1) = 0;
MP_DIGITS(&y1) = 0;
MP_DIGITS(&x2) = 0;
MP_DIGITS(&y2) = 0;
MP_DIGITS(&v) = 0;
MP_DIGITS(&n) = 0;
CHECK_MPI_OK( mp_init(&r_) );
CHECK_MPI_OK( mp_init(&s_) );
CHECK_MPI_OK( mp_init(&c) );
CHECK_MPI_OK( mp_init(&u1) );
CHECK_MPI_OK( mp_init(&u2) );
CHECK_MPI_OK( mp_init(&x1) );
CHECK_MPI_OK( mp_init(&y1) );
CHECK_MPI_OK( mp_init(&x2) );
CHECK_MPI_OK( mp_init(&y2) );
CHECK_MPI_OK( mp_init(&v) );
CHECK_MPI_OK( mp_init(&n) );
/*
** Convert received signature (r', s') into MPI integers.
*/
CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, len) );
CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + len, len) );
/*
** ANSI X9.62, Section 5.4.2, Steps 1 and 2
**
** Verify that 0 < r' < n and 0 < s' < n
*/
SECITEM_TO_MPINT(ecParams->order, &n);
if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0)
goto cleanup; /* will return rv == SECFailure */
/*
** ANSI X9.62, Section 5.4.2, Step 3
**
** c = (s')**-1 mod n
*/
CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */
/*
** ANSI X9.62, Section 5.4.2, Step 4
**
** u1 = ((SHA1(M')) * c) mod n
*/
SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */
#if EC_DEBUG
mp_todecimal(&r_, mpstr);
printf("r_: %s (dec)\n", mpstr);
mp_todecimal(&s_, mpstr);
printf("s_: %s (dec)\n", mpstr);
mp_todecimal(&c, mpstr);
printf("c : %s (dec)\n", mpstr);
mp_todecimal(&u1, mpstr);
printf("digest: %s (dec)\n", mpstr);
#endif
CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
/*
** ANSI X9.62, Section 5.4.2, Step 4
**
** u2 = ((r') * c) mod n
*/
CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
/*
** ANSI X9.62, Section 5.4.3, Step 1
**
** Compute u1*G + u2*Q
** Here, A = u1.G B = u2.Q and C = A + B
** If the result, C, is the point at infinity, reject the signature
*/
if ((ec_point_mul(ecParams, &u1, &ecParams->base, &pointA)
== SECFailure) ||
(ec_point_mul(ecParams, &u2, &key->publicValue, &pointB)
== SECFailure) ||
(ec_point_add(ecParams, &pointA, &pointB, &pointC) == SECFailure) ||
ec_point_at_infinity(&pointC)) {
rv = SECFailure;
goto cleanup;
}
CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, len) );
/*
** ANSI X9.62, Section 5.4.4, Step 2
**
** v = x1 mod n
*/
CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
/*
** ANSI X9.62, Section 5.4.4, Step 3
**
** Verification: v == r'
*/
if (mp_cmp(&v, &r_)) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
rv = SECFailure; /* Signature failed to verify. */
} else {
rv = SECSuccess; /* Signature verified. */
}
#if EC_DEBUG
mp_todecimal(&u1, mpstr);
printf("u1: %s (dec)\n", mpstr);
mp_todecimal(&u2, mpstr);
printf("u2: %s (dec)\n", mpstr);
mp_tohex(&x1, mpstr);
printf("x1: %s\n", mpstr);
mp_todecimal(&v, mpstr);
printf("v : %s (dec)\n", mpstr);
#endif
cleanup:
mp_clear(&r_);
mp_clear(&s_);
mp_clear(&c);
mp_clear(&u1);
mp_clear(&u2);
mp_clear(&x1);
mp_clear(&y1);
mp_clear(&x2);
mp_clear(&y2);
mp_clear(&v);
mp_clear(&n);
if (arena) PORT_FreeArena(arena, PR_TRUE);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
#if EC_DEBUG
printf("ECDSA verification %s\n",
(rv == SECSuccess) ? "succeeded" : "failed");
#endif
#else
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
#endif /* NSS_ENABLE_ECC */
return rv;
}

View File

@@ -1,50 +0,0 @@
/*
* 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 the Elliptic Curve Cryptography library.
*
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
*
* Alternatively, the contents of this file may be used under the terms of
* either 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.
*
*/
#ifndef __ec_h_
#define __ec_h_
#define EC_DEBUG 0
#define EC_POINT_FORM_COMPRESSED_Y0 0x02
#define EC_POINT_FORM_COMPRESSED_Y1 0x03
#define EC_POINT_FORM_UNCOMPRESSED 0x04
#define EC_POINT_FORM_HYBRID_Y0 0x06
#define EC_POINT_FORM_HYBRID_Y1 0x07
#define ANSI_X962_CURVE_OID_TOTAL_LEN 10
#define SECG_CURVE_OID_TOTAL_LEN 7
#endif /* __ec_h_ */

View File

@@ -1,120 +0,0 @@
/*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#include <stdio.h>
#include <stdlib.h>
#include <plstr.h>
#include "aglobal.h"
#include "bsafe.h"
#include "secport.h"
void CALL_CONV T_memset (p, c, count)
POINTER p;
int c;
unsigned int count;
{
if (count >= 0)
memset(p, c, count);
}
void CALL_CONV T_memcpy (d, s, count)
POINTER d, s;
unsigned int count;
{
if (count >= 0)
memcpy(d, s, count);
}
void CALL_CONV T_memmove (d, s, count)
POINTER d, s;
unsigned int count;
{
if (count >= 0)
PORT_Memmove(d, s, count);
}
int CALL_CONV T_memcmp (s1, s2, count)
POINTER s1, s2;
unsigned int count;
{
if (count == 0)
return (0);
else
return(memcmp(s1, s2, count));
}
POINTER CALL_CONV T_malloc (size)
unsigned int size;
{
return((POINTER)PORT_Alloc(size == 0 ? 1 : size));
}
POINTER CALL_CONV T_realloc (p, size)
POINTER p;
unsigned int size;
{
POINTER result;
if (p == NULL_PTR)
return (T_malloc(size));
if ((result = (POINTER)PORT_Realloc(p, size == 0 ? 1 : size)) == NULL_PTR)
PORT_Free(p);
return (result);
}
void CALL_CONV T_free (p)
POINTER p;
{
if (p != NULL_PTR)
PORT_Free(p);
}
unsigned int CALL_CONV T_strlen(p)
char *p;
{
return PL_strlen(p);
}
void CALL_CONV T_strcpy(dest, src)
char *dest;
char *src;
{
PL_strcpy(dest, src);
}
int CALL_CONV T_strcmp (a, b)
char *a, *b;
{
return (PL_strcmp (a, b));
}

View File

@@ -1,196 +0,0 @@
/*
* ldvector.c - platform dependent DSO containing freebl implementation.
*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: ldvector.c,v 1.6 2003-02-27 01:31:13 nelsonb%netscape.com Exp $
*/
#include "loader.h"
static const struct FREEBLVectorStr vector = {
sizeof vector,
FREEBL_VERSION,
RSA_NewKey,
RSA_PublicKeyOp,
RSA_PrivateKeyOp,
DSA_NewKey,
DSA_SignDigest,
DSA_VerifyDigest,
DSA_NewKeyFromSeed,
DSA_SignDigestWithSeed,
DH_GenParam,
DH_NewKey,
DH_Derive,
KEA_Derive,
KEA_Verify,
RC4_CreateContext,
RC4_DestroyContext,
RC4_Encrypt,
RC4_Decrypt,
RC2_CreateContext,
RC2_DestroyContext,
RC2_Encrypt,
RC2_Decrypt,
RC5_CreateContext,
RC5_DestroyContext,
RC5_Encrypt,
RC5_Decrypt,
DES_CreateContext,
DES_DestroyContext,
DES_Encrypt,
DES_Decrypt,
AES_CreateContext,
AES_DestroyContext,
AES_Encrypt,
AES_Decrypt,
MD5_Hash,
MD5_HashBuf,
MD5_NewContext,
MD5_DestroyContext,
MD5_Begin,
MD5_Update,
MD5_End,
MD5_FlattenSize,
MD5_Flatten,
MD5_Resurrect,
MD5_TraceState,
MD2_Hash,
MD2_NewContext,
MD2_DestroyContext,
MD2_Begin,
MD2_Update,
MD2_End,
MD2_FlattenSize,
MD2_Flatten,
MD2_Resurrect,
SHA1_Hash,
SHA1_HashBuf,
SHA1_NewContext,
SHA1_DestroyContext,
SHA1_Begin,
SHA1_Update,
SHA1_End,
SHA1_TraceState,
SHA1_FlattenSize,
SHA1_Flatten,
SHA1_Resurrect,
RNG_RNGInit,
RNG_RandomUpdate,
RNG_GenerateGlobalRandomBytes,
RNG_RNGShutdown,
PQG_ParamGen,
PQG_ParamGenSeedLen,
PQG_VerifyParams,
/* End of Version 3.001. */
RSA_PrivateKeyOpDoubleChecked,
RSA_PrivateKeyCheck,
BL_Cleanup,
/* End of Version 3.002. */
SHA256_NewContext,
SHA256_DestroyContext,
SHA256_Begin,
SHA256_Update,
SHA256_End,
SHA256_HashBuf,
SHA256_Hash,
SHA256_TraceState,
SHA256_FlattenSize,
SHA256_Flatten,
SHA256_Resurrect,
SHA512_NewContext,
SHA512_DestroyContext,
SHA512_Begin,
SHA512_Update,
SHA512_End,
SHA512_HashBuf,
SHA512_Hash,
SHA512_TraceState,
SHA512_FlattenSize,
SHA512_Flatten,
SHA512_Resurrect,
SHA384_NewContext,
SHA384_DestroyContext,
SHA384_Begin,
SHA384_Update,
SHA384_End,
SHA384_HashBuf,
SHA384_Hash,
SHA384_TraceState,
SHA384_FlattenSize,
SHA384_Flatten,
SHA384_Resurrect,
/* End of Version 3.003. */
AESKeyWrap_CreateContext,
AESKeyWrap_DestroyContext,
AESKeyWrap_Encrypt,
AESKeyWrap_Decrypt,
/* End of Version 3.004. */
BLAPI_SHVerify,
BLAPI_VerifySelf,
/* End of Version 3.005. */
EC_NewKey,
EC_NewKeyFromSeed,
EC_ValidatePublicKey,
ECDH_Derive,
ECDSA_SignDigest,
ECDSA_VerifyDigest,
ECDSA_SignDigestWithSeed,
/* End of Version 3.006. */
};
const FREEBLVector *
FREEBL_GetVector(void)
{
return &vector;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,386 +0,0 @@
/*
* loader.h - load platform dependent DSO containing freebl implementation.
*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
* Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: loader.h,v 1.9 2003-02-27 01:31:14 nelsonb%netscape.com Exp $
*/
#ifndef _LOADER_H_
#define _LOADER_H_ 1
#include "blapi.h"
#define FREEBL_VERSION 0x0306
struct FREEBLVectorStr {
unsigned short length; /* of this struct in bytes */
unsigned short version; /* of this struct. */
RSAPrivateKey * (* p_RSA_NewKey)(int keySizeInBits,
SECItem * publicExponent);
SECStatus (* p_RSA_PublicKeyOp) (RSAPublicKey * key,
unsigned char * output,
const unsigned char * input);
SECStatus (* p_RSA_PrivateKeyOp)(RSAPrivateKey * key,
unsigned char * output,
const unsigned char * input);
SECStatus (* p_DSA_NewKey)(const PQGParams * params,
DSAPrivateKey ** privKey);
SECStatus (* p_DSA_SignDigest)(DSAPrivateKey * key,
SECItem * signature,
const SECItem * digest);
SECStatus (* p_DSA_VerifyDigest)(DSAPublicKey * key,
const SECItem * signature,
const SECItem * digest);
SECStatus (* p_DSA_NewKeyFromSeed)(const PQGParams *params,
const unsigned char * seed,
DSAPrivateKey **privKey);
SECStatus (* p_DSA_SignDigestWithSeed)(DSAPrivateKey * key,
SECItem * signature,
const SECItem * digest,
const unsigned char * seed);
SECStatus (* p_DH_GenParam)(int primeLen, DHParams ** params);
SECStatus (* p_DH_NewKey)(DHParams * params,
DHPrivateKey ** privKey);
SECStatus (* p_DH_Derive)(SECItem * publicValue,
SECItem * prime,
SECItem * privateValue,
SECItem * derivedSecret,
unsigned int maxOutBytes);
SECStatus (* p_KEA_Derive)(SECItem *prime,
SECItem *public1,
SECItem *public2,
SECItem *private1,
SECItem *private2,
SECItem *derivedSecret);
PRBool (* p_KEA_Verify)(SECItem *Y, SECItem *prime, SECItem *subPrime);
RC4Context * (* p_RC4_CreateContext)(const unsigned char *key, int len);
void (* p_RC4_DestroyContext)(RC4Context *cx, PRBool freeit);
SECStatus (* p_RC4_Encrypt)(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (* p_RC4_Decrypt)(RC4Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
RC2Context * (* p_RC2_CreateContext)(const unsigned char *key,
unsigned int len, const unsigned char *iv,
int mode, unsigned effectiveKeyLen);
void (* p_RC2_DestroyContext)(RC2Context *cx, PRBool freeit);
SECStatus (* p_RC2_Encrypt)(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (* p_RC2_Decrypt)(RC2Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
RC5Context *(* p_RC5_CreateContext)(const SECItem *key, unsigned int rounds,
unsigned int wordSize, const unsigned char *iv, int mode);
void (* p_RC5_DestroyContext)(RC5Context *cx, PRBool freeit);
SECStatus (* p_RC5_Encrypt)(RC5Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (* p_RC5_Decrypt)(RC5Context *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
DESContext *(* p_DES_CreateContext)(const unsigned char *key,
const unsigned char *iv,
int mode, PRBool encrypt);
void (* p_DES_DestroyContext)(DESContext *cx, PRBool freeit);
SECStatus (* p_DES_Encrypt)(DESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (* p_DES_Decrypt)(DESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
AESContext * (* p_AES_CreateContext)(const unsigned char *key,
const unsigned char *iv,
int mode, int encrypt, unsigned int keylen,
unsigned int blocklen);
void (* p_AES_DestroyContext)(AESContext *cx, PRBool freeit);
SECStatus (* p_AES_Encrypt)(AESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (* p_AES_Decrypt)(AESContext *cx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (* p_MD5_Hash)(unsigned char *dest, const char *src);
SECStatus (* p_MD5_HashBuf)(unsigned char *dest, const unsigned char *src,
uint32 src_length);
MD5Context *(* p_MD5_NewContext)(void);
void (* p_MD5_DestroyContext)(MD5Context *cx, PRBool freeit);
void (* p_MD5_Begin)(MD5Context *cx);
void (* p_MD5_Update)(MD5Context *cx,
const unsigned char *input, unsigned int inputLen);
void (* p_MD5_End)(MD5Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
unsigned int (* p_MD5_FlattenSize)(MD5Context *cx);
SECStatus (* p_MD5_Flatten)(MD5Context *cx,unsigned char *space);
MD5Context * (* p_MD5_Resurrect)(unsigned char *space, void *arg);
void (* p_MD5_TraceState)(MD5Context *cx);
SECStatus (* p_MD2_Hash)(unsigned char *dest, const char *src);
MD2Context *(* p_MD2_NewContext)(void);
void (* p_MD2_DestroyContext)(MD2Context *cx, PRBool freeit);
void (* p_MD2_Begin)(MD2Context *cx);
void (* p_MD2_Update)(MD2Context *cx,
const unsigned char *input, unsigned int inputLen);
void (* p_MD2_End)(MD2Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
unsigned int (* p_MD2_FlattenSize)(MD2Context *cx);
SECStatus (* p_MD2_Flatten)(MD2Context *cx,unsigned char *space);
MD2Context * (* p_MD2_Resurrect)(unsigned char *space, void *arg);
SECStatus (* p_SHA1_Hash)(unsigned char *dest, const char *src);
SECStatus (* p_SHA1_HashBuf)(unsigned char *dest, const unsigned char *src,
uint32 src_length);
SHA1Context *(* p_SHA1_NewContext)(void);
void (* p_SHA1_DestroyContext)(SHA1Context *cx, PRBool freeit);
void (* p_SHA1_Begin)(SHA1Context *cx);
void (* p_SHA1_Update)(SHA1Context *cx, const unsigned char *input,
unsigned int inputLen);
void (* p_SHA1_End)(SHA1Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
void (* p_SHA1_TraceState)(SHA1Context *cx);
unsigned int (* p_SHA1_FlattenSize)(SHA1Context *cx);
SECStatus (* p_SHA1_Flatten)(SHA1Context *cx,unsigned char *space);
SHA1Context * (* p_SHA1_Resurrect)(unsigned char *space, void *arg);
SECStatus (* p_RNG_RNGInit)(void);
SECStatus (* p_RNG_RandomUpdate)(const void *data, size_t bytes);
SECStatus (* p_RNG_GenerateGlobalRandomBytes)(void *dest, size_t len);
void (* p_RNG_RNGShutdown)(void);
SECStatus (* p_PQG_ParamGen)(unsigned int j, PQGParams **pParams,
PQGVerify **pVfy);
SECStatus (* p_PQG_ParamGenSeedLen)( unsigned int j, unsigned int seedBytes,
PQGParams **pParams, PQGVerify **pVfy);
SECStatus (* p_PQG_VerifyParams)(const PQGParams *params,
const PQGVerify *vfy, SECStatus *result);
/* Version 3.001 came to here */
SECStatus (* p_RSA_PrivateKeyOpDoubleChecked)(RSAPrivateKey *key,
unsigned char *output,
const unsigned char *input);
SECStatus (* p_RSA_PrivateKeyCheck)(RSAPrivateKey *key);
void (* p_BL_Cleanup)(void);
/* Version 3.002 came to here */
SHA256Context *(* p_SHA256_NewContext)(void);
void (* p_SHA256_DestroyContext)(SHA256Context *cx, PRBool freeit);
void (* p_SHA256_Begin)(SHA256Context *cx);
void (* p_SHA256_Update)(SHA256Context *cx, const unsigned char *input,
unsigned int inputLen);
void (* p_SHA256_End)(SHA256Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
SECStatus (* p_SHA256_HashBuf)(unsigned char *dest, const unsigned char *src,
uint32 src_length);
SECStatus (* p_SHA256_Hash)(unsigned char *dest, const char *src);
void (* p_SHA256_TraceState)(SHA256Context *cx);
unsigned int (* p_SHA256_FlattenSize)(SHA256Context *cx);
SECStatus (* p_SHA256_Flatten)(SHA256Context *cx,unsigned char *space);
SHA256Context * (* p_SHA256_Resurrect)(unsigned char *space, void *arg);
SHA512Context *(* p_SHA512_NewContext)(void);
void (* p_SHA512_DestroyContext)(SHA512Context *cx, PRBool freeit);
void (* p_SHA512_Begin)(SHA512Context *cx);
void (* p_SHA512_Update)(SHA512Context *cx, const unsigned char *input,
unsigned int inputLen);
void (* p_SHA512_End)(SHA512Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
SECStatus (* p_SHA512_HashBuf)(unsigned char *dest, const unsigned char *src,
uint32 src_length);
SECStatus (* p_SHA512_Hash)(unsigned char *dest, const char *src);
void (* p_SHA512_TraceState)(SHA512Context *cx);
unsigned int (* p_SHA512_FlattenSize)(SHA512Context *cx);
SECStatus (* p_SHA512_Flatten)(SHA512Context *cx,unsigned char *space);
SHA512Context * (* p_SHA512_Resurrect)(unsigned char *space, void *arg);
SHA384Context *(* p_SHA384_NewContext)(void);
void (* p_SHA384_DestroyContext)(SHA384Context *cx, PRBool freeit);
void (* p_SHA384_Begin)(SHA384Context *cx);
void (* p_SHA384_Update)(SHA384Context *cx, const unsigned char *input,
unsigned int inputLen);
void (* p_SHA384_End)(SHA384Context *cx, unsigned char *digest,
unsigned int *digestLen, unsigned int maxDigestLen);
SECStatus (* p_SHA384_HashBuf)(unsigned char *dest, const unsigned char *src,
uint32 src_length);
SECStatus (* p_SHA384_Hash)(unsigned char *dest, const char *src);
void (* p_SHA384_TraceState)(SHA384Context *cx);
unsigned int (* p_SHA384_FlattenSize)(SHA384Context *cx);
SECStatus (* p_SHA384_Flatten)(SHA384Context *cx,unsigned char *space);
SHA384Context * (* p_SHA384_Resurrect)(unsigned char *space, void *arg);
/* Version 3.003 came to here */
AESKeyWrapContext * (* p_AESKeyWrap_CreateContext)(const unsigned char *key,
const unsigned char *iv, int encrypt, unsigned int keylen);
void (* p_AESKeyWrap_DestroyContext)(AESKeyWrapContext *cx, PRBool freeit);
SECStatus (* p_AESKeyWrap_Encrypt)(AESKeyWrapContext *cx,
unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
SECStatus (* p_AESKeyWrap_Decrypt)(AESKeyWrapContext *cx,
unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen);
/* Version 3.004 came to here */
PRBool (*p_BLAPI_SHVerify)(const char *name, PRFuncPtr addr);
PRBool (*p_BLAPI_VerifySelf)(const char *name);
/* Version 3.005 came to here */
SECStatus (* p_EC_NewKey)(ECParams * params,
ECPrivateKey ** privKey);
SECStatus (* p_EC_NewKeyFromSeed)(ECParams * params,
ECPrivateKey ** privKey,
const unsigned char * seed,
int seedlen);
SECStatus (* p_EC_ValidatePublicKey)(ECParams * params,
SECItem * publicValue);
SECStatus (* p_ECDH_Derive)(SECItem * publicValue,
ECParams * params,
SECItem * privateValue,
PRBool withCofactor,
SECItem * derivedSecret);
SECStatus (* p_ECDSA_SignDigest)(ECPrivateKey * key,
SECItem * signature,
const SECItem * digest);
SECStatus (* p_ECDSA_VerifyDigest)(ECPublicKey * key,
const SECItem * signature,
const SECItem * digest);
SECStatus (* p_ECDSA_SignDigestWithSeed)(ECPrivateKey * key,
SECItem * signature,
const SECItem * digest,
const unsigned char * seed,
const int seedlen);
/* Version 3.006 came to here */
};
typedef struct FREEBLVectorStr FREEBLVector;
SEC_BEGIN_PROTOS
typedef const FREEBLVector * FREEBLGetVectorFn(void);
extern FREEBLGetVectorFn FREEBL_GetVector;
SEC_END_PROTOS
#endif

View File

@@ -1,315 +0,0 @@
/*
* 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 the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#ifdef notdef
#include "xp_core.h"
#include "xp_file.h"
#endif
#include "secrng.h"
#include "mcom_db.h"
#ifdef XP_MAC
#include <Events.h>
#include <OSUtils.h>
#include <QDOffscreen.h>
#include <PPCToolbox.h>
#include <Processes.h>
#include <LowMem.h>
#include <Scrap.h>
/* Static prototypes */
static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen);
void FE_ReadScreen();
static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
{
union endianness {
int32 i;
char c[4];
} u;
if (srclen <= dstlen) {
memcpy(dst, src, srclen);
return srclen;
}
u.i = 0x01020304;
if (u.c[0] == 0x01) {
/* big-endian case */
memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
} else {
/* little-endian case */
memcpy(dst, src, dstlen);
}
return dstlen;
}
size_t RNG_GetNoise(void *buf, size_t maxbytes)
{
UnsignedWide microTickCount;
Microseconds(&microTickCount);
return CopyLowBits(buf, maxbytes, &microTickCount, sizeof(microTickCount));
}
void RNG_FileForRNG(const char *filename)
{
unsigned char buffer[BUFSIZ];
size_t bytes;
#ifdef notdef /*sigh*/
XP_File file;
unsigned long totalFileBytes = 0;
if (filename == NULL) /* For now, read in global history if filename is null */
file = XP_FileOpen(NULL, xpGlobalHistory,XP_FILE_READ_BIN);
else
file = XP_FileOpen(NULL, xpURL,XP_FILE_READ_BIN);
if (file != NULL) {
for (;;) {
bytes = XP_FileRead(buffer, sizeof(buffer), file);
if (bytes == 0) break;
RNG_RandomUpdate( buffer, bytes);
totalFileBytes += bytes;
if (totalFileBytes > 100*1024) break; /* No more than 100 K */
}
XP_FileClose(file);
}
#endif
/*
* Pass yet another snapshot of our highest resolution clock into
* the hash function.
*/
bytes = RNG_GetNoise(buffer, sizeof(buffer));
RNG_RandomUpdate(buffer, sizeof(buffer));
}
void RNG_SystemInfoForRNG()
{
/* Time */
{
unsigned long sec;
size_t bytes;
GetDateTime(&sec); /* Current time since 1970 */
RNG_RandomUpdate( &sec, sizeof(sec));
bytes = RNG_GetNoise(&sec, sizeof(sec));
RNG_RandomUpdate(&sec, bytes);
}
/* User specific variables */
{
MachineLocation loc;
ReadLocation(&loc);
RNG_RandomUpdate( &loc, sizeof(loc));
}
#if !TARGET_CARBON
/* User name */
{
unsigned long userRef;
Str32 userName;
GetDefaultUser(&userRef, userName);
RNG_RandomUpdate( &userRef, sizeof(userRef));
RNG_RandomUpdate( userName, sizeof(userName));
}
#endif
/* Mouse location */
{
Point mouseLoc;
GetMouse(&mouseLoc);
RNG_RandomUpdate( &mouseLoc, sizeof(mouseLoc));
}
/* Keyboard time threshold */
{
SInt16 keyTresh = LMGetKeyThresh();
RNG_RandomUpdate( &keyTresh, sizeof(keyTresh));
}
/* Last key pressed */
{
SInt8 keyLast;
keyLast = LMGetKbdLast();
RNG_RandomUpdate( &keyLast, sizeof(keyLast));
}
/* Volume */
{
UInt8 volume = LMGetSdVolume();
RNG_RandomUpdate( &volume, sizeof(volume));
}
#if !TARGET_CARBON
/* Current directory */
{
SInt32 dir = LMGetCurDirStore();
RNG_RandomUpdate( &dir, sizeof(dir));
}
#endif
/* Process information about all the processes in the machine */
{
ProcessSerialNumber process;
ProcessInfoRec pi;
process.highLongOfPSN = process.lowLongOfPSN = kNoProcess;
while (GetNextProcess(&process) == noErr)
{
FSSpec fileSpec;
pi.processInfoLength = sizeof(ProcessInfoRec);
pi.processName = NULL;
pi.processAppSpec = &fileSpec;
GetProcessInformation(&process, &pi);
RNG_RandomUpdate( &pi, sizeof(pi));
RNG_RandomUpdate( &fileSpec, sizeof(fileSpec));
}
}
#if !TARGET_CARBON
/* Heap */
{
THz zone = LMGetTheZone();
RNG_RandomUpdate( &zone, sizeof(zone));
}
#endif
/* Screen */
{
GDHandle h = GetMainDevice(); /* GDHandle is **GDevice */
RNG_RandomUpdate( *h, sizeof(GDevice));
}
#if !TARGET_CARBON
/* Scrap size */
{
SInt32 scrapSize = LMGetScrapSize();
RNG_RandomUpdate( &scrapSize, sizeof(scrapSize));
}
/* Scrap count */
{
SInt16 scrapCount = LMGetScrapCount();
RNG_RandomUpdate( &scrapCount, sizeof(scrapCount));
}
#else
{
ScrapRef scrap;
if (GetCurrentScrap(&scrap) == noErr) {
UInt32 flavorCount;
if (GetScrapFlavorCount(scrap, &flavorCount) == noErr) {
ScrapFlavorInfo* flavorInfo = (ScrapFlavorInfo*) malloc(flavorCount * sizeof(ScrapFlavorInfo));
if (flavorInfo != NULL) {
if (GetScrapFlavorInfoList(scrap, &flavorCount, flavorInfo) == noErr) {
UInt32 i;
RNG_RandomUpdate(&flavorCount, sizeof(flavorCount));
for (i = 0; i < flavorCount; ++i) {
Size flavorSize;
if (GetScrapFlavorSize(scrap, flavorInfo[i].flavorType, &flavorSize) == noErr)
RNG_RandomUpdate(&flavorSize, sizeof(flavorSize));
}
}
free(flavorInfo);
}
}
}
}
#endif
/* File stuff, last modified, etc. */
{
HParamBlockRec pb;
GetVolParmsInfoBuffer volInfo;
pb.ioParam.ioVRefNum = 0;
pb.ioParam.ioNamePtr = nil;
pb.ioParam.ioBuffer = (Ptr) &volInfo;
pb.ioParam.ioReqCount = sizeof(volInfo);
PBHGetVolParmsSync(&pb);
RNG_RandomUpdate( &volInfo, sizeof(volInfo));
}
#if !TARGET_CARBON
/* Event queue */
{
EvQElPtr eventQ;
for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead;
eventQ;
eventQ = (EvQElPtr)eventQ->qLink)
RNG_RandomUpdate( &eventQ->evtQWhat, sizeof(EventRecord));
}
#endif
FE_ReadScreen();
RNG_FileForRNG(NULL);
}
void FE_ReadScreen()
{
UInt16 coords[4];
PixMapHandle pmap;
GDHandle gh;
UInt16 screenHeight;
UInt16 screenWidth; /* just what they say */
UInt32 bytesToRead; /* number of bytes we're giving */
UInt32 offset; /* offset into the graphics buffer */
UInt16 rowBytes;
UInt32 rowsToRead;
float bytesPerPixel; /* dependent on buffer depth */
Ptr p; /* temporary */
UInt16 x, y, w, h;
gh = LMGetMainDevice();
if ( !gh )
return;
pmap = (**gh).gdPMap;
if ( !pmap )
return;
RNG_GenerateGlobalRandomBytes( coords, sizeof( coords ) );
/* make x and y inside the screen rect */
screenHeight = (**pmap).bounds.bottom - (**pmap).bounds.top;
screenWidth = (**pmap).bounds.right - (**pmap).bounds.left;
x = coords[0] % screenWidth;
y = coords[1] % screenHeight;
w = ( coords[2] & 0x7F ) | 0x40; /* Make sure that w is in the range 64..128 */
h = ( coords[3] & 0x7F ) | 0x40; /* same for h */
bytesPerPixel = (**pmap).pixelSize / 8;
rowBytes = (**pmap).rowBytes & 0x7FFF;
/* starting address */
offset = ( rowBytes * y ) + (UInt32)( (float)x * bytesPerPixel );
/* don't read past the end of the pixmap's rowbytes */
bytesToRead = PR_MIN( (UInt32)( w * bytesPerPixel ),
(UInt32)( rowBytes - ( x * bytesPerPixel ) ) );
/* don't read past the end of the graphics device pixmap */
rowsToRead = PR_MIN( h,
( screenHeight - y ) );
p = GetPixBaseAddr( pmap ) + offset;
while ( rowsToRead-- )
{
RNG_RandomUpdate( p, bytesToRead );
p += rowBytes;
}
}
#endif

View File

@@ -1,146 +0,0 @@
#
# 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 the Netscape security libraries.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Portions created by Sun Microsystems, Inc. are Copyright (C) 2003
# Sun Microsystems, Inc. All Rights Reserved.
#
# Contributor(s):
# Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU General Public License Version 2 or later (the
# "GPL"), in which case the provisions of the GPL are applicable
# instead of those above. If you wish to allow use of your
# version of this file only under the terms of the GPL and not to
# allow others to use your version of this file under the MPL,
# indicate your decision by deleting the provisions above and
# replace them with the notice and other provisions required by
# the GPL. If you do not delete the provisions above, a recipient
# may use your version of this file under either the MPL or the
# GPL.
#
CORE_DEPTH = ../../..
MODULE = nss
ifndef FREEBL_RECURSIVE_BUILD
LIBRARY_NAME = freebl
else
ifdef USE_PURE_32
CORE_DEPTH = ../../../..
LIBRARY_NAME = freebl_pure32
else
LIBRARY_NAME = freebl_hybrid
endif
endif
# same version as rest of freebl
LIBRARY_VERSION = _3
DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\"
REQUIRES =
EXPORTS = \
blapi.h \
blapit.h \
secrng.h \
shsign.h \
$(NULL)
PRIVATE_EXPORTS = \
secmpi.h \
ec.h \
$(NULL)
MPI_HDRS = mpi-config.h mpi.h mpi-priv.h mplogic.h mpprime.h logtab.h mp_gf2m.h
MPI_SRCS = mpprime.c mpmontg.c mplogic.c mpi.c mp_gf2m.c
ifdef MOZILLA_BSAFE_BUILD
CSRCS = \
fblstdlib.c \
sha_fast.c \
md2.c \
md5.c \
blapi_bsf.c \
$(MPI_SRCS) \
dh.c \
$(NULL)
else
CSRCS = \
ldvector.c \
prng_fips1861.c \
sysrand.c \
sha_fast.c \
md2.c \
md5.c \
sha512.c \
alg2268.c \
arcfour.c \
arcfive.c \
desblapi.c \
des.c \
rijndael.c \
aeskeywrap.c \
dh.c \
ec.c \
GFp_ecl.c \
GF2m_ecl.c \
pqg.c \
dsa.c \
rsa.c \
shvfy.c \
$(MPI_SRCS) \
$(NULL)
endif
ALL_CSRCS := $(CSRCS)
ALL_HDRS = \
blapi.h \
blapit.h \
des.h \
ec.h \
GFp_ecl.h \
GF2m_ecl.h \
loader.h \
rijndael.h \
secmpi.h \
sha.h \
sha_fast.h \
shsign.h \
vis_proto.h \
$(NULL)
ifdef AES_GEN_TBL
DEFINES += -DRIJNDAEL_GENERATE_TABLES
else
ifdef AES_GEN_TBL_M
DEFINES += -DRIJNDAEL_GENERATE_TABLES_MACRO
else
ifdef AES_GEN_VAL
DEFINES += -DRIJNDAEL_GENERATE_VALUES
else
ifdef AES_GEN_VAL_M
DEFINES += -DRIJNDAEL_GENERATE_VALUES_MACRO
else
DEFINES += -DRIJNDAEL_INCLUDE_TABLES
endif
endif
endif
endif

View File

@@ -1,39 +0,0 @@
#
# 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 the Netscape security libraries.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU General Public License Version 2 or later (the
# "GPL"), in which case the provisions of the GPL are applicable
# instead of those above. If you wish to allow use of your
# version of this file only under the terms of the GPL and not to
# allow others to use your version of this file under the MPL,
# indicate your decision by deleting the provisions above and
# replace them with the notice and other provisions required by
# the GPL. If you do not delete the provisions above, a recipient
# may use your version of this file under either the MPL or the
# GPL.
#
libfreebl_3.so {
global:
FREEBL_GetVector;
local:
*;
};