Compare commits
1 Commits
CacheInteg
...
tags/Last1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
973a54719f |
5
mozilla/js/src/liveconnect/MANIFEST
Normal file
5
mozilla/js/src/liveconnect/MANIFEST
Normal file
@@ -0,0 +1,5 @@
|
||||
# This is a list of local files which get copied to the mozilla:dist directory
|
||||
#
|
||||
|
||||
jsjava.h
|
||||
nsILiveconnect.h
|
||||
89
mozilla/js/src/liveconnect/Makefile
Normal file
89
mozilla/js/src/liveconnect/Makefile
Normal 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
|
||||
|
||||
90
mozilla/js/src/liveconnect/Makefile.in
Normal file
90
mozilla/js/src/liveconnect/Makefile.in
Normal 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
|
||||
|
||||
@@ -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
|
||||
102
mozilla/js/src/liveconnect/_jni/netscape_javascript_JSObject.h
Normal file
102
mozilla/js/src/liveconnect/_jni/netscape_javascript_JSObject.h
Normal 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
|
||||
65
mozilla/js/src/liveconnect/classes/Makefile
Normal file
65
mozilla/js/src/liveconnect/classes/Makefile
Normal 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:
|
||||
70
mozilla/js/src/liveconnect/classes/Makefile.in
Normal file
70
mozilla/js/src/liveconnect/classes/Makefile.in
Normal 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:
|
||||
78
mozilla/js/src/liveconnect/classes/makefile.win
Normal file
78
mozilla/js/src/liveconnect/classes/makefile.win
Normal 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:/=.)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
876
mozilla/js/src/liveconnect/jsj.c
Normal file
876
mozilla/js/src/liveconnect/jsj.c
Normal 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 */
|
||||
76
mozilla/js/src/liveconnect/jsj1640.rc
Normal file
76
mozilla/js/src/liveconnect/jsj1640.rc
Normal 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
|
||||
|
||||
1243
mozilla/js/src/liveconnect/jsj_JSObject.c
Normal file
1243
mozilla/js/src/liveconnect/jsj_JSObject.c
Normal file
File diff suppressed because it is too large
Load Diff
403
mozilla/js/src/liveconnect/jsj_JavaArray.c
Normal file
403
mozilla/js/src/liveconnect/jsj_JavaArray.c
Normal 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;
|
||||
}
|
||||
|
||||
586
mozilla/js/src/liveconnect/jsj_JavaClass.c
Normal file
586
mozilla/js/src/liveconnect/jsj_JavaClass.c
Normal 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();
|
||||
}
|
||||
|
||||
134
mozilla/js/src/liveconnect/jsj_JavaMember.c
Normal file
134
mozilla/js/src/liveconnect/jsj_JavaMember.c
Normal 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;
|
||||
}
|
||||
686
mozilla/js/src/liveconnect/jsj_JavaObject.c
Normal file
686
mozilla/js/src/liveconnect/jsj_JavaObject.c
Normal 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();
|
||||
}
|
||||
500
mozilla/js/src/liveconnect/jsj_JavaPackage.c
Normal file
500
mozilla/js/src/liveconnect/jsj_JavaPackage.c
Normal 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;
|
||||
}
|
||||
180
mozilla/js/src/liveconnect/jsj_array.c
Normal file
180
mozilla/js/src/liveconnect/jsj_array.c
Normal 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;
|
||||
}
|
||||
|
||||
605
mozilla/js/src/liveconnect/jsj_class.c
Normal file
605
mozilla/js/src/liveconnect/jsj_class.c
Normal 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;
|
||||
}
|
||||
806
mozilla/js/src/liveconnect/jsj_convert.c
Normal file
806
mozilla/js/src/liveconnect/jsj_convert.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
383
mozilla/js/src/liveconnect/jsj_field.c
Normal file
383
mozilla/js/src/liveconnect/jsj_field.c
Normal 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;
|
||||
}
|
||||
487
mozilla/js/src/liveconnect/jsj_hash.c
Normal file
487
mozilla/js/src/liveconnect/jsj_hash.c
Normal 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;
|
||||
}
|
||||
141
mozilla/js/src/liveconnect/jsj_hash.h
Normal file
141
mozilla/js/src/liveconnect/jsj_hash.h
Normal 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___ */
|
||||
1164
mozilla/js/src/liveconnect/jsj_method.c
Normal file
1164
mozilla/js/src/liveconnect/jsj_method.c
Normal file
File diff suppressed because it is too large
Load Diff
0
mozilla/js/src/liveconnect/jsj_nodl.c
Normal file
0
mozilla/js/src/liveconnect/jsj_nodl.c
Normal file
552
mozilla/js/src/liveconnect/jsj_private.h
Normal file
552
mozilla/js/src/liveconnect/jsj_private.h
Normal 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 */
|
||||
361
mozilla/js/src/liveconnect/jsj_utils.c
Normal file
361
mozilla/js/src/liveconnect/jsj_utils.c
Normal 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;
|
||||
}
|
||||
264
mozilla/js/src/liveconnect/jsjava.h
Normal file
264
mozilla/js/src/liveconnect/jsjava.h
Normal 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 */
|
||||
182
mozilla/js/src/liveconnect/makefile.win
Normal file
182
mozilla/js/src/liveconnect/makefile.win
Normal 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
|
||||
111
mozilla/js/src/liveconnect/netscape_javascript_JSObject.h
Normal file
111
mozilla/js/src/liveconnect/netscape_javascript_JSObject.h
Normal 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
|
||||
567
mozilla/js/src/liveconnect/nsCLiveconnect.cpp
Normal file
567
mozilla/js/src/liveconnect/nsCLiveconnect.cpp
Normal 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()
|
||||
{
|
||||
}
|
||||
|
||||
166
mozilla/js/src/liveconnect/nsCLiveconnect.h
Normal file
166
mozilla/js/src/liveconnect/nsCLiveconnect.h
Normal 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___
|
||||
168
mozilla/js/src/liveconnect/nsCLiveconnectFactory.cpp
Normal file
168
mozilla/js/src/liveconnect/nsCLiveconnectFactory.cpp
Normal 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
mozilla/js/src/liveconnect/nsCLiveconnectFactory.h
Normal file
59
mozilla/js/src/liveconnect/nsCLiveconnectFactory.h
Normal 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___
|
||||
157
mozilla/js/src/liveconnect/nsILiveconnect.h
Normal file
157
mozilla/js/src/liveconnect/nsILiveconnect.h
Normal 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___
|
||||
File diff suppressed because it is too large
Load Diff
38
mozilla/netwerk/cache/Makefile.in
vendored
38
mozilla/netwerk/cache/Makefile.in
vendored
@@ -1,38 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = \
|
||||
public \
|
||||
memcache \
|
||||
filecache \
|
||||
mgr \
|
||||
build \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
33
mozilla/netwerk/cache/Makefile.win
vendored
33
mozilla/netwerk/cache/Makefile.win
vendored
@@ -1,33 +0,0 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
|
||||
DEPTH=..\..
|
||||
DIRS= \
|
||||
public \
|
||||
mgr \
|
||||
memcache \
|
||||
filecache \
|
||||
build \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
54
mozilla/netwerk/cache/build/Makefile.in
vendored
54
mozilla/netwerk/cache/build/Makefile.in
vendored
@@ -1,54 +0,0 @@
|
||||
#
|
||||
# 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 = nkcacke
|
||||
LIBRARY_NAME = necko_cache
|
||||
IS_COMPONENT = 1
|
||||
|
||||
CPPSRCS = nsNetDataCacheModule.cpp
|
||||
|
||||
SHARED_LIBRARY_LIBS = \
|
||||
$(DIST)/lib/libnkcachemgr_s.a \
|
||||
$(DIST)/lib/libnkfilecache_s.a \
|
||||
$(DIST)/lib/libnkmemcache_s.a \
|
||||
$(DIST)/lib/libmozdbm_s.a \
|
||||
$(DIST)/lib/libxpcomio_s.a \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(DEPTH)/netwerk/cache/memcache \
|
||||
-I$(DEPTH)/netwerk/cache/filecache \
|
||||
-I$(DEPTH)/netwerk/cache/mgr \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(MKSHLIB_FORCE_ALL) \
|
||||
$(SHARED_LIBRARY_LIBS) \
|
||||
$(MKSHLIB_UNFORCE_ALL) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
$(LIBRARY) $(SHARED_LIBRARY): $(SHARED_LIBRARY_LIBS) Makefile
|
||||
|
||||
51
mozilla/netwerk/cache/build/makefile.win
vendored
51
mozilla/netwerk/cache/build/makefile.win
vendored
@@ -1,51 +0,0 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
|
||||
DEPTH=..\..\..
|
||||
MODULE=nkcache
|
||||
|
||||
MAKE_OBJ_TYPE=DLL
|
||||
DLLNAME=nkcache
|
||||
DLL=.\$(OBJDIR)\$(DLLNAME).dll
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsNetDataCacheModule.obj \
|
||||
$(NULL)
|
||||
|
||||
LLIBS= \
|
||||
$(DIST)\lib\nkcachemgr_s.lib \
|
||||
$(DIST)\lib\nkfilecache_s.lib \
|
||||
$(DIST)\lib\nkmemcache_s.lib \
|
||||
$(DIST)\lib\dbm32.lib \
|
||||
$(DIST)\lib\xpcom.lib \
|
||||
$(LIBNSPR)
|
||||
|
||||
INCS = $(INCS) \
|
||||
-I$(DEPTH)\netwerk\cache\memcache \
|
||||
-I$(DEPTH)\netwerk\cache\filecache \
|
||||
-I$(DEPTH)\netwerk\cache\mgr \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(DLL)
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).dll $(DIST)\bin\components
|
||||
$(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME).lib $(DIST)\lib
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIModule.h"
|
||||
#include "nscore.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataCacheManager.h"
|
||||
#include "nsMemCacheCID.h"
|
||||
#include "nsMemCache.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsCacheManager.h"
|
||||
|
||||
// Factory method to create a new nsMemCache instance. Used
|
||||
// by nsNetDataCacheModule
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMemCache, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNetDiskCache, Init)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCacheManager, Init)
|
||||
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ "Memory Cache", NS_MEM_CACHE_FACTORY_CID, NS_NETWORK_MEMORY_CACHE_PROGID, nsMemCacheConstructor },
|
||||
{ "File Cache", NS_NETDISKCACHE_CID, NS_NETWORK_FILE_CACHE_PROGID, nsNetDiskCacheConstructor },
|
||||
{ "Cache Manager",NS_CACHE_MANAGER_CID, NS_NETWORK_CACHE_MANAGER_PROGID,nsCacheManagerConstructor }
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE("Network Data Cache", components)
|
||||
60
mozilla/netwerk/cache/filecache/Makefile.in
vendored
60
mozilla/netwerk/cache/filecache/Makefile.in
vendored
@@ -1,60 +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 Mozilla Communicator.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Intel Corp.
|
||||
# Portions created by Intel Corp. are
|
||||
# Copyright (C) 1999, 1999 Intel Corp. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
# Carl Wong <carl.wong@intel.com>
|
||||
#
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkfilecache_s
|
||||
|
||||
REQUIRES = nspr dbm
|
||||
|
||||
EXTRA_DSO_LDOPTS += -L$(DIST)/lib -lmozdbm_s
|
||||
|
||||
EXPORTS=nsNetDiskCacheCID.h \
|
||||
nsNetDiskCache.h \
|
||||
nsIDBAccessor.h \
|
||||
nsDBAccessor.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsDBAccessor.cpp\
|
||||
nsDBEnumerator.cpp \
|
||||
nsNetDiskCache.cpp \
|
||||
nsDiskCacheRecord.cpp \
|
||||
nsDiskCacheRecordChannel.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_LIBS = $(NSPR_LIBS)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
override NO_SHARED_LIB=1
|
||||
override NO_STATIC_LIB=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
44
mozilla/netwerk/cache/filecache/makefile.win
vendored
44
mozilla/netwerk/cache/filecache/makefile.win
vendored
@@ -1,44 +0,0 @@
|
||||
#!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.mak>
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkfilecache_s
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsDBAccessor.obj \
|
||||
.\$(OBJDIR)\nsDBEnumerator.obj \
|
||||
.\$(OBJDIR)\nsNetDiskCache.obj \
|
||||
.\$(OBJDIR)\nsDiskCacheRecord.obj \
|
||||
.\$(OBJDIR)\nsDiskCacheRecordChannel.obj \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS=nsNetDiskCacheCID.h
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -rf $(OBJDIR)
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
|
||||
416
mozilla/netwerk/cache/filecache/nsDBAccessor.cpp
vendored
416
mozilla/netwerk/cache/filecache/nsDBAccessor.cpp
vendored
@@ -1,416 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* nsIDBAccessor is a interface that shields all the direct database access
|
||||
* method from nsNetDiskCache.
|
||||
*
|
||||
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
|
||||
* uses dbm(Berkely) as the database.
|
||||
*
|
||||
* a nsDiskCacheRecord is mapped into two entries in the database,
|
||||
* key->recordID
|
||||
* recordID->metadata
|
||||
*/
|
||||
|
||||
#include "nsDBAccessor.h"
|
||||
#include "nscore.h"
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "plhash.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
nsDBAccessor::nsDBAccessor() :
|
||||
mDB(0) ,
|
||||
mDBFile(0) ,
|
||||
mSessionID(0) ,
|
||||
mSessionCntr(0) ,
|
||||
mDBFilesize(0)
|
||||
{
|
||||
mLastSyncTime = PR_IntervalNow() ;
|
||||
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsDBAccessor::~nsDBAccessor()
|
||||
{
|
||||
Shutdown() ;
|
||||
}
|
||||
|
||||
//
|
||||
// Implement nsISupports methods
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(nsDBAccessor, NS_GET_IID(nsIDBAccessor))
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// nsIDBAccessor methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Init(nsIFileSpec* dbfile)
|
||||
{
|
||||
char* dbname ;
|
||||
|
||||
// this should cover all platforms.
|
||||
dbfile->GetNativePath(&dbname) ;
|
||||
|
||||
mDBFile = dbfile ;
|
||||
|
||||
// FUR - how is page size chosen ? It's worth putting a comment
|
||||
// in here about the possible usefulness of tuning these parameters
|
||||
HASHINFO hash_info = {
|
||||
16*1024 , /* bucket size */
|
||||
0 , /* fill factor */
|
||||
0 , /* number of elements */
|
||||
0 , /* bytes to cache */
|
||||
0 , /* hash function */
|
||||
0} ; /* byte order */
|
||||
|
||||
mDB = dbopen(dbname,
|
||||
O_RDWR | O_CREAT ,
|
||||
0600 ,
|
||||
DB_HASH ,
|
||||
& hash_info) ;
|
||||
|
||||
nsCRT::free(dbname) ;
|
||||
|
||||
if(!mDB)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
// set mSessionID
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, SessionKey) ;
|
||||
db_key.size = PL_strlen(SessionKey) ;
|
||||
|
||||
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
if(status == -1) {
|
||||
NS_ERROR("ERROR: failed get session id in database.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
if(status == 0) {
|
||||
// get the last session id
|
||||
PRInt16 *old_ID = NS_STATIC_CAST(PRInt16*, db_data.data) ;
|
||||
if(*old_ID < ini_sessionID) {
|
||||
NS_ERROR("ERROR: Bad Session ID in database, corrupted db.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
mSessionID = *old_ID + 1 ;
|
||||
}
|
||||
else if(status == 1) {
|
||||
// must be a new db
|
||||
mSessionID = ini_sessionID ;
|
||||
}
|
||||
db_data.data = NS_REINTERPRET_CAST(void*, &mSessionID) ;
|
||||
db_data.size = sizeof(PRInt16) ;
|
||||
|
||||
// store the new session id
|
||||
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
|
||||
|
||||
if(status == 0) {
|
||||
(*mDB->sync)(mDB, 0) ;
|
||||
|
||||
// initialize database filesize
|
||||
return mDBFile->GetFileSize(&mDBFilesize) ;
|
||||
}
|
||||
else {
|
||||
NS_ERROR("reset session ID failure.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Shutdown(void)
|
||||
{
|
||||
if(mDB) {
|
||||
(*mDB->sync)(mDB, 0) ;
|
||||
(*mDB->close)(mDB) ;
|
||||
mDB = nsnull ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Get(PRInt32 aID, void** anEntry, PRUint32 *aLength)
|
||||
{
|
||||
if(!anEntry)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*anEntry = nsnull ;
|
||||
*aLength = 0 ;
|
||||
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
|
||||
db_key.size = sizeof(PRInt32) ;
|
||||
|
||||
int status = 0 ;
|
||||
status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
|
||||
if(status == 0) {
|
||||
*anEntry = db_data.data ;
|
||||
*aLength = db_data.size ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else if(status == 1)
|
||||
return NS_OK ;
|
||||
else
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Put(PRInt32 aID, void* anEntry, PRUint32 aLength)
|
||||
{
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
|
||||
db_key.size = sizeof(PRInt32) ;
|
||||
|
||||
db_data.data = anEntry ;
|
||||
db_data.size = aLength ;
|
||||
|
||||
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
|
||||
return Sync() ;
|
||||
}
|
||||
else {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It's more important to remove the id->metadata entry first since
|
||||
* key->id mapping is just a reference
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::Del(PRInt32 aID, void* anEntry, PRUint32 aLength)
|
||||
{
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key ;
|
||||
|
||||
// delete recordID->metadata
|
||||
db_key.data = NS_REINTERPRET_CAST(void*, &aID) ;
|
||||
db_key.size = sizeof(PRInt32) ;
|
||||
|
||||
PRInt32 status = -1 ;
|
||||
status = (*mDB->del)(mDB, &db_key, 0) ;
|
||||
|
||||
if(-1 == status) {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
// delete key->recordID
|
||||
db_key.data = anEntry ;
|
||||
db_key.size = aLength ;
|
||||
status = (*mDB->del)(mDB, &db_key, 0) ;
|
||||
if(-1 == status) {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
return Sync() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::GetID(const char* key, PRUint32 length, PRInt32* aID)
|
||||
{
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, key) ;
|
||||
db_key.size = length ;
|
||||
|
||||
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
if(status == 0) {
|
||||
// found recordID
|
||||
*aID = *(NS_REINTERPRET_CAST(PRInt32*, db_data.data)) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else if(status == 1) {
|
||||
// create a new one
|
||||
PRInt32 id = 0 ;
|
||||
id = mSessionID << 16 | mSessionCntr++ ;
|
||||
|
||||
// add new id into mDB
|
||||
db_data.data = NS_REINTERPRET_CAST(void*, &id) ;
|
||||
db_data.size = sizeof(PRInt32) ;
|
||||
|
||||
status = (*mDB->put)(mDB, &db_key, &db_data, 0) ;
|
||||
if(status != 0) {
|
||||
NS_ERROR("updating db failure.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
*aID = id ;
|
||||
return Sync() ;
|
||||
}
|
||||
else {
|
||||
NS_ERROR("ERROR: keydb failure.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::EnumEntry(void** anEntry, PRUint32* aLength, PRBool bReset)
|
||||
{
|
||||
if(!anEntry)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*anEntry = nsnull ;
|
||||
*aLength = 0 ;
|
||||
|
||||
NS_ASSERTION(mDB, "no database") ;
|
||||
|
||||
PRUint32 flag ;
|
||||
|
||||
if(bReset)
|
||||
flag = R_FIRST ;
|
||||
else
|
||||
flag = R_NEXT ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
PRUint32 len = PL_strlen(SessionKey) ;
|
||||
|
||||
int status ;
|
||||
|
||||
do {
|
||||
status = (*mDB->seq)(mDB, &db_key, &db_data, flag) ;
|
||||
flag = R_NEXT ;
|
||||
if(status == -1)
|
||||
return NS_ERROR_FAILURE ;
|
||||
// get next if it's a key->recordID
|
||||
if(db_key.size > sizeof(PRInt32) && db_data.size == sizeof(PRInt32))
|
||||
continue ;
|
||||
// get next if it's a sessionID entry
|
||||
if(db_key.size == len && db_data.size == sizeof(PRInt16))
|
||||
continue ;
|
||||
// recordID is always 32 bits long
|
||||
if(db_key.size == sizeof(PRInt32))
|
||||
break ;
|
||||
} while(!status) ;
|
||||
|
||||
if (0 == status) {
|
||||
*anEntry = db_data.data ;
|
||||
*aLength = db_data.size ;
|
||||
}
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the cached database file size.
|
||||
* mDBFilesize will be updated during Sync().
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::GetDBFilesize(PRUint32* aSize)
|
||||
{
|
||||
*aSize = mDBFilesize ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::GetSpecialEntry(void** anEntry, PRUint32* aLength)
|
||||
{
|
||||
if(!anEntry)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*anEntry = nsnull ;
|
||||
*aLength = 0 ;
|
||||
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
|
||||
db_key.size = PL_strlen(SpecialEntry) ;
|
||||
|
||||
int status = (*mDB->get)(mDB, &db_key, &db_data, 0) ;
|
||||
|
||||
if(status == -1) {
|
||||
NS_ERROR("ERROR: failed get special entry in database.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
if(status == 0) {
|
||||
*anEntry = db_data.data ;
|
||||
*aLength = db_data.size ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBAccessor::SetSpecialEntry(void* anEntry, PRUint32 aLength)
|
||||
{
|
||||
DBT db_key, db_data ;
|
||||
|
||||
db_key.data = NS_CONST_CAST(char*, SpecialEntry) ;
|
||||
db_key.size = PL_strlen(SpecialEntry) ;
|
||||
|
||||
db_data.data = anEntry ;
|
||||
db_data.size = aLength ;
|
||||
|
||||
if(0 == (*mDB->put)(mDB, &db_key, &db_data, 0)) {
|
||||
(*mDB->sync)(mDB, 0) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else {
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* sync routine is only called when the SyncInterval is reached. Otherwise
|
||||
* it just returns. If db synced, the filesize will be updated at the
|
||||
* same time.
|
||||
*/
|
||||
nsresult
|
||||
nsDBAccessor::Sync(void)
|
||||
{
|
||||
PRIntervalTime time = PR_IntervalNow() ;
|
||||
PRIntervalTime duration = time - mLastSyncTime ;
|
||||
|
||||
if (PR_IntervalToMilliseconds(duration) > SyncInterval) {
|
||||
int status = (*mDB->sync)(mDB, 0) ;
|
||||
if(status == 0) {
|
||||
// printf("\tsynced\n") ;
|
||||
mLastSyncTime = time ;
|
||||
|
||||
// update db filesize here
|
||||
return mDBFile->GetFileSize(&mDBFilesize) ;
|
||||
|
||||
} else
|
||||
return NS_ERROR_FAILURE ;
|
||||
} else {
|
||||
// printf("\tnot synced\n") ;
|
||||
return NS_OK ;
|
||||
}
|
||||
}
|
||||
93
mozilla/netwerk/cache/filecache/nsDBAccessor.h
vendored
93
mozilla/netwerk/cache/filecache/nsDBAccessor.h
vendored
@@ -1,93 +0,0 @@
|
||||
/*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* nsIDBAccessor is a interface that shields all the direct database access
|
||||
* method from nsNetDiskCache.
|
||||
*
|
||||
* nsDBAccessor is a implementation of the nsIDBAccessor interface. It
|
||||
* uses dbm(Berkely) as the database.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NSIDBACCESSOR_H_
|
||||
#define _NSIDBACCESSOR_H_
|
||||
|
||||
#include "nsIDBAccessor.h"
|
||||
#include "mcom_db.h"
|
||||
#include "prinrval.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
// bogus string for the key of session id
|
||||
static const char * const SessionKey = "SK" ;
|
||||
|
||||
// bogus string for the size
|
||||
static const char * const SpecialEntry = "SE" ;
|
||||
|
||||
// initial session id number
|
||||
static const PRInt16 ini_sessionID = 0xff ;
|
||||
|
||||
static const PRUint16 SyncInterval = 1000 ;
|
||||
|
||||
class nsDBAccessor : public nsIDBAccessor
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsDBAccessor() ;
|
||||
virtual ~nsDBAccessor() ;
|
||||
|
||||
NS_IMETHOD Init(nsIFileSpec* dbfile) ;
|
||||
NS_IMETHOD Shutdown(void) ;
|
||||
|
||||
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
|
||||
|
||||
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) ;
|
||||
|
||||
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) ;
|
||||
|
||||
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) ;
|
||||
|
||||
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) ;
|
||||
|
||||
NS_IMETHOD GetDBFilesize(PRUint32* aSize) ;
|
||||
|
||||
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) ;
|
||||
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) ;
|
||||
|
||||
protected:
|
||||
nsresult Sync(void) ;
|
||||
|
||||
private:
|
||||
DB * mDB ;
|
||||
nsCOMPtr<nsIFileSpec> mDBFile ;
|
||||
PRInt16 mSessionID ;
|
||||
PRInt16 mSessionCntr ;
|
||||
PRIntervalTime mLastSyncTime ;
|
||||
PRUint32 mDBFilesize ; // cached DB filesize,
|
||||
// updated on every sync for now
|
||||
} ;
|
||||
|
||||
#endif // _NSIDBACCESSOR_H_
|
||||
108
mozilla/netwerk/cache/filecache/nsDBEnumerator.cpp
vendored
108
mozilla/netwerk/cache/filecache/nsDBEnumerator.cpp
vendored
@@ -1,108 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* It implements a simple iterator for the database, see nsDBAccessor.
|
||||
*/
|
||||
|
||||
#include "nsDBEnumerator.h"
|
||||
#include "nsDiskCacheRecord.h"
|
||||
|
||||
nsDBEnumerator::nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) :
|
||||
m_DB(aDB) ,
|
||||
m_DiskCache(aCache) ,
|
||||
m_tempEntry(0) ,
|
||||
m_tempEntry_length(0) ,
|
||||
m_CacheEntry(0) ,
|
||||
m_bReset(PR_TRUE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
}
|
||||
|
||||
nsDBEnumerator::~nsDBEnumerator()
|
||||
{
|
||||
NS_IF_RELEASE(m_CacheEntry) ;
|
||||
}
|
||||
|
||||
//
|
||||
// Implement nsISupports methods
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(nsDBEnumerator, NS_GET_IID(nsIEnumerator))
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// nsISimpleEnumerator methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDBEnumerator::HasMoreElements(PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE ;
|
||||
|
||||
nsresult rv = m_DB->EnumEntry(&m_tempEntry, &m_tempEntry_length, m_bReset) ;
|
||||
|
||||
if(NS_FAILED(rv)) {
|
||||
// do some error recovery
|
||||
m_DiskCache->DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
m_bReset = PR_FALSE ;
|
||||
|
||||
if(m_tempEntry && m_tempEntry_length != 0)
|
||||
*_retval = PR_TRUE ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// this routine does not create a new item by itself
|
||||
// Rather it reuses the item inside the object. So if you need to use the
|
||||
// item later, you have to
|
||||
// create a new item specifically, using copy constructor or some other dup
|
||||
// function. And don't forget to release it after you're done
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsDBEnumerator::GetNext(nsISupports **_retval)
|
||||
{
|
||||
if(!m_CacheEntry) {
|
||||
m_CacheEntry = new nsDiskCacheRecord(m_DB, m_DiskCache) ;
|
||||
if(m_CacheEntry)
|
||||
NS_ADDREF(m_CacheEntry) ;
|
||||
else
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
*_retval = nsnull ;
|
||||
|
||||
nsresult rv = m_CacheEntry->RetrieveInfo(m_tempEntry, m_tempEntry_length) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
*_retval = NS_STATIC_CAST(nsISupports*, m_CacheEntry) ;
|
||||
NS_ADDREF(*_retval) ; // all good getter addref
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
60
mozilla/netwerk/cache/filecache/nsDBEnumerator.h
vendored
60
mozilla/netwerk/cache/filecache/nsDBEnumerator.h
vendored
@@ -1,60 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* It implements a simple iterator for the database, see nsDBAccessor.
|
||||
*/
|
||||
|
||||
#ifndef _NS_DBENUMERATOR_H_
|
||||
#define _NS_DBENUMERATOR_H_
|
||||
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsIDBAccessor.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nsDiskCacheRecord.h"
|
||||
|
||||
class nsCachedDiskData ; /* forward decl */
|
||||
|
||||
class nsDBEnumerator : public nsISimpleEnumerator {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
nsDBEnumerator(nsIDBAccessor* aDB, nsNetDiskCache* aCache) ;
|
||||
virtual ~nsDBEnumerator() ;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDBAccessor> m_DB ;
|
||||
nsCOMPtr<nsNetDiskCache> m_DiskCache ;
|
||||
void * m_tempEntry ;
|
||||
PRUint32 m_tempEntry_length ;
|
||||
nsDiskCacheRecord* m_CacheEntry ;
|
||||
PRBool m_bReset ;
|
||||
};
|
||||
|
||||
#endif // _NS_DBENUMERATOR_H_
|
||||
@@ -1,456 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#include "nsDiskCacheRecord.h"
|
||||
#include "nsINetDataDiskCache.h"
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsDiskCacheRecordChannel.h"
|
||||
#include "nsFileStream.h"
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIAllocator.h"
|
||||
|
||||
#include "plstr.h"
|
||||
#include "prprf.h"
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
#include "prtypes.h"
|
||||
#include "netCore.h"
|
||||
|
||||
#include "nsDBAccessor.h"
|
||||
|
||||
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
|
||||
ERROR! Must have a byte order
|
||||
#endif
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
|
||||
#else
|
||||
#define COPY_INT32(_a,_b) /* swap */ \
|
||||
do { \
|
||||
((char *)(_a))[0] = ((char *)(_b))[3]; \
|
||||
((char *)(_a))[1] = ((char *)(_b))[2]; \
|
||||
((char *)(_a))[2] = ((char *)(_b))[1]; \
|
||||
((char *)(_a))[3] = ((char *)(_b))[0]; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
nsDiskCacheRecord::nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) :
|
||||
mKey(0) ,
|
||||
mKeyLength(0) ,
|
||||
mRecordID(0) ,
|
||||
mMetaData(0) ,
|
||||
mMetaDataLength(0) ,
|
||||
mDB(db) ,
|
||||
mInfo(0) ,
|
||||
mInfoSize(0) ,
|
||||
mNumChannels(0) ,
|
||||
mDiskCache(aCache)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ASSERTION(mDiskCache, "Must have an nsNetDiskCache");
|
||||
NS_ADDREF(mDiskCache);
|
||||
}
|
||||
|
||||
// mem alloced. so caller should do free() on key.
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::Init(const char* key, PRUint32 length, PRInt32 ID)
|
||||
{
|
||||
NS_NewFileSpec(getter_AddRefs(mFile));
|
||||
if(!mFile)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
// copy key
|
||||
mKeyLength = length ;
|
||||
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
|
||||
if(!mKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(mKey, key, length) ;
|
||||
|
||||
// get RecordID
|
||||
mRecordID = ID ;
|
||||
|
||||
// setup the file name
|
||||
nsCOMPtr<nsIFileSpec> dbFolder ;
|
||||
mDiskCache->GetDiskCacheFolder(getter_AddRefs(dbFolder)) ;
|
||||
|
||||
nsresult rv = mFile->FromFileSpec(dbFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
// dir is a hash result of mRecordID%32, hope it's enough
|
||||
char filename[9], dirName[3] ;
|
||||
|
||||
PR_snprintf(dirName, 3, "%02x", (((PRUint32)mRecordID) % 32)) ;
|
||||
mFile->AppendRelativeUnixPath(dirName) ;
|
||||
|
||||
PR_snprintf(filename, 9, "%08x", mRecordID) ;
|
||||
mFile->AppendRelativeUnixPath(filename) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
nsDiskCacheRecord::~nsDiskCacheRecord()
|
||||
{
|
||||
if(mKey)
|
||||
nsAllocator::Free(mKey) ;
|
||||
if(mMetaData)
|
||||
nsAllocator::Free(mMetaData) ;
|
||||
if(mInfo)
|
||||
nsAllocator::Free(mInfo) ;
|
||||
|
||||
NS_IF_RELEASE(mDiskCache);
|
||||
}
|
||||
|
||||
//
|
||||
// Implement nsISupports methods
|
||||
//
|
||||
NS_IMPL_ISUPPORTS(nsDiskCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// nsINetDataCacheRecord methods
|
||||
|
||||
// yes, mem alloced on *_retval.
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetKey(PRUint32 *length, char** _retval)
|
||||
{
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*length = mKeyLength ;
|
||||
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
|
||||
if(!*_retval)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(*_retval, mKey, mKeyLength) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetRecordID(PRInt32* aRecordID)
|
||||
{
|
||||
*aRecordID = mRecordID ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// yes, mem alloced on *_retval.
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetMetaData(PRUint32 *length, char **_retval)
|
||||
{
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
// always null the return value first.
|
||||
*_retval = nsnull ;
|
||||
|
||||
*length = mMetaDataLength ;
|
||||
|
||||
if(mMetaDataLength) {
|
||||
*_retval = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
|
||||
if(!*_retval)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(*_retval, mMetaData, mMetaDataLength) ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::SetMetaData(PRUint32 length, const char* data)
|
||||
{
|
||||
// set the mMetaData
|
||||
mMetaDataLength = length ;
|
||||
if(mMetaData)
|
||||
nsAllocator::Free(mMetaData) ;
|
||||
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
|
||||
if(!mMetaData) {
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
memcpy(mMetaData, data, length) ;
|
||||
|
||||
// Generate mInfo
|
||||
nsresult rv = GenInfo() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// write through into mDB
|
||||
rv = mDB->Put(mRecordID, mInfo, mInfoSize) ;
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
|
||||
{
|
||||
return mFile->GetFileSize(aStoredContentLength) ;
|
||||
}
|
||||
|
||||
// untill nsIFileSpec::Truncate() is in, we have to do all this ugly stuff
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
|
||||
{
|
||||
PRUint32 len = 0 ;
|
||||
nsresult rv = mFile->GetFileSize(&len) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
if(len < aStoredContentLength)
|
||||
{
|
||||
NS_ERROR("Error: can not set filesize to something bigger than itself.\n") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
else {
|
||||
rv = mFile->Truncate(aStoredContentLength) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
mDiskCache->m_StorageInUse -= (len - aStoredContentLength) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::Delete(void)
|
||||
{
|
||||
if(mNumChannels)
|
||||
return NS_ERROR_NOT_AVAILABLE ;
|
||||
|
||||
PRUint32 len ;
|
||||
mFile->GetFileSize(&len) ;
|
||||
|
||||
nsFileSpec cache_file ;
|
||||
nsresult rv = mFile->GetFileSpec(&cache_file) ;
|
||||
|
||||
if(NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
cache_file.Delete(PR_TRUE) ;
|
||||
|
||||
// updata the storage size
|
||||
mDiskCache->m_StorageInUse -= len ;
|
||||
|
||||
rv = mDB->Del(mRecordID, mKey, mKeyLength) ;
|
||||
if(NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE ;
|
||||
else
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::GetFilename(nsIFileSpec * *aFilename)
|
||||
{
|
||||
if(!aFilename)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*aFilename = mFile ;
|
||||
NS_ADDREF(*aFilename) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::NewChannel(nsILoadGroup *loadGroup, nsIChannel **_retval)
|
||||
{
|
||||
nsDiskCacheRecordChannel* channel = new nsDiskCacheRecordChannel(this, loadGroup) ;
|
||||
if(!channel)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
nsresult rv = channel->Init() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
NS_ADDREF(channel) ;
|
||||
*_retval = NS_STATIC_CAST(nsIChannel*, channel) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// nsDiskCacheRecord methods
|
||||
|
||||
// file name is represented by a url string. I hope this would be more
|
||||
// generic
|
||||
nsresult
|
||||
nsDiskCacheRecord::GenInfo()
|
||||
{
|
||||
if(mInfo)
|
||||
nsAllocator::Free(mInfo) ;
|
||||
|
||||
char* file_url=nsnull ;
|
||||
PRUint32 name_len ;
|
||||
mFile->GetURLString(&file_url) ;
|
||||
name_len = PL_strlen(file_url)+1 ;
|
||||
|
||||
mInfoSize = sizeof(PRUint32) ; // checksum for mInfoSize
|
||||
mInfoSize += sizeof(PRInt32) ; // RecordID
|
||||
mInfoSize += sizeof(PRUint32) ; // key length
|
||||
mInfoSize += mKeyLength ; // key
|
||||
mInfoSize += sizeof(PRUint32) ; // metadata length
|
||||
mInfoSize += mMetaDataLength ; // metadata
|
||||
mInfoSize += sizeof(PRUint32) ; // filename length
|
||||
mInfoSize += name_len ; // filename
|
||||
|
||||
void* newInfo = nsAllocator::Alloc(mInfoSize*sizeof(char)) ;
|
||||
if(!newInfo) {
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
// copy the checksum mInfoSize
|
||||
char* cur_ptr = NS_STATIC_CAST(char*, newInfo) ;
|
||||
COPY_INT32(cur_ptr, &mInfoSize) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy RecordID
|
||||
COPY_INT32(cur_ptr, &mRecordID) ;
|
||||
cur_ptr += sizeof(PRInt32) ;
|
||||
|
||||
// copy key length
|
||||
COPY_INT32(cur_ptr, &mKeyLength) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy key
|
||||
memcpy(cur_ptr, mKey, mKeyLength) ;
|
||||
cur_ptr += mKeyLength ;
|
||||
|
||||
// copy metadata length
|
||||
COPY_INT32(cur_ptr, &mMetaDataLength) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy metadata
|
||||
memcpy(cur_ptr, mMetaData, mMetaDataLength) ;
|
||||
cur_ptr += mMetaDataLength ;
|
||||
|
||||
// copy file name length
|
||||
COPY_INT32(cur_ptr, &name_len) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// copy file name
|
||||
memcpy(cur_ptr, file_url, name_len) ;
|
||||
cur_ptr += name_len ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, newInfo) + mInfoSize);
|
||||
mInfo = newInfo ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
* This Method suppose to get all the info from the db record
|
||||
* and set them to accroding members. the original values
|
||||
* will all be overwritten. only minimal error checking is performed.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecord::RetrieveInfo(void* aInfo, PRUint32 aInfoLength)
|
||||
{
|
||||
// reset everything
|
||||
if(mInfo) {
|
||||
nsAllocator::Free(mInfo) ;
|
||||
mInfo = nsnull ;
|
||||
}
|
||||
|
||||
if(mKey) {
|
||||
nsAllocator::Free(mKey) ;
|
||||
mKey = nsnull ;
|
||||
}
|
||||
if(mMetaData) {
|
||||
nsAllocator::Free(mMetaData) ;
|
||||
mMetaData = nsnull ;
|
||||
}
|
||||
|
||||
char * cur_ptr = NS_STATIC_CAST(char*, aInfo) ;
|
||||
|
||||
char* file_url ;
|
||||
PRUint32 name_len ;
|
||||
|
||||
// set mInfoSize
|
||||
COPY_INT32(&mInfoSize, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// check this at least
|
||||
if(mInfoSize != aInfoLength)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
// set mRecordID
|
||||
COPY_INT32(&mRecordID, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRInt32) ;
|
||||
|
||||
// set mKeyLength
|
||||
COPY_INT32(&mKeyLength, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// set mKey
|
||||
mKey = NS_STATIC_CAST(char*, nsAllocator::Alloc(mKeyLength*sizeof(char))) ;
|
||||
if(!mKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(mKey, cur_ptr, mKeyLength) ;
|
||||
cur_ptr += mKeyLength ;
|
||||
|
||||
PRInt32 id ;
|
||||
mDB->GetID(mKey, mKeyLength, &id) ;
|
||||
NS_ASSERTION(id==mRecordID, "\t ++++++ bad record, somethings wrong\n") ;
|
||||
|
||||
// set mMetaDataLength
|
||||
COPY_INT32(&mMetaDataLength, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// set mMetaData
|
||||
mMetaData = NS_STATIC_CAST(char*, nsAllocator::Alloc(mMetaDataLength*sizeof(char))) ;
|
||||
if(!mMetaData)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(mMetaData, cur_ptr, mMetaDataLength) ;
|
||||
cur_ptr += mMetaDataLength ;
|
||||
|
||||
// get mFile name length
|
||||
COPY_INT32(&name_len, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// get mFile native name
|
||||
file_url = NS_STATIC_CAST(char*, nsAllocator::Alloc(name_len*sizeof(char))) ;
|
||||
if(!file_url)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
memcpy(file_url, cur_ptr, name_len) ;
|
||||
cur_ptr += name_len ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, aInfo) + mInfoSize);
|
||||
|
||||
// create mFile if Init() isn't called
|
||||
if(!mFile) {
|
||||
NS_NewFileSpec(getter_AddRefs(mFile));
|
||||
if(!mFile)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
// setup mFile
|
||||
mFile->SetURLString(file_url) ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _NET_CACHEDDISKDATA_H_
|
||||
#define _NET_CACHEDDISKDATA_H_
|
||||
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDBAccessor.h"
|
||||
#include "prtypes.h"
|
||||
#include "nsILoadGroup.h"
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
|
||||
class nsDiskCacheRecord : public nsINetDataCacheRecord
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETDATACACHERECORD
|
||||
|
||||
protected:
|
||||
|
||||
nsDiskCacheRecord(nsIDBAccessor* db, nsNetDiskCache* aCache) ;
|
||||
virtual ~nsDiskCacheRecord() ;
|
||||
|
||||
NS_IMETHOD RetrieveInfo(void* aInfo, PRUint32 aInfoLength) ;
|
||||
NS_IMETHOD Init(const char* key, PRUint32 length, PRInt32 ID) ;
|
||||
|
||||
nsresult GenInfo(void) ;
|
||||
|
||||
private:
|
||||
|
||||
char* mKey ;
|
||||
PRUint32 mKeyLength ;
|
||||
PRInt32 mRecordID ;
|
||||
char* mMetaData ;
|
||||
PRUint32 mMetaDataLength ;
|
||||
nsCOMPtr<nsIFileSpec> mFile ;
|
||||
nsCOMPtr<nsIDBAccessor> mDB ;
|
||||
void* mInfo ;
|
||||
PRUint32 mInfoSize ;
|
||||
PRUint32 mNumChannels ;
|
||||
nsNetDiskCache* mDiskCache ;
|
||||
|
||||
friend class nsDiskCacheRecordChannel ;
|
||||
friend class nsDBEnumerator ;
|
||||
friend class nsNetDiskCache ;
|
||||
} ;
|
||||
|
||||
#endif // _NET_CACHEDDISKDATA_H_
|
||||
@@ -1,552 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Most of the code are taken from nsFileChannel.
|
||||
*/
|
||||
|
||||
#include "nsDiskCacheRecordChannel.h"
|
||||
#include "nsIFileTransportService.h"
|
||||
//#include "nsIIOService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "netCore.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
|
||||
//static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
static NS_DEFINE_CID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
|
||||
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
|
||||
static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID);
|
||||
|
||||
// This is copied from nsMemCacheChannel, We should consolidate these two.
|
||||
class WriteStreamWrapper : public nsIOutputStream
|
||||
{
|
||||
public:
|
||||
WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
|
||||
nsIOutputStream *aBaseStream) ;
|
||||
|
||||
virtual ~WriteStreamWrapper() ;
|
||||
|
||||
static nsresult
|
||||
Create(nsDiskCacheRecordChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) ;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIBASESTREAM
|
||||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
private:
|
||||
nsDiskCacheRecordChannel* mChannel;
|
||||
nsCOMPtr<nsIOutputStream> mBaseStream;
|
||||
} ;
|
||||
|
||||
// implement nsISupports
|
||||
NS_IMPL_ISUPPORTS(WriteStreamWrapper, NS_GET_IID(nsIOutputStream))
|
||||
|
||||
WriteStreamWrapper::WriteStreamWrapper(nsDiskCacheRecordChannel* aChannel,
|
||||
nsIOutputStream *aBaseStream)
|
||||
: mChannel(aChannel), mBaseStream(aBaseStream)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mChannel);
|
||||
}
|
||||
|
||||
WriteStreamWrapper::~WriteStreamWrapper()
|
||||
{
|
||||
NS_RELEASE(mChannel);
|
||||
}
|
||||
|
||||
nsresult
|
||||
WriteStreamWrapper::Create(nsDiskCacheRecordChannel*aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* * aWrapper)
|
||||
{
|
||||
WriteStreamWrapper *wrapper = new WriteStreamWrapper(aChannel, aBaseStream);
|
||||
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(wrapper);
|
||||
*aWrapper = wrapper;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WriteStreamWrapper::Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten)
|
||||
{
|
||||
*aNumWritten = 0;
|
||||
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
|
||||
mChannel->NotifyStorageInUse(*aNumWritten);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WriteStreamWrapper::Flush()
|
||||
{
|
||||
return mBaseStream->Flush();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WriteStreamWrapper::Close()
|
||||
{
|
||||
return mBaseStream->Close();
|
||||
}
|
||||
|
||||
nsDiskCacheRecordChannel::nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord,
|
||||
nsILoadGroup *aLoadGroup)
|
||||
: mRecord(aRecord) ,
|
||||
mLoadGroup(aLoadGroup)
|
||||
{
|
||||
NS_INIT_REFCNT() ;
|
||||
NS_ADDREF(mRecord);
|
||||
mRecord->mNumChannels++ ;
|
||||
}
|
||||
|
||||
nsDiskCacheRecordChannel::~nsDiskCacheRecordChannel()
|
||||
{
|
||||
mRecord->mNumChannels-- ;
|
||||
NS_RELEASE(mRecord);
|
||||
}
|
||||
|
||||
// I know that I gave conflicting advice on the issue of file
|
||||
// transport versus file protocol handler, but I thought that the
|
||||
// last word was that we would use the raw transport, when I wrote:
|
||||
//
|
||||
// > I just thought of an argument for the other side of the coin, i.e. the
|
||||
// > benefit of *not* reusing the file protocol handler: On the Mac, it's
|
||||
// > expensive to convert from a string URL to an nsFileSpec, because the Mac
|
||||
// > is brain-dead and scans every directory on the path to the file. It's
|
||||
// > cheaper to create a nsFileSpec for a cache file by combining a single,
|
||||
// > static nsFileSpec that corresponds to the cache directory with the
|
||||
// > relative path to the cache file (using nsFileSpec's operator +). This
|
||||
// > operation is optimized on the Mac to avoid the scanning operation.
|
||||
//
|
||||
// The Mac guys will eat us alive if we do path string to nsFileSpec
|
||||
// conversions for every cache file we open.
|
||||
|
||||
nsresult
|
||||
nsDiskCacheRecordChannel::Init(void)
|
||||
{
|
||||
nsresult rv = mRecord->mFile->GetFileSpec(&mSpec) ;
|
||||
|
||||
#ifdef XP_MAC
|
||||
|
||||
// Don't assume we actually created a good file spec
|
||||
FSSpec theSpec = mSpec.GetFSSpec();
|
||||
if (!theSpec.name[0]) {
|
||||
NS_ERROR("failed to create a file spec");
|
||||
|
||||
// Since we didn't actually create the file spec
|
||||
// we return an error
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv ;
|
||||
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDiskCacheRecordChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
|
||||
{
|
||||
return mRecord->mDiskCache->m_StorageInUse += aBytesUsed ;
|
||||
}
|
||||
|
||||
// implement nsISupports
|
||||
NS_IMPL_ISUPPORTS4(nsDiskCacheRecordChannel,
|
||||
nsIChannel,
|
||||
nsIRequest,
|
||||
nsIStreamListener,
|
||||
nsIStreamObserver)
|
||||
|
||||
// implement nsIRequest
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::IsPending(PRBool *aIsPending)
|
||||
{
|
||||
*aIsPending = PR_FALSE ;
|
||||
if(!mFileTransport)
|
||||
return NS_OK ;
|
||||
|
||||
return mFileTransport->IsPending(aIsPending) ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::Cancel(void)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->Cancel() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::Suspend(void)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->Suspend() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::Resume(void)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->Resume() ;
|
||||
}
|
||||
|
||||
// implement nsIChannel
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetOriginalURI(nsIURI* *aURI)
|
||||
{
|
||||
// FUR - might need to implement this - not sure
|
||||
return NS_ERROR_NOT_IMPLEMENTED ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetURI(nsIURI * *aURI)
|
||||
{
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->GetURI(aURI) ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OpenInputStream(PRUint32 aStartPosition,
|
||||
PRInt32 aReadCount,
|
||||
nsIInputStream* *aResult)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if(mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS ;
|
||||
|
||||
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
|
||||
if(NS_FAILED(rv)) return rv ;
|
||||
|
||||
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// we don't need to worry about notification callbacks
|
||||
|
||||
rv = mFileTransport->OpenInputStream(aStartPosition, aReadCount, aResult) ;
|
||||
if(NS_FAILED(rv))
|
||||
mFileTransport = nsnull ;
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OpenOutputStream(PRUint32 startPosition,
|
||||
nsIOutputStream* *aResult)
|
||||
{
|
||||
nsresult rv ;
|
||||
NS_ENSURE_ARG(aResult) ;
|
||||
|
||||
if(mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS ;
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream ;
|
||||
|
||||
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv) ;
|
||||
if(NS_FAILED(rv)) return rv ;
|
||||
|
||||
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport)) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// we don't need to worry about notification callbacks
|
||||
|
||||
rv = mFileTransport->OpenOutputStream(startPosition, getter_AddRefs(outputStream)) ;
|
||||
if(NS_FAILED(rv)) {
|
||||
mFileTransport = nsnull ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
return WriteStreamWrapper::Create(this, outputStream, aResult) ;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::AsyncOpen(nsIStreamObserver *observer,
|
||||
nsISupports *ctxt)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::AsyncRead(PRUint32 aStartPosition,
|
||||
PRInt32 aReadCount,
|
||||
nsISupports *aContext,
|
||||
nsIStreamListener *aListener)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if(mFileTransport)
|
||||
return NS_ERROR_IN_PROGRESS ;
|
||||
|
||||
mRealListener = aListener;
|
||||
nsCOMPtr<nsIStreamListener> tempListener = this;
|
||||
|
||||
if (mLoadGroup) {
|
||||
nsCOMPtr<nsILoadGroupListenerFactory> factory;
|
||||
//
|
||||
// Create a load group "proxy" listener...
|
||||
//
|
||||
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
|
||||
if (factory) {
|
||||
nsIStreamListener *newListener;
|
||||
rv = factory->CreateLoadGroupListener(mRealListener, &newListener);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mRealListener = newListener;
|
||||
NS_RELEASE(newListener);
|
||||
}
|
||||
}
|
||||
|
||||
rv = mLoadGroup->AddChannel(this, nsnull);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_WITH_SERVICE(nsIFileTransportService, fts, kFileTransportServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = fts->CreateTransport(mSpec, "load", 0, 0, getter_AddRefs(mFileTransport));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// no callbacks
|
||||
|
||||
rv = mFileTransport->AsyncRead(aStartPosition,
|
||||
aReadCount,
|
||||
aContext,
|
||||
tempListener);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// release the transport so that we don't think we're in progress
|
||||
mFileTransport = nsnull;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::AsyncWrite(nsIInputStream *fromStream,
|
||||
PRUint32 startPosition,
|
||||
PRInt32 writeCount,
|
||||
nsISupports *ctxt,
|
||||
nsIStreamObserver *observer)
|
||||
|
||||
{
|
||||
/*
|
||||
if(!mFileTransport)
|
||||
return NS_ERROR_FAILURE ;
|
||||
|
||||
return mFileTransport->AsyncWrite(fromStream,
|
||||
startPosition,
|
||||
writeCount,
|
||||
ctxt,
|
||||
observer) ;
|
||||
*/
|
||||
|
||||
// I can't do this since the write is not monitored, and I won't be
|
||||
// able to updata the storage.
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
#define DUMMY_TYPE "text/html"
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetContentType(char * *aContentType)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if (mSpec.IsDirectory()) {
|
||||
*aContentType = nsCRT::strdup("application/http-index-format");
|
||||
return *aContentType ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
// I wish I can make this simplier
|
||||
|
||||
char* urlStr ;
|
||||
mRecord->mFile->GetURLString(&urlStr) ;
|
||||
|
||||
// file: URLs (currently) have no additional structure beyond that provided by standard
|
||||
// URLs, so there is no "outer" given to CreateInstance
|
||||
|
||||
nsCOMPtr<nsIURI> url;
|
||||
rv = nsComponentManager::CreateInstance(kStandardURLCID, nsnull,
|
||||
NS_GET_IID(nsIURI),
|
||||
//(void**)&url);
|
||||
getter_AddRefs(url)) ;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = url->SetSpec((char*)urlStr);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIMIMEService, MIMEService, kMIMEServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = MIMEService->GetTypeFromURI(url, aContentType);
|
||||
if (NS_SUCCEEDED(rv)) return rv;
|
||||
}
|
||||
|
||||
// if all else fails treat it as text/html?
|
||||
*aContentType = nsCRT::strdup(DUMMY_TYPE);
|
||||
if (!*aContentType) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
} else {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetContentLength(PRInt32 *aContentLength)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 length;
|
||||
|
||||
rv = mRecord->mFile->GetFileSize(&length);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*aContentLength = (PRInt32)length;
|
||||
} else {
|
||||
*aContentLength = -1;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetOwner(nsISupports* *aOwner)
|
||||
{
|
||||
*aOwner = mOwner.get() ;
|
||||
NS_IF_ADDREF(*aOwner) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetOwner(nsISupports* aOwner)
|
||||
{
|
||||
mOwner = aOwner ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsDiskCacheRecordChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIStreamListener methods:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OnStartRequest(nsIChannel* transportChannel, nsISupports* context)
|
||||
{
|
||||
NS_ASSERTION(mRealListener, "No listener...");
|
||||
return mRealListener->OnStartRequest(this, context);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OnStopRequest(nsIChannel* transportChannel, nsISupports* context,
|
||||
nsresult aStatus, const PRUnichar* aMsg)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = mRealListener->OnStopRequest(this, context, aStatus, aMsg);
|
||||
|
||||
if (mLoadGroup) {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mLoadGroup->RemoveChannel(this, context, aStatus, aMsg);
|
||||
}
|
||||
}
|
||||
|
||||
// Release the reference to the consumer stream listener...
|
||||
mRealListener = null_nsCOMPtr();
|
||||
mFileTransport = null_nsCOMPtr();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDiskCacheRecordChannel::OnDataAvailable(nsIChannel* transportChannel, nsISupports* context,
|
||||
nsIInputStream *aIStream, PRUint32 aSourceOffset,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = mRealListener->OnDataAvailable(this, context, aIStream,
|
||||
aSourceOffset, aLength);
|
||||
|
||||
//
|
||||
// If the connection is being aborted cancel the transport. This will
|
||||
// insure that the transport will go away even if it is blocked waiting
|
||||
// for the consumer to empty the pipe...
|
||||
//
|
||||
if (NS_FAILED(rv)) {
|
||||
mFileTransport->Cancel();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _ns_DiskCacheRecordChannel_h_
|
||||
#define _ns_DiskCacheRecordChannel_h_
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDiskCacheRecord.h"
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
/*
|
||||
* This class is plagiarized from nsMemCacheChannel
|
||||
*/
|
||||
|
||||
class nsDiskCacheRecordChannel : public nsIChannel,
|
||||
public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
|
||||
nsDiskCacheRecordChannel(nsDiskCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
|
||||
virtual ~nsDiskCacheRecordChannel() ;
|
||||
|
||||
// Declare nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Declare nsIRequest methods
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
// Declare nsIChannel methods
|
||||
NS_DECL_NSICHANNEL
|
||||
|
||||
// Declare nsIStreamObserver methods
|
||||
NS_DECL_NSISTREAMOBSERVER
|
||||
|
||||
// Declare nsIStreamListener methods
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
nsresult Init(void) ;
|
||||
|
||||
private:
|
||||
|
||||
nsresult NotifyStorageInUse(PRInt32 aBytesUsed) ;
|
||||
|
||||
nsDiskCacheRecord* mRecord ;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup ;
|
||||
nsCOMPtr<nsISupports> mOwner ;
|
||||
nsCOMPtr<nsIChannel> mFileTransport ;
|
||||
nsFileSpec mSpec ;
|
||||
nsCOMPtr<nsIStreamListener> mRealListener;
|
||||
|
||||
friend class WriteStreamWrapper ;
|
||||
} ;
|
||||
|
||||
#endif // _ns_DiskCacheRecordChannel_h_
|
||||
|
||||
66
mozilla/netwerk/cache/filecache/nsIDBAccessor.h
vendored
66
mozilla/netwerk/cache/filecache/nsIDBAccessor.h
vendored
@@ -1,66 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _NS_IDBACCESSOR_H_
|
||||
#define _NS_IDBACCESSOR_H_
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFileSpec.h"
|
||||
|
||||
// nsIDBAccessorIID {6AADD4D0-7785-11d3-87FE-000629D01344}
|
||||
#define NS_IDBACCESSOR_IID \
|
||||
{ 0x6aadd4d0, 0x7785, 0x11d3, \
|
||||
{0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44}}
|
||||
|
||||
// nsDBAccessorCID {6AADD4D1-7785-11d3-87FE-000629D01344}
|
||||
#define NS_DBACCESSOR_CID \
|
||||
{ 0x6aadd4d1, 0x7785, 0x11d3, \
|
||||
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
|
||||
|
||||
class nsIDBAccessor : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IDBACCESSOR_IID)
|
||||
|
||||
NS_IMETHOD Init(nsIFileSpec* DBFile) = 0 ;
|
||||
NS_IMETHOD Shutdown(void) = 0 ;
|
||||
|
||||
NS_IMETHOD Put(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
|
||||
|
||||
NS_IMETHOD Get(PRInt32 aID, void** anEntry, PRUint32 *aLength) = 0 ;
|
||||
|
||||
NS_IMETHOD Del(PRInt32 aID, void* anEntry, PRUint32 aLength) = 0 ;
|
||||
|
||||
NS_IMETHOD GetID(const char* key, PRUint32 length, PRInt32* aID) = 0 ;
|
||||
|
||||
NS_IMETHOD EnumEntry(void* *anEntry, PRUint32* aLength, PRBool bReset) = 0 ;
|
||||
|
||||
NS_IMETHOD GetDBFilesize(PRUint32* aSize) = 0 ;
|
||||
|
||||
NS_IMETHOD GetSpecialEntry(void** anEntry, PRUint32 *aLength) = 0 ;
|
||||
NS_IMETHOD SetSpecialEntry(void* anEntry, PRUint32 aLength) = 0 ;
|
||||
|
||||
} ;
|
||||
|
||||
#endif // _NS_IDBACCESSOR_H_
|
||||
|
||||
704
mozilla/netwerk/cache/filecache/nsNetDiskCache.cpp
vendored
704
mozilla/netwerk/cache/filecache/nsNetDiskCache.cpp
vendored
@@ -1,704 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nscore.h"
|
||||
|
||||
#include "plstr.h"
|
||||
#include "prprf.h"
|
||||
#include "prtypes.h"
|
||||
#include "prio.h"
|
||||
#include "prsystem.h" // Directory Seperator
|
||||
#include "plhash.h"
|
||||
#include "prclist.h"
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
#include "nsIPref.h"
|
||||
#include "mcom_db.h"
|
||||
#include "nsDBEnumerator.h"
|
||||
|
||||
#include "nsDiskCacheRecord.h"
|
||||
#include "netCore.h"
|
||||
|
||||
#if !defined(IS_LITTLE_ENDIAN) && !defined(IS_BIG_ENDIAN)
|
||||
ERROR! Must have a byte order
|
||||
#endif
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
#define COPY_INT32(_a,_b) memcpy(_a, _b, sizeof(int32))
|
||||
#else
|
||||
#define COPY_INT32(_a,_b) /* swap */ \
|
||||
do { \
|
||||
((char *)(_a))[0] = ((char *)(_b))[3]; \
|
||||
((char *)(_a))[1] = ((char *)(_b))[2]; \
|
||||
((char *)(_a))[2] = ((char *)(_b))[1]; \
|
||||
((char *)(_a))[3] = ((char *)(_b))[0]; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID) ;
|
||||
static NS_DEFINE_CID(kDBAccessorCID, NS_DBACCESSOR_CID) ;
|
||||
|
||||
static const PRUint32 DISK_CACHE_SIZE_DEFAULT = 5*1024*1024 ; // 5MB
|
||||
static const char * const DISK_CACHE_PREF = "browser.cache.disk_cache_size";
|
||||
static const char * const CACHE_DIR_PREF = "browser.cache.directory";
|
||||
|
||||
class nsDiskCacheRecord ;
|
||||
|
||||
nsNetDiskCache::nsNetDiskCache() :
|
||||
m_Enabled(PR_TRUE) ,
|
||||
m_NumEntries(0) ,
|
||||
m_pNextCache(0) ,
|
||||
m_pDiskCacheFolder(0) ,
|
||||
m_StorageInUse(0) ,
|
||||
m_DB(0) ,
|
||||
m_DBCorrupted(PR_FALSE)
|
||||
{
|
||||
// set it to INF for now
|
||||
m_MaxEntries = (PRUint32)-1 ;
|
||||
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
}
|
||||
|
||||
nsNetDiskCache::~nsNetDiskCache()
|
||||
{
|
||||
SetSpecialEntry() ;
|
||||
|
||||
NS_IF_RELEASE(m_DB) ;
|
||||
|
||||
|
||||
// FUR
|
||||
// I think that, eventually, we also want a distinguished key in the DB which
|
||||
// means "clean cache shutdown". You clear this flag when the db is first
|
||||
// opened and set it just before the db is closed. If the db wasn't shutdown
|
||||
// cleanly in a prior session, i.e. because the app crashed, on startup you
|
||||
// scan all the individual files in directories and look for "orphans",
|
||||
// i.e. cache files which don't have corresponding entries in the db. That's
|
||||
// also when storage-in-use and number of entries would be recomputed.
|
||||
//
|
||||
// We don't necessarily need all this functionality immediately, though.
|
||||
|
||||
|
||||
if(m_DBCorrupted) {
|
||||
|
||||
nsFileSpec cacheFolder ;
|
||||
m_pDiskCacheFolder->GetFileSpec(&cacheFolder) ;
|
||||
|
||||
char nameInt[6] ;
|
||||
|
||||
for(nsDirectoryIterator di(cacheFolder, PR_FALSE); di.Exists(); di++) {
|
||||
char* filename = di.Spec().GetLeafName() ;
|
||||
char* pname = nameInt ;
|
||||
pname = PL_strncpyz(pname, filename, 6) ;
|
||||
|
||||
if(PL_strcmp(pname, "trash") == 0)
|
||||
RemoveFolder(di.Spec()) ;
|
||||
|
||||
nsCRT::free(filename) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::Init(void)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
// don't initialize if no cache folder is set.
|
||||
if(!m_pDiskCacheFolder) return NS_OK ;
|
||||
|
||||
if(!m_DB) {
|
||||
m_DB = new nsDBAccessor() ;
|
||||
if(!m_DB)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
else
|
||||
NS_ADDREF(m_DB) ;
|
||||
}
|
||||
|
||||
// create cache sub directories
|
||||
nsCOMPtr<nsIFileSpec> cacheSubDir;
|
||||
rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir));
|
||||
|
||||
for (int i=0; i < 32; i++) {
|
||||
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
char dirName[3];
|
||||
PR_snprintf (dirName, 3, "%0.2x", i);
|
||||
cacheSubDir->AppendRelativeUnixPath (dirName) ;
|
||||
CreateDir(cacheSubDir);
|
||||
}
|
||||
|
||||
return InitDB() ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::InitDB(void)
|
||||
{
|
||||
nsresult rv ;
|
||||
|
||||
if(!m_DBFile) {
|
||||
NS_NewFileSpec(getter_AddRefs(m_DBFile)) ;
|
||||
if(!m_DBFile)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
rv = m_DBFile->FromFileSpec(m_pDiskCacheFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
m_DBFile->AppendRelativeUnixPath("cache.db") ;
|
||||
|
||||
rv = m_DB->Init(m_DBFile) ;
|
||||
|
||||
if(rv == NS_ERROR_FAILURE) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
}
|
||||
|
||||
rv = GetSpecialEntry() ;
|
||||
if(rv == NS_ERROR_FAILURE) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
}
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// nsISupports methods
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsNetDiskCache,
|
||||
nsINetDataDiskCache,
|
||||
nsINetDataCache,
|
||||
nsISupports)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// nsINetDataCache Method
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetDescription(PRUnichar* *aDescription)
|
||||
{
|
||||
nsAutoString description("Disk Cache") ;
|
||||
*aDescription = description.ToNewUnicode() ;
|
||||
if(!*aDescription)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/* don't alloc mem for nsICachedNetData.
|
||||
* RecordID is generated using the same scheme in nsCacheDiskData,
|
||||
* see GetCachedNetData() for detail.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::Contains(const char* key, PRUint32 length, PRBool *_retval)
|
||||
{
|
||||
*_retval = PR_FALSE ;
|
||||
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
PRInt32 id = 0 ;
|
||||
nsresult rv = m_DB->GetID(key, length, &id) ;
|
||||
|
||||
if(NS_FAILED(rv)) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
void* info = 0 ;
|
||||
PRUint32 info_size = 0 ;
|
||||
|
||||
rv = m_DB->Get(id, &info, &info_size) ;
|
||||
if(NS_SUCCEEDED(rv) && info)
|
||||
*_retval = PR_TRUE ;
|
||||
|
||||
if(NS_FAILED(rv)) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
}
|
||||
|
||||
return rv ;
|
||||
}
|
||||
|
||||
/* regardless if it's cached or not, a copy of nsNetDiskCache would
|
||||
* always be returned. so release it appropriately.
|
||||
* if mem alloced, updata m_NumEntries also.
|
||||
* for now, the new nsCachedNetData is not written into db yet since
|
||||
* we have nothing to write.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetCachedNetData(const char* key, PRUint32 length, nsINetDataCacheRecord **_retval)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
nsresult rv = 0 ;
|
||||
if (!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*_retval = nsnull ;
|
||||
|
||||
PRInt32 id = 0 ;
|
||||
rv = m_DB->GetID(key, length, &id) ;
|
||||
if(NS_FAILED(rv)) {
|
||||
// try recovery if error
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
// construct an empty record
|
||||
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
|
||||
if(!newRecord)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
rv = newRecord->Init(key, length, id) ;
|
||||
if(NS_FAILED(rv)) {
|
||||
delete newRecord ;
|
||||
return rv ;
|
||||
}
|
||||
|
||||
NS_ADDREF(newRecord) ; // addref for _retval
|
||||
*_retval = (nsINetDataCacheRecord*) newRecord ;
|
||||
|
||||
void* info = 0 ;
|
||||
PRUint32 info_size = 0 ;
|
||||
|
||||
rv = m_DB->Get(id, &info, &info_size) ;
|
||||
if(NS_SUCCEEDED(rv) && info) {
|
||||
|
||||
// this is a previously cached record
|
||||
nsresult r1 ;
|
||||
r1 = newRecord->RetrieveInfo(info, info_size) ;
|
||||
|
||||
if(NS_SUCCEEDED(rv))
|
||||
return NS_OK ;
|
||||
else {
|
||||
// probably a bad one
|
||||
NS_RELEASE(newRecord) ;
|
||||
*_retval = nsnull ;
|
||||
return r1;
|
||||
}
|
||||
|
||||
} else if (NS_SUCCEEDED(rv) && !info) {
|
||||
// this is a new record.
|
||||
m_NumEntries ++ ;
|
||||
return NS_OK ;
|
||||
} else {
|
||||
// database error.
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
}
|
||||
|
||||
/* get an nsICachedNetData, mem needs to be de-alloced if not found. */
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetCachedNetDataByID(PRInt32 RecordID, nsINetDataCacheRecord **_retval)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
if (!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*_retval = nsnull ;
|
||||
|
||||
nsresult rv ;
|
||||
|
||||
void* info = 0 ;
|
||||
PRUint32 info_size = 0 ;
|
||||
|
||||
rv = m_DB->Get(RecordID, &info, &info_size) ;
|
||||
if(NS_SUCCEEDED(rv) && info) {
|
||||
|
||||
// construct an empty record if only found in db
|
||||
nsDiskCacheRecord* newRecord = new nsDiskCacheRecord(m_DB, this) ;
|
||||
if(!newRecord)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
NS_ADDREF(newRecord) ; // addref for _retval
|
||||
rv = newRecord->RetrieveInfo(info, info_size) ;
|
||||
|
||||
if(NS_SUCCEEDED(rv)) {
|
||||
*_retval = (nsINetDataCacheRecord*) newRecord ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else {
|
||||
// bad record, I guess
|
||||
NS_RELEASE(newRecord) ; // release if bad things happen
|
||||
return rv ;
|
||||
}
|
||||
} else {
|
||||
NS_ERROR("Error: RecordID not in DB\n") ;
|
||||
DBRecovery() ;
|
||||
return rv ;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetEnabled(PRBool *aEnabled)
|
||||
{
|
||||
*aEnabled = m_Enabled ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetEnabled(PRBool aEnabled)
|
||||
{
|
||||
m_Enabled = aEnabled ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetFlags(PRUint32 *aFlags)
|
||||
{
|
||||
*aFlags = FILE_PER_URL_CACHE;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetNumEntries(PRUint32 *aNumEntries)
|
||||
{
|
||||
*aNumEntries = m_NumEntries ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetMaxEntries(PRUint32 *aMaxEntries)
|
||||
{
|
||||
*aMaxEntries = m_MaxEntries ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::NewCacheEntryIterator(nsISimpleEnumerator **_retval)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
if(!_retval)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*_retval = nsnull ;
|
||||
|
||||
nsISimpleEnumerator* enumerator = new nsDBEnumerator(m_DB, this) ;
|
||||
if(enumerator) {
|
||||
NS_ADDREF(enumerator) ;
|
||||
*_retval = enumerator ;
|
||||
return NS_OK ;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetNextCache(nsINetDataCache * *aNextCache)
|
||||
{
|
||||
if(!aNextCache)
|
||||
return NS_ERROR_NULL_POINTER ;
|
||||
|
||||
*aNextCache = m_pNextCache ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetNextCache(nsINetDataCache *aNextCache)
|
||||
{
|
||||
m_pNextCache = aNextCache ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// db size can always be measured at the last minute. Since it's hard
|
||||
// to know before hand.
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetStorageInUse(PRUint32 *aStorageInUse)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
|
||||
PRUint32 total_size = m_StorageInUse ;
|
||||
|
||||
/*
|
||||
PRUint32 len = 0 ;
|
||||
// add the size of the db.
|
||||
m_DB->GetDBFilesize(&len) ;
|
||||
total_size += len ;
|
||||
*/
|
||||
|
||||
// we need size in kB
|
||||
total_size = total_size >> 10 ;
|
||||
|
||||
*aStorageInUse = total_size ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
/*
|
||||
* The whole cache dirs can be whiped clean since all the cache
|
||||
* files are resides in seperate hashed dirs. It's safe to do so.
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::RemoveAll(void)
|
||||
{
|
||||
NS_ASSERTION(m_DB, "no db.") ;
|
||||
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
|
||||
|
||||
// remove all the sub folders
|
||||
nsFileSpec cacheSubDir;
|
||||
|
||||
for (int i=0; i < 32; i++) {
|
||||
m_pDiskCacheFolder->GetFileSpec(&cacheSubDir) ;
|
||||
|
||||
char dirName[3];
|
||||
PR_snprintf (dirName, 3, "%0.2x", i);
|
||||
cacheSubDir += dirName ;
|
||||
RemoveFolder(cacheSubDir) ;
|
||||
}
|
||||
|
||||
// don't forget the db file itself
|
||||
m_DB->Shutdown() ;
|
||||
nsFileSpec dbfile ;
|
||||
m_DBFile->GetFileSpec(&dbfile) ;
|
||||
dbfile.Delete(PR_TRUE) ;
|
||||
|
||||
// reinitilize
|
||||
return Init() ;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// nsINetDataDiskCache methods
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetDiskCacheFolder(nsIFileSpec * *aDiskCacheFolder)
|
||||
{
|
||||
*aDiskCacheFolder = nsnull ;
|
||||
NS_ASSERTION(m_pDiskCacheFolder, "no cache folder.") ;
|
||||
|
||||
*aDiskCacheFolder = m_pDiskCacheFolder ;
|
||||
NS_ADDREF(*aDiskCacheFolder) ;
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetDiskCacheFolder(nsIFileSpec * aDiskCacheFolder)
|
||||
{
|
||||
if(!m_pDiskCacheFolder) {
|
||||
NS_NewFileSpec(getter_AddRefs(m_pDiskCacheFolder));
|
||||
if(!m_pDiskCacheFolder)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
m_pDiskCacheFolder = aDiskCacheFolder ;
|
||||
return Init() ;
|
||||
}
|
||||
else {
|
||||
char *newfolder, *oldfolder ;
|
||||
m_pDiskCacheFolder->GetNativePath(&oldfolder) ;
|
||||
aDiskCacheFolder->GetNativePath(&newfolder) ;
|
||||
|
||||
if(PL_strcmp(newfolder, oldfolder) != 0) {
|
||||
m_pDiskCacheFolder = aDiskCacheFolder ;
|
||||
|
||||
// do we need to blow away old cache before building a new one?
|
||||
// return RemoveAll() ;
|
||||
|
||||
m_DB->Shutdown() ;
|
||||
return Init() ;
|
||||
|
||||
} else
|
||||
return NS_OK ;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// nsNetDiskCache methods
|
||||
|
||||
// create a directory (recursively)
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::CreateDir(nsIFileSpec* dir_spec)
|
||||
{
|
||||
PRBool does_exist ;
|
||||
nsCOMPtr<nsIFileSpec> p_spec ;
|
||||
|
||||
dir_spec->Exists(&does_exist) ;
|
||||
if(does_exist)
|
||||
return NS_OK ;
|
||||
|
||||
nsresult rv = dir_spec->GetParent(getter_AddRefs(p_spec)) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
p_spec->Exists(&does_exist) ;
|
||||
if(!does_exist) {
|
||||
CreateDir(p_spec) ;
|
||||
rv = dir_spec->CreateDir() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
}
|
||||
else {
|
||||
rv = dir_spec->CreateDir() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// We can't afford to make a *separate* pass over the whole db on every
|
||||
// startup, just to figure out m_NumEntries and m_StorageInUse. (This is a
|
||||
// several second operation on a large db). We'll likely need to store
|
||||
// distinguished keys in the db that contain these values and update them
|
||||
// incrementally, except when failure to shut down the db cleanly is detected.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::GetSpecialEntry(void)
|
||||
{
|
||||
void* pInfo ;
|
||||
PRUint32 InfoSize ;
|
||||
|
||||
nsresult rv = m_DB->GetSpecialEntry(&pInfo, &InfoSize) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
if(!pInfo && InfoSize == 0) {
|
||||
// must be a new DB
|
||||
m_NumEntries = 0 ;
|
||||
m_StorageInUse = 0 ;
|
||||
}
|
||||
else {
|
||||
char * cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
|
||||
|
||||
// get m_NumEntries
|
||||
COPY_INT32(&m_NumEntries, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
// get m_StorageInUse
|
||||
COPY_INT32(&m_StorageInUse, cur_ptr) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
|
||||
}
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::SetSpecialEntry(void)
|
||||
{
|
||||
PRUint32 InfoSize ;
|
||||
|
||||
InfoSize = sizeof m_NumEntries ;
|
||||
InfoSize += sizeof m_StorageInUse ;
|
||||
|
||||
void* pInfo = nsAllocator::Alloc(InfoSize*sizeof(char)) ;
|
||||
if(!pInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY ;
|
||||
|
||||
char* cur_ptr = NS_STATIC_CAST(char*, pInfo) ;
|
||||
|
||||
COPY_INT32(cur_ptr, &m_NumEntries) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
COPY_INT32(cur_ptr, &m_StorageInUse) ;
|
||||
cur_ptr += sizeof(PRUint32) ;
|
||||
|
||||
PR_ASSERT(cur_ptr == NS_STATIC_CAST(char*, pInfo) + InfoSize);
|
||||
|
||||
return m_DB->SetSpecialEntry(pInfo, InfoSize) ;
|
||||
}
|
||||
|
||||
// this routine will be called everytime we have a db corruption.
|
||||
// m_DB will be re-initialized, m_StorageInUse and m_NumEntries will
|
||||
// be reset.
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::DBRecovery(void)
|
||||
{
|
||||
// rename all the sub cache dirs and remove them later during dtor.
|
||||
nsresult rv = RenameCacheSubDirs() ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
// remove corrupted db file, don't care if db->shutdown fails or not.
|
||||
m_DB->Shutdown() ;
|
||||
|
||||
nsFileSpec dbfile ;
|
||||
m_DBFile->GetFileSpec(&dbfile) ;
|
||||
dbfile.Delete(PR_TRUE) ;
|
||||
|
||||
// make sure it's not there any more
|
||||
PRBool exists = dbfile.Exists() ;
|
||||
if(exists) {
|
||||
NS_ERROR("can't remove old db.") ;
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
// reinitilize DB
|
||||
return InitDB() ;
|
||||
}
|
||||
|
||||
// this routine will add string "trash" to current CacheSubDir names.
|
||||
// e.g. 00->trash00, 1f->trash1f. and update the m_DBCorrupted.
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::RenameCacheSubDirs(void)
|
||||
{
|
||||
nsCOMPtr<nsIFileSpec> cacheSubDir;
|
||||
nsresult rv = NS_NewFileSpec(getter_AddRefs(cacheSubDir)) ;
|
||||
|
||||
for (int i=0; i < 32; i++) {
|
||||
rv = cacheSubDir->FromFileSpec(m_pDiskCacheFolder) ;
|
||||
if(NS_FAILED(rv))
|
||||
return rv ;
|
||||
|
||||
char oldName[3], newName[8];
|
||||
PR_snprintf(oldName, 3, "%0.2x", i) ;
|
||||
cacheSubDir->AppendRelativeUnixPath(oldName) ;
|
||||
|
||||
// re-name the directory
|
||||
PR_snprintf(newName, 8, "trash%0.2x", i) ;
|
||||
rv = cacheSubDir->Rename(newName) ;
|
||||
if(NS_FAILED(rv))
|
||||
// TODO, error checking
|
||||
return NS_ERROR_FAILURE ;
|
||||
}
|
||||
|
||||
// update m_DBCorrupted
|
||||
m_DBCorrupted = PR_TRUE ;
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
|
||||
// this routine is used by dtor and RemoveAll() to clean up dirs.
|
||||
NS_IMETHODIMP
|
||||
nsNetDiskCache::RemoveFolder(nsFileSpec aFolder)
|
||||
{
|
||||
for(nsDirectoryIterator di(aFolder, PR_FALSE); di.Exists(); di++) {
|
||||
di.Spec().Delete(PR_TRUE) ;
|
||||
}
|
||||
|
||||
aFolder.Delete(PR_FALSE) ; // recursive delete
|
||||
|
||||
return NS_OK ;
|
||||
}
|
||||
91
mozilla/netwerk/cache/filecache/nsNetDiskCache.h
vendored
91
mozilla/netwerk/cache/filecache/nsNetDiskCache.h
vendored
@@ -1,91 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of filecache implementation.
|
||||
*
|
||||
* nsNetDiskCache is the main disk cache module that will create
|
||||
* the cache database, and then store and retrieve nsDiskCacheRecord
|
||||
* objects from it. It also contains some basic error recovery procedure.
|
||||
*/
|
||||
|
||||
#ifndef __gen_nsNetDiskCache_h__
|
||||
#define __gen_nsNetDiskCache_h__
|
||||
|
||||
#include "nsINetDataDiskCache.h"
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPref.h"
|
||||
#include "nsDBAccessor.h"
|
||||
|
||||
class nsIURI; /* forward decl */
|
||||
class nsICachedNetData; /* forward decl */
|
||||
class nsISimpleEnumerator; /* forward decl */
|
||||
class nsIFileSpec; /* forward decl */
|
||||
|
||||
/* starting interface: nsNetDiskCache */
|
||||
|
||||
class nsNetDiskCache : public nsINetDataDiskCache {
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETDATACACHE
|
||||
NS_DECL_NSINETDATADISKCACHE
|
||||
|
||||
NS_IMETHOD Init(void) ;
|
||||
|
||||
nsNetDiskCache() ;
|
||||
virtual ~nsNetDiskCache() ;
|
||||
|
||||
protected:
|
||||
|
||||
NS_IMETHOD InitDB(void) ;
|
||||
NS_IMETHOD CreateDir(nsIFileSpec* dir_spec) ;
|
||||
NS_IMETHOD GetSpecialEntry(void) ;
|
||||
NS_IMETHOD SetSpecialEntry(void) ;
|
||||
|
||||
NS_IMETHOD RenameCacheSubDirs(void) ;
|
||||
NS_IMETHOD DBRecovery(void) ;
|
||||
NS_IMETHOD RemoveFolder(nsFileSpec aFolder) ;
|
||||
|
||||
private:
|
||||
|
||||
PRBool m_Enabled ;
|
||||
PRUint32 m_NumEntries ;
|
||||
nsCOMPtr<nsINetDataCache> m_pNextCache ;
|
||||
nsCOMPtr<nsIFileSpec> m_pDiskCacheFolder ;
|
||||
nsCOMPtr<nsIFileSpec> m_DBFile ;
|
||||
|
||||
PRUint32 m_MaxEntries ;
|
||||
PRUint32 m_StorageInUse ;
|
||||
nsIDBAccessor* m_DB ;
|
||||
|
||||
// this is used to indicate a db corruption
|
||||
PRBool m_DBCorrupted ;
|
||||
|
||||
friend class nsDiskCacheRecord ;
|
||||
friend class nsDiskCacheRecordChannel ;
|
||||
friend class nsDBEnumerator ;
|
||||
} ;
|
||||
|
||||
#endif /* __gen_nsNetDiskCache_h__ */
|
||||
@@ -1,32 +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 Mozilla Communicator.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Intel Corp.
|
||||
* Portions created by Intel Corp. are
|
||||
* Copyright (C) 1999, 1999 Intel Corp. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Yixiong Zou <yixiong.zou@intel.com>
|
||||
* Carl Wong <carl.wong@intel.com>
|
||||
*/
|
||||
|
||||
#ifndef _nsNetDiskCacheCID_h_
|
||||
#define _nsNetDiskCacheCID_h_
|
||||
|
||||
#define NS_NETDISKCACHE_CID_STR "ECFEEA00-7201-11d3-87FE-000629D01344"
|
||||
|
||||
#define NS_NETDISKCACHE_CID \
|
||||
{ 0xecfeea00, 0x7201, 0x11d3, \
|
||||
{ 0x87, 0xfe, 0x0, 0x6, 0x29, 0xd0, 0x13, 0x44 }}
|
||||
|
||||
#endif /* _nsNetDiskCacheCID_h_ */
|
||||
50
mozilla/netwerk/cache/filecache/test/Makefile.in
vendored
50
mozilla/netwerk/cache/filecache/test/Makefile.in
vendored
@@ -1,50 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
REQUIRES = libreg xpcom
|
||||
|
||||
CPPSRCS = \
|
||||
diskcache.cpp \
|
||||
$(NULL)
|
||||
|
||||
SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=)
|
||||
|
||||
ifdef NO_LD_ARCHIVE_FLAGS
|
||||
LOST_SYM_LIBS = -lxpcomds_s -lxptinfo -lmozreg_s
|
||||
endif
|
||||
|
||||
LIBS = \
|
||||
-lmozjs \
|
||||
-lxpcom \
|
||||
-lmozdbm_s \
|
||||
$(MOZ_NECKO_UTIL_LIBS) \
|
||||
$(LOST_SYM_LIBS) \
|
||||
$(NSPR_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/..
|
||||
|
||||
DEFINES += -DUSE_NSREG -DCACHE
|
||||
836
mozilla/netwerk/cache/filecache/test/diskcache.cpp
vendored
836
mozilla/netwerk/cache/filecache/test/diskcache.cpp
vendored
@@ -1,836 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamObserver.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
//#include "nsMemCacheCID.h"
|
||||
#include "nsNetDiskCache.h"
|
||||
#include "nsIPref.h"
|
||||
#include "prenv.h"
|
||||
#include "nsIFileStream.h"
|
||||
|
||||
// Number of test entries to be placed in the cache
|
||||
#define NUM_CACHE_ENTRIES 250
|
||||
|
||||
// Cache content stream length will have random length between zero and
|
||||
// MAX_CONTENT_LENGTH bytes
|
||||
#define MAX_CONTENT_LENGTH 20000
|
||||
|
||||
// Length of random-data cache entry key
|
||||
#define CACHE_KEY_LENGTH 15
|
||||
|
||||
// Length of random-data cache entry meta-data
|
||||
#define CACHE_METADATA_LENGTH 100
|
||||
|
||||
//static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
|
||||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
|
||||
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
|
||||
|
||||
// Mapping from test case number to RecordID
|
||||
static PRInt32 recordID[NUM_CACHE_ENTRIES];
|
||||
|
||||
static PRInt32
|
||||
mapRecordIdToTestNum(PRInt32 aRecordID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
|
||||
if (recordID[i] == aRecordID)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// A supply of stream data to either store or compare with
|
||||
class nsITestDataStream {
|
||||
public:
|
||||
virtual ~nsITestDataStream() {};
|
||||
virtual PRUint32 Next() = 0;
|
||||
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
|
||||
|
||||
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void Skip(PRUint32 aCount) = 0;
|
||||
};
|
||||
|
||||
// A reproducible stream of random data.
|
||||
class RandomStream : public nsITestDataStream {
|
||||
public:
|
||||
RandomStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState = 1103515245 * mState + 12345;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(Next() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
Next();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
// A stream of data that increments on each byte that is read, modulo 256
|
||||
class CounterStream : public nsITestDataStream {
|
||||
public:
|
||||
CounterStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState += 1;
|
||||
mState &= 0xff;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)Next())
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
mState += aCount;
|
||||
mState &= 0xff;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
static int gNumReaders = 0;
|
||||
static PRUint32 gTotalBytesRead = 0;
|
||||
static PRUint32 gTotalDuration = 0;
|
||||
|
||||
class nsReader : public nsIStreamListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsReader()
|
||||
: mStartTime(0), mBytesRead(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
gNumReaders++;
|
||||
}
|
||||
|
||||
virtual ~nsReader() {
|
||||
delete mTestDataStream;
|
||||
gNumReaders--;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init(nsIChannel *aChannel, nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
|
||||
mChannel = aChannel;
|
||||
mTestDataStream = aRandomStream;
|
||||
mExpectedStreamLength = aExpectedStreamLength;
|
||||
mRefCnt = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStartRequest(nsIChannel* channel,
|
||||
nsISupports* context) {
|
||||
mStartTime = PR_IntervalNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aSourceOffset,
|
||||
PRUint32 aLength) {
|
||||
char buf[1025];
|
||||
while (aLength > 0) {
|
||||
PRUint32 amt;
|
||||
PRBool match;
|
||||
aIStream->Read(buf, sizeof buf, &amt);
|
||||
if (amt == 0) break;
|
||||
aLength -= amt;
|
||||
mBytesRead += amt;
|
||||
match = mTestDataStream->Match(buf, amt);
|
||||
NS_ASSERTION(match, "Stored data was corrupted on read");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStopRequest(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsresult aStatus,
|
||||
const PRUnichar* aMsg) {
|
||||
PRIntervalTime endTime;
|
||||
PRIntervalTime duration;
|
||||
|
||||
endTime = PR_IntervalNow();
|
||||
duration = (endTime - mStartTime);
|
||||
|
||||
if (NS_FAILED(aStatus)) printf("channel failed.\n");
|
||||
// printf("read %d bytes\n", mBytesRead);
|
||||
|
||||
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
|
||||
"Stream in cache is wrong length");
|
||||
|
||||
gTotalBytesRead += mBytesRead;
|
||||
gTotalDuration += duration;
|
||||
|
||||
// Release channel
|
||||
mChannel = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
PRIntervalTime mStartTime;
|
||||
PRUint32 mBytesRead;
|
||||
nsITestDataStream* mTestDataStream;
|
||||
PRUint32 mExpectedStreamLength;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
static nsIEventQueue* eventQueue;
|
||||
|
||||
nsresult
|
||||
InitQueue() {
|
||||
nsresult rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
|
||||
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Process events until all streams are OnStopRequest'ed
|
||||
nsresult
|
||||
WaitForEvents() {
|
||||
while (gNumReaders) {
|
||||
eventQueue->ProcessPendingEvents();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read data for a single cache record and compare against testDataStream
|
||||
nsresult
|
||||
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
|
||||
PRUint32 expectedStreamLength)
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv;
|
||||
PRUint32 actualContentLength;
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = record->GetStoredContentLength(&actualContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(actualContentLength == expectedStreamLength,
|
||||
"nsINetDataCacheRecord::GetContentLength() busted ?");
|
||||
|
||||
nsReader *reader = new nsReader;
|
||||
reader->AddRef();
|
||||
rv = reader->Init(channel, testDataStream, expectedStreamLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->AsyncRead(0, -1, 0, reader);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
reader->Release();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that records can be retrieved using their record-ID, in addition
|
||||
// to using the opaque key.
|
||||
nsresult
|
||||
TestRecordID(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
|
||||
nsAllocator::Free(metaData);
|
||||
delete randomStream;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that all cache entries in the database are enumerated and that
|
||||
// no duplicates appear.
|
||||
nsresult
|
||||
TestEnumeration(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsISupports> tempISupports;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
PRInt32 recID;
|
||||
|
||||
int numRecords = 0;
|
||||
|
||||
// Iterate over all records in the cache
|
||||
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
|
||||
|
||||
PRBool notDone;
|
||||
while (1) {
|
||||
|
||||
// Done iterating ?
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
// Get next record in iteration
|
||||
rv = iterator->GetNext(getter_AddRefs(tempISupports));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
|
||||
record = do_QueryInterface(tempISupports);
|
||||
|
||||
numRecords++;
|
||||
|
||||
// Get record ID
|
||||
rv = record->GetRecordID(&recID);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
testNum = mapRecordIdToTestNum(recID);
|
||||
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
|
||||
|
||||
// Erase mapping from table, so that duplicate enumerations are detected
|
||||
recordID[testNum] = -1;
|
||||
|
||||
// Make sure stream matches test data
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read the test data that was written in FillCache(), checking for
|
||||
// corruption, truncation.
|
||||
nsresult
|
||||
TestRead(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData, *storedCacheKey;
|
||||
PRUint32 testNum, storedCacheKeyLength;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Ensure that entry is in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
match = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
// Test GetKey() method
|
||||
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
(storedCacheKeyLength == sizeof cacheKey) &&
|
||||
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
|
||||
"nsINetDataCacheRecord::GetKey failed");
|
||||
nsAllocator::Free(storedCacheKey);
|
||||
|
||||
PRUint32 expectedStreamLength = randomStream->Next() & 0xffff;
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
}
|
||||
|
||||
WaitForEvents();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
|
||||
rate *= NUM_CACHE_ENTRIES;
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Read %d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesRead, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Repeatedly call SetStoredContentLength() on a cache entry and make
|
||||
// read the stream's data to ensure that it's not corrupted by the effect
|
||||
nsresult
|
||||
TestTruncation(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
randomStream->Skip(CACHE_METADATA_LENGTH);
|
||||
PRUint32 initialStreamLength = randomStream->Next() & 0xffff;
|
||||
delete randomStream;
|
||||
|
||||
PRUint32 i;
|
||||
PRUint32 delta = initialStreamLength / 64;
|
||||
for (i = initialStreamLength; i >= delta; i -= delta) {
|
||||
PRUint32 expectedStreamLength = i;
|
||||
|
||||
// Do the truncation
|
||||
record->SetStoredContentLength(expectedStreamLength);
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
WaitForEvents();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write known data to random offsets in a single cache entry and test
|
||||
// resulting stream for correctness.
|
||||
nsresult
|
||||
TestOffsetWrites(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[512];
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
RandomStream *randomStream;
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
|
||||
nsCOMPtr<nsIFileSpec> file ;
|
||||
record->GetFilename(getter_AddRefs(file)) ;
|
||||
char* name ;
|
||||
file->GetUnixStyleFilePath(&name) ;
|
||||
printf(" file name is %s \n", name) ;
|
||||
|
||||
// Write buffer-fulls of data at random offsets into the cache entry.
|
||||
// Data written is (offset % 0xff)
|
||||
PRUint32 startingOffset;
|
||||
PRUint32 streamLength = 0;
|
||||
PRUint32 len = 0 ;
|
||||
CounterStream *counterStream;
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; i < 257; i++) {
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
|
||||
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
truncate(name, startingOffset) ;
|
||||
|
||||
counterStream = new CounterStream(startingOffset);
|
||||
counterStream->Read(buf, sizeof buf);
|
||||
|
||||
nsresult status ;
|
||||
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
|
||||
if (NS_FAILED(status)) {
|
||||
// mState = END_WRITE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
PRIntn offset ;
|
||||
ras->Tell(&offset) ;
|
||||
// printf(" offset is %d \n", offset) ;
|
||||
|
||||
PRUint32 numWritten;
|
||||
rv = outStream->Write(buf, sizeof buf, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
|
||||
streamLength = startingOffset + sizeof buf;
|
||||
|
||||
rv = outStream->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
|
||||
delete counterStream;
|
||||
|
||||
record->GetStoredContentLength(&len) ;
|
||||
if(len != streamLength)
|
||||
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
startingOffset = 208;
|
||||
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
counterStream = new CounterStream(startingOffset);
|
||||
counterStream->Read(buf, sizeof buf);
|
||||
|
||||
nsresult status ;
|
||||
nsCOMPtr<nsIRandomAccessStore> ras = do_QueryInterface(outStream, &status);
|
||||
if (NS_FAILED(status)) {
|
||||
// mState = END_WRITE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
PRIntn offset = 0 ;
|
||||
ras->Tell(&offset) ;
|
||||
printf(" offset is %d \n", offset) ;
|
||||
|
||||
PRUint32 numWritten;
|
||||
rv = outStream->Write(buf, sizeof buf, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
|
||||
streamLength = startingOffset + sizeof buf;
|
||||
|
||||
rv = outStream->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
|
||||
delete counterStream;
|
||||
|
||||
record->GetStoredContentLength(&len) ;
|
||||
if(len != streamLength)
|
||||
printf(" offset = %d is wrong, filesize = %d\n", startingOffset, len) ;
|
||||
*/
|
||||
|
||||
delete randomStream;
|
||||
|
||||
counterStream = new CounterStream(0);
|
||||
TestReadStream(record, counterStream, streamLength);
|
||||
WaitForEvents();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create entries in the network data cache, using random data for the
|
||||
// key, the meta-data and the stored content data.
|
||||
nsresult
|
||||
FillCache(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[1000];
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char metaData[CACHE_METADATA_LENGTH];
|
||||
PRUint32 testNum;
|
||||
char *data;
|
||||
RandomStream *randomStream;
|
||||
|
||||
PRIntervalTime startTime = PR_IntervalNow();
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// No entry should be in cache until we add it
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
// Test nsINetDataCacheRecord::GetRecordID()
|
||||
rv = record->GetRecordID(&recordID[testNum]);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
|
||||
// Test nsINetDataCache::GetNumEntries()
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
|
||||
|
||||
// Record meta-data should be initially empty
|
||||
rv = record->GetMetaData(&metaDataLength, &data);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
if ((metaDataLength != 0) || (data != 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Store random data as meta-data
|
||||
randomStream->Read(metaData, sizeof metaData);
|
||||
record->SetMetaData(sizeof metaData, metaData);
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
PRUint32 beforeOccupancy;
|
||||
rv = cache->GetStorageInUse(&beforeOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
int streamLength = randomStream->Next() & 0xffff;
|
||||
int remaining = streamLength;
|
||||
while (remaining) {
|
||||
PRUint32 numWritten;
|
||||
int amount = PR_MIN(sizeof buf, remaining);
|
||||
randomStream->Read(buf, amount);
|
||||
|
||||
rv = outStream->Write(buf, amount, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
|
||||
|
||||
remaining -= amount;
|
||||
}
|
||||
outStream->Close();
|
||||
|
||||
PRUint32 afterOccupancy;
|
||||
rv = cache->GetStorageInUse(&afterOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
PRUint32 streamLengthInKB = streamLength >> 10;
|
||||
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
|
||||
"nsINetDataCache::GetStorageInUse() is busted");
|
||||
|
||||
|
||||
// *Now* there should be an entry in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_AutoregisterComponents()
|
||||
{
|
||||
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
NULL /* default */);
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRBool initPref ()
|
||||
{
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCOMPtr<nsIFileSpec> fileSpec;
|
||||
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
|
||||
if (defaultPrefFile.Length())
|
||||
defaultPrefFile += "/";
|
||||
else
|
||||
defaultPrefFile = "./";
|
||||
defaultPrefFile += "default_prefs.js";
|
||||
|
||||
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
|
||||
|
||||
PRBool exists = false;
|
||||
fileSpec->Exists(&exists);
|
||||
if (exists)
|
||||
prefPtr->ReadUserPrefsFrom(fileSpec);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
initPref() ;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
|
||||
rv = NS_AutoregisterComponents();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
|
||||
|
||||
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(cache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
|
||||
|
||||
InitQueue();
|
||||
|
||||
PRUnichar* description;
|
||||
rv = cache->GetDescription(&description);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
|
||||
nsCAutoString descStr(description);
|
||||
printf("Testing: %s\n", descStr.GetBuffer());
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
PRUint32 startOccupancy;
|
||||
rv = cache->GetStorageInUse(&startOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
rv = FillCache(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
|
||||
|
||||
rv = TestRead(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
|
||||
|
||||
rv = TestRecordID(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
|
||||
|
||||
rv = TestEnumeration(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
|
||||
|
||||
rv = TestTruncation(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
|
||||
|
||||
rv = TestOffsetWrites(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
PRUint32 endOccupancy;
|
||||
rv = cache->GetStorageInUse(&endOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
48
mozilla/netwerk/cache/memcache/Makefile.in
vendored
48
mozilla/netwerk/cache/memcache/Makefile.in
vendored
@@ -1,48 +0,0 @@
|
||||
# Generated automatically from Makefile.in by configure.
|
||||
#
|
||||
# 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@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkmemcache_s
|
||||
|
||||
REQUIRES = nspr dbm
|
||||
|
||||
EXPORTS=nsMemCacheCID.h \
|
||||
nsMemCache.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsMemCache.cpp \
|
||||
nsMemCacheRecord.cpp \
|
||||
nsMemCacheChannel.cpp \
|
||||
$(NULL)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
override NO_SHARED_LIB=1
|
||||
override NO_STATIC_LIB=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
42
mozilla/netwerk/cache/memcache/makefile.win
vendored
42
mozilla/netwerk/cache/memcache/makefile.win
vendored
@@ -1,42 +0,0 @@
|
||||
#!nmake
|
||||
#
|
||||
# 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.mak>
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkmemcache_s
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsMemCache.obj \
|
||||
.\$(OBJDIR)\nsMemCacheRecord.obj \
|
||||
.\$(OBJDIR)\nsMemCacheChannel.obj \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS=nsMemCacheCID.h
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -rf $(OBJDIR)
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
|
||||
334
mozilla/netwerk/cache/memcache/nsMemCache.cpp
vendored
334
mozilla/netwerk/cache/memcache/nsMemCache.cpp
vendored
@@ -1,334 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* nsMemCache is the implementation of an in-memory network-data
|
||||
* cache, used to cache the responses to network retrieval commands.
|
||||
* Each cache entry may contain both content, e.g. GIF image data, and
|
||||
* associated metadata, e.g. HTTP headers. Each entry is indexed by
|
||||
* two different keys: a record id number and an opaque key, which is
|
||||
* created by the cache manager by combining the URI with a "secondary
|
||||
* key", e.g. HTTP post data.
|
||||
*/
|
||||
|
||||
#include "nsMemCache.h"
|
||||
#include "nsMemCacheRecord.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsString.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsHashtableEnumerator.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
|
||||
PRInt32 nsMemCache::gRecordSerialNumber = 0;
|
||||
|
||||
nsMemCache::nsMemCache()
|
||||
: mNumEntries(0), mOccupancy(0), mEnabled(PR_TRUE),
|
||||
mHashTable(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsMemCache::~nsMemCache()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (mNumEntries == 0),
|
||||
"Failure to shut down memory cache. "
|
||||
"Somewhere, someone is holding references to at least one cache record");
|
||||
delete mHashTable;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMemCache::Init()
|
||||
{
|
||||
mHashTable = new nsHashtable(256);
|
||||
if (!mHashTable)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMemCache, NS_GET_IID(nsINetDataCache))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetDescription(PRUnichar * *aDescription)
|
||||
{
|
||||
nsAutoString description("Memory Cache");
|
||||
*aDescription = description.ToNewUnicode();
|
||||
if (!*aDescription)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::Contains(const char *aKey, PRUint32 aKeyLength, PRBool *aFound)
|
||||
{
|
||||
nsOpaqueKey *opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
|
||||
if (!opaqueKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
*aFound = mHashTable->Exists(opaqueKey);
|
||||
delete opaqueKey;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetCachedNetData(const char *aKey, PRUint32 aKeyLength,
|
||||
nsINetDataCacheRecord* *aRecord)
|
||||
{
|
||||
nsresult rv;
|
||||
nsMemCacheRecord* record = 0;
|
||||
nsOpaqueKey *opaqueKey2 = 0;
|
||||
nsOpaqueKey *opaqueKey3 = 0;
|
||||
nsOpaqueKey *opaqueKey;
|
||||
|
||||
opaqueKey = new nsOpaqueKey(aKey, aKeyLength);
|
||||
if (!opaqueKey)
|
||||
goto out_of_memory;
|
||||
record = (nsMemCacheRecord*)mHashTable->Get(opaqueKey);
|
||||
delete opaqueKey;
|
||||
|
||||
// No existing cache database entry was found. Create a new one.
|
||||
// This requires two mappings in the hash table:
|
||||
// Record ID ==> record
|
||||
// Opaque key ==> record
|
||||
if (!record) {
|
||||
record = new nsMemCacheRecord;
|
||||
if (!record)
|
||||
goto out_of_memory;
|
||||
rv = record->Init(aKey, aKeyLength, ++gRecordSerialNumber, this);
|
||||
if (NS_FAILED(rv)) goto out_of_memory;
|
||||
|
||||
// Index the record by opaque key
|
||||
opaqueKey2 = new nsOpaqueKey(record->mKey, record->mKeyLength);
|
||||
if (!opaqueKey2) goto out_of_memory;
|
||||
mHashTable->Put(opaqueKey2, record);
|
||||
|
||||
// Index the record by it's record ID
|
||||
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &record->mRecordID);
|
||||
opaqueKey3 = new nsOpaqueKey(recordIDbytes,
|
||||
sizeof record->mRecordID);
|
||||
if (!opaqueKey3) {
|
||||
// Clean up the first record from the hash table
|
||||
mHashTable->Remove(opaqueKey);
|
||||
goto out_of_memory;
|
||||
}
|
||||
mHashTable->Put(opaqueKey3, record);
|
||||
|
||||
// The hash table holds on to the record
|
||||
record->AddRef();
|
||||
|
||||
delete opaqueKey2;
|
||||
delete opaqueKey3;
|
||||
mNumEntries++;
|
||||
}
|
||||
|
||||
record->AddRef();
|
||||
*aRecord = record;
|
||||
return NS_OK;
|
||||
|
||||
out_of_memory:
|
||||
delete opaqueKey2;
|
||||
delete opaqueKey3;
|
||||
delete record;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetCachedNetDataByID(PRInt32 RecordID,
|
||||
nsINetDataCacheRecord* *aRecord)
|
||||
{
|
||||
nsOpaqueKey opaqueKey(NS_REINTERPRET_CAST(const char *, &RecordID),
|
||||
sizeof RecordID);
|
||||
*aRecord = (nsINetDataCacheRecord*)mHashTable->Get(&opaqueKey);
|
||||
if (*aRecord) {
|
||||
NS_ADDREF(*aRecord);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsMemCache::Delete(nsMemCacheRecord* aRecord)
|
||||
{
|
||||
nsMemCacheRecord *removedRecord;
|
||||
|
||||
char *recordIDbytes = NS_REINTERPRET_CAST(char *, &aRecord->mRecordID);
|
||||
nsOpaqueKey opaqueRecordIDKey(recordIDbytes,
|
||||
sizeof aRecord->mRecordID);
|
||||
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueRecordIDKey);
|
||||
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
|
||||
|
||||
nsOpaqueKey opaqueKey(aRecord->mKey, aRecord->mKeyLength);
|
||||
removedRecord = (nsMemCacheRecord*)mHashTable->Remove(&opaqueKey);
|
||||
NS_ASSERTION(removedRecord == aRecord, "memory cache database inconsistent");
|
||||
|
||||
aRecord->Release();
|
||||
|
||||
mNumEntries--;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetEnabled(PRBool *aEnabled)
|
||||
{
|
||||
NS_ENSURE_ARG(aEnabled);
|
||||
*aEnabled = mEnabled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::SetEnabled(PRBool aEnabled)
|
||||
{
|
||||
mEnabled = aEnabled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetFlags(PRUint32 *aFlags)
|
||||
{
|
||||
NS_ENSURE_ARG(aFlags);
|
||||
*aFlags = MEMORY_CACHE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetNumEntries(PRUint32 *aNumEntries)
|
||||
{
|
||||
NS_ENSURE_ARG(aNumEntries);
|
||||
*aNumEntries = mNumEntries;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetMaxEntries(PRUint32 *aMaxEntries)
|
||||
{
|
||||
NS_ENSURE_ARG(aMaxEntries);
|
||||
*aMaxEntries = MEM_CACHE_MAX_ENTRIES;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_METHOD
|
||||
HashEntryConverter(nsHashKey *aKey, void *aValue,
|
||||
void *unused, nsISupports **retval)
|
||||
{
|
||||
nsMemCacheRecord *record;
|
||||
nsOpaqueKey *opaqueKey;
|
||||
|
||||
record = (nsMemCacheRecord*)aValue;
|
||||
opaqueKey = (nsOpaqueKey*)aKey;
|
||||
|
||||
// Hash table keys that index cache entries by their record ID
|
||||
// shouldn't be enumerated.
|
||||
if ((opaqueKey->GetKeyLength() == sizeof(PRInt32))) {
|
||||
|
||||
#ifdef DEBUG
|
||||
PRInt32 recordID;
|
||||
record->GetRecordID(&recordID);
|
||||
NS_ASSERTION(*((PRInt32*)opaqueKey->GetKey()) == recordID,
|
||||
"Key has incorrect key length");
|
||||
#endif
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(record);
|
||||
*retval = NS_STATIC_CAST(nsISupports*, record);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::NewCacheEntryIterator(nsISimpleEnumerator* *aIterator)
|
||||
{
|
||||
nsCOMPtr<nsIEnumerator> iterator;
|
||||
|
||||
NS_ENSURE_ARG(aIterator);
|
||||
NS_NewHashtableEnumerator(mHashTable, HashEntryConverter,
|
||||
mHashTable, getter_AddRefs(iterator));
|
||||
return NS_NewAdapterEnumerator(aIterator, iterator);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetNextCache(nsINetDataCache* *aNextCache)
|
||||
{
|
||||
NS_ENSURE_ARG(aNextCache);
|
||||
*aNextCache = mNextCache;
|
||||
NS_ADDREF(*aNextCache);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::SetNextCache(nsINetDataCache* aNextCache)
|
||||
{
|
||||
mNextCache = aNextCache;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::GetStorageInUse(PRUint32 *aStorageInUse)
|
||||
{
|
||||
NS_ENSURE_ARG(aStorageInUse);
|
||||
|
||||
// Convert from bytes to KB
|
||||
*aStorageInUse = (mOccupancy >> 10);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCache::RemoveAll(void)
|
||||
{
|
||||
PRBool failed;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsISupports> recordSupports;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsresult rv;
|
||||
|
||||
failed = PR_FALSE;
|
||||
rv = NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRBool notDone;
|
||||
while (1) {
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
iterator->GetNext(getter_AddRefs(recordSupports));
|
||||
record = do_QueryInterface(recordSupports);
|
||||
recordSupports = 0;
|
||||
|
||||
PRUint32 bytesUsed;
|
||||
record->GetStoredContentLength(&bytesUsed);
|
||||
rv = record->Delete();
|
||||
if (NS_FAILED(rv)) {
|
||||
failed = PR_TRUE;
|
||||
continue;
|
||||
}
|
||||
mOccupancy -= bytesUsed;
|
||||
}
|
||||
|
||||
if (failed)
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
83
mozilla/netwerk/cache/memcache/nsMemCache.h
vendored
83
mozilla/netwerk/cache/memcache/nsMemCache.h
vendored
@@ -1,83 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* nsMemCache is the implementation of an in-memory network-data
|
||||
* cache, used to cache the responses to network retrieval commands.
|
||||
* Each cache entry may contain both content, e.g. GIF image data, and
|
||||
* associated metadata, e.g. HTTP headers. Each entry is indexed by
|
||||
* two different keys: a record id number and an opaque key, which is
|
||||
* created by the cache manager by combining the URI with a "secondary
|
||||
* key", e.g. HTTP post data.
|
||||
*/
|
||||
|
||||
#ifndef _nsMemCache_h_
|
||||
#define _nsMemCache_h_
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
|
||||
// Maximum number of URIs that may be resident in the cache
|
||||
#define MEM_CACHE_MAX_ENTRIES 1000
|
||||
|
||||
#define MEM_CACHE_SEGMENT_SIZE (1 << 12)
|
||||
#define MEM_CACHE_MAX_ENTRY_SIZE (1 << 20)
|
||||
|
||||
class nsHashtable;
|
||||
class nsMemCacheRecord;
|
||||
|
||||
class nsMemCache : public nsINetDataCache
|
||||
{
|
||||
public:
|
||||
nsMemCache();
|
||||
virtual ~nsMemCache();
|
||||
nsresult Init();
|
||||
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsINetDataCache methods
|
||||
NS_DECL_NSINETDATACACHE
|
||||
|
||||
// Factory
|
||||
static NS_METHOD nsMemCacheConstructor(nsISupports *aOuter, REFNSIID aIID,
|
||||
void **aResult);
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mNumEntries;
|
||||
PRUint32 mOccupancy; // Memory used, in bytes
|
||||
PRBool mEnabled; // If false, bypass mem cache
|
||||
|
||||
nsINetDataCache* mNextCache;
|
||||
|
||||
// Mapping from either opaque key or record ID to nsMemCacheRecord
|
||||
nsHashtable* mHashTable;
|
||||
|
||||
// Used to assign record ID's
|
||||
static PRInt32 gRecordSerialNumber;
|
||||
|
||||
NS_METHOD Delete(nsMemCacheRecord* aRecord);
|
||||
|
||||
friend class nsMemCacheRecord;
|
||||
friend class nsMemCacheChannel;
|
||||
};
|
||||
|
||||
#endif // _nsMemCache_h_
|
||||
36
mozilla/netwerk/cache/memcache/nsMemCacheCID.h
vendored
36
mozilla/netwerk/cache/memcache/nsMemCacheCID.h
vendored
@@ -1,36 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
// XPCOM Class ID for the network data in-memory cache
|
||||
|
||||
#ifndef nsMEMCACHECID_h__
|
||||
#define nsMEMCACHECID_h__
|
||||
|
||||
// {e4710560-7de2-11d3-90cb-0040056a906e}
|
||||
#define NS_MEM_CACHE_FACTORY_CID \
|
||||
{ \
|
||||
0xe4710560, \
|
||||
0x7de2, \
|
||||
0x11d3, \
|
||||
{0x90, 0xcb, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
|
||||
}
|
||||
|
||||
#endif // nsMEMCACHECID_h__
|
||||
462
mozilla/netwerk/cache/memcache/nsMemCacheChannel.cpp
vendored
462
mozilla/netwerk/cache/memcache/nsMemCacheChannel.cpp
vendored
@@ -1,462 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsMemCache.h"
|
||||
#include "nsMemCacheChannel.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsILoadGroup.h"
|
||||
|
||||
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMemCacheChannel, NS_GET_IID(nsIChannel))
|
||||
|
||||
void
|
||||
nsMemCacheChannel::NotifyStorageInUse(PRInt32 aBytesUsed)
|
||||
{
|
||||
mRecord->mCache->mOccupancy += aBytesUsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class acts as an adaptor around a synchronous input stream to add async
|
||||
* read capabilities. It adds methods for initiating, suspending, resuming and
|
||||
* cancelling async reads.
|
||||
*/
|
||||
class AsyncReadStreamAdaptor : public nsIInputStream {
|
||||
public:
|
||||
AsyncReadStreamAdaptor(nsMemCacheChannel* aChannel, nsIInputStream *aSyncStream):
|
||||
mSyncStream(aSyncStream), mDataAvailCursor(0),
|
||||
mRemaining(0), mAvailable(0), mChannel(aChannel), mAborted(PR_FALSE), mSuspended(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mChannel);
|
||||
}
|
||||
|
||||
virtual ~AsyncReadStreamAdaptor() {
|
||||
mChannel->mAsyncReadStream = 0;
|
||||
NS_RELEASE(mChannel);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsresult
|
||||
IsPending(PRBool* aIsPending) {
|
||||
*aIsPending = (mRemaining != 0) && !mAborted;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Cancel(void) {
|
||||
mAborted = PR_TRUE;
|
||||
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_ABORTED, nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Suspend(void) { mSuspended = PR_TRUE; return NS_OK; }
|
||||
|
||||
nsresult
|
||||
Resume(void) {
|
||||
if (!mSuspended)
|
||||
return NS_ERROR_FAILURE;
|
||||
mSuspended = PR_FALSE;
|
||||
return NextListenerEvent();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Available(PRUint32 *aNumBytes) { return mAvailable; }
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuf, PRUint32 aCount, PRUint32 *aBytesRead) {
|
||||
if (mAborted)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
*aBytesRead = 0;
|
||||
aCount = PR_MIN(aCount, mAvailable);
|
||||
nsresult rv = mSyncStream->Read(aBuf, aCount, aBytesRead);
|
||||
mAvailable -= *aBytesRead;
|
||||
|
||||
if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
|
||||
Fail();
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!mSuspended && !mAvailable) {
|
||||
rv = NextListenerEvent();
|
||||
if (NS_FAILED(rv)) {
|
||||
Fail();
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Close() {
|
||||
nsresult rv = mSyncStream->Close();
|
||||
mSyncStream = 0;
|
||||
mContext = 0;
|
||||
mStreamListener = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports* aContext, nsIStreamListener* aListener) {
|
||||
|
||||
nsresult rv;
|
||||
nsIEventQueue *eventQ;
|
||||
|
||||
mContext = aContext;
|
||||
mStreamListener = aListener;
|
||||
mRemaining = aReadCount;
|
||||
|
||||
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueService, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQ);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewAsyncStreamListener(aListener, eventQ,
|
||||
getter_AddRefs(mStreamListener));
|
||||
NS_RELEASE(eventQ);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mStreamListener->OnStartRequest(mChannel, aContext);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NextListenerEvent();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
nsresult
|
||||
Fail(void) {
|
||||
mAborted = PR_TRUE;
|
||||
return mStreamListener->OnStopRequest(mChannel, mContext, NS_BINDING_FAILED, nsnull);
|
||||
}
|
||||
|
||||
nsresult
|
||||
NextListenerEvent() {
|
||||
PRUint32 available;
|
||||
nsresult rv = mSyncStream->Available(&available);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
available -= mAvailable;
|
||||
available = PR_MIN(available, mRemaining);
|
||||
|
||||
if (available) {
|
||||
PRUint32 size = PR_MIN(available, MEM_CACHE_SEGMENT_SIZE);
|
||||
rv = mStreamListener->OnDataAvailable(mChannel, mContext, this,
|
||||
mDataAvailCursor, size);
|
||||
mDataAvailCursor += size;
|
||||
mRemaining -= size;
|
||||
mAvailable += size;
|
||||
return rv;
|
||||
} else {
|
||||
rv = mStreamListener->OnStopRequest(mChannel, mContext, NS_OK, nsnull);
|
||||
AsyncReadStreamAdaptor* thisAlias = this;
|
||||
NS_RELEASE(thisAlias);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mContext; // Opaque context passed to AsyncRead()
|
||||
nsCOMPtr<nsIStreamListener> mStreamListener; // Stream listener that has been proxied
|
||||
nsCOMPtr<nsIInputStream> mSyncStream; // Underlying synchronous stream that is
|
||||
// being converted to an async stream
|
||||
PRUint32 mDataAvailCursor;
|
||||
PRUint32 mRemaining; // Size of AsyncRead request less bytes for
|
||||
// consumer OnDataAvailable's that were fired
|
||||
PRUint32 mAvailable; // Number of bytes for which OnDataAvailable fired
|
||||
nsMemCacheChannel* mChannel; // Associated memory cache channel, strong link
|
||||
// but can not use nsCOMPtr
|
||||
PRBool mAborted; // Abort() has been called
|
||||
PRBool mSuspended; // Suspend() has been called
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(AsyncReadStreamAdaptor, NS_GET_IID(nsIInputStream))
|
||||
|
||||
// The only purpose of this output stream wrapper is to adjust the cache's
|
||||
// overall occupancy as new data flows into the cache entry.
|
||||
class MemCacheWriteStreamWrapper : public nsIOutputStream {
|
||||
public:
|
||||
MemCacheWriteStreamWrapper(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream):
|
||||
mBaseStream(aBaseStream), mChannel(aChannel)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ADDREF(mChannel);
|
||||
}
|
||||
|
||||
virtual ~MemCacheWriteStreamWrapper() { NS_RELEASE(mChannel); };
|
||||
|
||||
static nsresult
|
||||
Create(nsMemCacheChannel* aChannel, nsIOutputStream *aBaseStream, nsIOutputStream* *aWrapper) {
|
||||
MemCacheWriteStreamWrapper *wrapper =
|
||||
new MemCacheWriteStreamWrapper(aChannel, aBaseStream);
|
||||
if (!wrapper) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(wrapper);
|
||||
*aWrapper = wrapper;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD
|
||||
Write(const char *aBuffer, PRUint32 aCount, PRUint32 *aNumWritten) {
|
||||
*aNumWritten = 0;
|
||||
nsresult rv = mBaseStream->Write(aBuffer, aCount, aNumWritten);
|
||||
mChannel->NotifyStorageInUse(*aNumWritten);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Flush() { return mBaseStream->Flush(); }
|
||||
|
||||
NS_IMETHOD
|
||||
Close() { return mBaseStream->Close(); }
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIOutputStream> mBaseStream;
|
||||
nsMemCacheChannel* mChannel;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(MemCacheWriteStreamWrapper, NS_GET_IID(nsIOutputStream))
|
||||
|
||||
nsMemCacheChannel::nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup)
|
||||
: mRecord(aRecord)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mRecord->mNumChannels++;
|
||||
}
|
||||
|
||||
nsMemCacheChannel::~nsMemCacheChannel()
|
||||
{
|
||||
mRecord->mNumChannels--;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::IsPending(PRBool* aIsPending)
|
||||
{
|
||||
*aIsPending = PR_FALSE;
|
||||
if (!mAsyncReadStream)
|
||||
return NS_OK;
|
||||
return mAsyncReadStream->IsPending(aIsPending);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::Cancel(void)
|
||||
{
|
||||
if (!mAsyncReadStream)
|
||||
return NS_ERROR_FAILURE;
|
||||
return mAsyncReadStream->Cancel();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::Suspend(void)
|
||||
{
|
||||
if (!mAsyncReadStream)
|
||||
return NS_ERROR_FAILURE;
|
||||
return mAsyncReadStream->Suspend();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::Resume(void)
|
||||
{
|
||||
if (!mAsyncReadStream)
|
||||
return NS_ERROR_FAILURE;
|
||||
return mAsyncReadStream->Resume();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetOriginalURI(nsIURI * *aURI)
|
||||
{
|
||||
// Not required
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetURI(nsIURI * *aURI)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsIInputStream* *aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ENSURE_ARG(aResult);
|
||||
if (mInputStream)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
rv = mRecord->mStorageStream->NewInputStream(aStartPosition, getter_AddRefs(mInputStream));
|
||||
*aResult = mInputStream;
|
||||
NS_ADDREF(*aResult);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::OpenOutputStream(PRUint32 startPosition, nsIOutputStream* *aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
|
||||
PRUint32 oldLength;
|
||||
mRecord->mStorageStream->GetLength(&oldLength);
|
||||
rv = mRecord->mStorageStream->GetOutputStream(startPosition, getter_AddRefs(outputStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (startPosition < oldLength)
|
||||
NotifyStorageInUse(startPosition - oldLength);
|
||||
|
||||
return MemCacheWriteStreamWrapper::Create(this, outputStream, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::AsyncOpen(nsIStreamObserver *observer, nsISupports *ctxt)
|
||||
{
|
||||
// Not required
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports *aContext, nsIStreamListener *aListener)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
nsresult rv = OpenInputStream(aStartPosition, aReadCount, getter_AddRefs(inputStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
AsyncReadStreamAdaptor *asyncReadStreamAdaptor;
|
||||
asyncReadStreamAdaptor = new AsyncReadStreamAdaptor(this, inputStream);
|
||||
if (!asyncReadStreamAdaptor)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(asyncReadStreamAdaptor);
|
||||
mAsyncReadStream = asyncReadStreamAdaptor;
|
||||
|
||||
rv = asyncReadStreamAdaptor->AsyncRead(aStartPosition, aReadCount, aContext, aListener);
|
||||
if (NS_FAILED(rv))
|
||||
delete asyncReadStreamAdaptor;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::AsyncWrite(nsIInputStream *fromStream, PRUint32 startPosition,
|
||||
PRInt32 writeCount, nsISupports *ctxt,
|
||||
nsIStreamObserver *observer)
|
||||
{
|
||||
// Not required to be implemented
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetContentType(char* *aContentType)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetContentLength(PRInt32 *aContentLength)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetOwner(nsISupports* *aOwner)
|
||||
{
|
||||
*aOwner = mOwner.get();
|
||||
NS_IF_ADDREF(*aOwner);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetOwner(nsISupports* aOwner)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
mOwner = aOwner;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
|
||||
{
|
||||
// Not required to be implemented, since it is implemented by cache manager
|
||||
NS_ASSERTION(0, "nsMemCacheChannel method unexpectedly called");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _nsMemCacheChannel_h_
|
||||
#define _nsMemCacheChannel_h_
|
||||
|
||||
#include "nsMemCacheRecord.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
|
||||
class AsyncReadStreamAdaptor;
|
||||
|
||||
class nsMemCacheChannel : public nsIChannel
|
||||
{
|
||||
public:
|
||||
// Constructors and Destructor
|
||||
nsMemCacheChannel(nsMemCacheRecord *aRecord, nsILoadGroup *aLoadGroup);
|
||||
virtual ~nsMemCacheChannel();
|
||||
|
||||
// Declare nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Declare nsIRequest methods
|
||||
NS_DECL_NSIREQUEST
|
||||
|
||||
// Declare nsIChannel methods
|
||||
NS_DECL_NSICHANNEL
|
||||
|
||||
protected:
|
||||
void NotifyStorageInUse(PRInt32 aBytesUsed);
|
||||
|
||||
nsCOMPtr<nsMemCacheRecord> mRecord;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
AsyncReadStreamAdaptor* mAsyncReadStream; // non-owning pointer
|
||||
|
||||
friend class MemCacheWriteStreamWrapper;
|
||||
friend class AsyncReadStreamAdaptor;
|
||||
};
|
||||
|
||||
#endif // _nsMemCacheChannel_h_
|
||||
164
mozilla/netwerk/cache/memcache/nsMemCacheRecord.cpp
vendored
164
mozilla/netwerk/cache/memcache/nsMemCacheRecord.cpp
vendored
@@ -1,164 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nsMemCache.h"
|
||||
#include "nsMemCacheRecord.h"
|
||||
#include "nsMemCacheChannel.h"
|
||||
#include "nsIAllocator.h"
|
||||
#include "nsStorageStream.h"
|
||||
|
||||
static NS_DEFINE_IID(kINetDataCacheRecord, NS_INETDATACACHERECORD_IID);
|
||||
|
||||
nsMemCacheRecord::nsMemCacheRecord()
|
||||
: mKey(0), mKeyLength(0), mMetaData(0), mMetaDataLength(0), mNumChannels(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsMemCacheRecord::~nsMemCacheRecord()
|
||||
{
|
||||
if (mMetaData)
|
||||
delete[] mMetaData;
|
||||
if (mKey)
|
||||
delete[] mKey;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMemCacheRecord, NS_GET_IID(nsINetDataCacheRecord))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetKey(PRUint32 *aLength, char **aResult)
|
||||
{
|
||||
NS_ENSURE_ARG(aResult);
|
||||
*aResult = (char *)nsAllocator::Alloc(mKeyLength);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(*aResult, mKey, mKeyLength);
|
||||
*aLength = mKeyLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsMemCacheRecord::Init(const char *aKey, PRUint32 aKeyLength,
|
||||
PRUint32 aRecordID, nsMemCache *aCache)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(!mKey, "Memory cache record key set multiple times");
|
||||
|
||||
rv = NS_NewStorageStream(MEM_CACHE_SEGMENT_SIZE, MEM_CACHE_MAX_ENTRY_SIZE,
|
||||
getter_AddRefs(mStorageStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mKey = new char[aKeyLength];
|
||||
if (!mKey)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(mKey, aKey, aKeyLength);
|
||||
mKeyLength = aKeyLength;
|
||||
mRecordID = aRecordID;
|
||||
mCache = aCache;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetRecordID(PRInt32 *aRecordID)
|
||||
{
|
||||
NS_ENSURE_ARG(aRecordID);
|
||||
*aRecordID = mRecordID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetMetaData(PRUint32 *aLength, char **aResult)
|
||||
{
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
*aResult = 0;
|
||||
if (mMetaDataLength) {
|
||||
*aResult = (char*)nsAllocator::Alloc(mMetaDataLength);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(*aResult, mMetaData, mMetaDataLength);
|
||||
}
|
||||
*aLength = mMetaDataLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::SetMetaData(PRUint32 aLength, const char *aData)
|
||||
{
|
||||
if (mMetaData)
|
||||
delete[] mMetaData;
|
||||
mMetaData = new char[aLength];
|
||||
if (!mMetaData)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
memcpy(mMetaData, aData, aLength);
|
||||
mMetaDataLength = aLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetStoredContentLength(PRUint32 *aStoredContentLength)
|
||||
{
|
||||
NS_ENSURE_ARG(aStoredContentLength);
|
||||
return mStorageStream->GetLength(aStoredContentLength);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::SetStoredContentLength(PRUint32 aStoredContentLength)
|
||||
{
|
||||
PRUint32 before, after;
|
||||
mStorageStream->GetLength(&before);
|
||||
nsresult rv = mStorageStream->SetLength(aStoredContentLength);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mStorageStream->GetLength(&after);
|
||||
mCache->mOccupancy -= (before - after);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::Delete(void)
|
||||
{
|
||||
if (mNumChannels)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return mCache->Delete(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::GetFilename(nsIFileSpec* *aFilename)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMemCacheRecord::NewChannel(nsILoadGroup *aLoadGroup, nsIChannel* *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
nsMemCacheChannel* channel = new nsMemCacheChannel(this, aLoadGroup);
|
||||
if (!channel)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(channel);
|
||||
*aResult = NS_STATIC_CAST(nsIChannel*, channel);
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _nsMemCacheRecord_h_
|
||||
#define _nsMemCacheRecord_h_
|
||||
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsMemCache;
|
||||
|
||||
class nsMemCacheRecord : public nsINetDataCacheRecord
|
||||
{
|
||||
|
||||
public:
|
||||
// Declare interface methods
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSINETDATACACHERECORD
|
||||
|
||||
protected:
|
||||
// Constructors and Destructor
|
||||
nsMemCacheRecord();
|
||||
virtual ~nsMemCacheRecord();
|
||||
|
||||
nsresult Init(const char *aKey, PRUint32 aKeyLength,
|
||||
PRUint32 aRecordID, nsMemCache *aCache);
|
||||
|
||||
char* mKey; // opaque database key for this record
|
||||
PRUint32 mKeyLength; // length, in bytes, of mKey
|
||||
|
||||
PRInt32 mRecordID; // An alternate key for this record
|
||||
|
||||
char* mMetaData; // opaque URI metadata
|
||||
PRUint32 mMetaDataLength; // length, in bytes, of mMetaData
|
||||
|
||||
nsMemCache* mCache; // weak pointer to the cache database
|
||||
// that this record inhabits
|
||||
|
||||
nsCOMPtr<nsIStorageStream> mStorageStream;
|
||||
PRUint32 mNumChannels; // Count un-Release'ed nsIChannels
|
||||
|
||||
friend class nsMemCache;
|
||||
friend class nsMemCacheChannel;
|
||||
};
|
||||
|
||||
#endif // _nsMemCacheRecord_h_
|
||||
55
mozilla/netwerk/cache/mgr/Makefile.in
vendored
55
mozilla/netwerk/cache/mgr/Makefile.in
vendored
@@ -1,55 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = nkcache
|
||||
LIBRARY_NAME = nkcachemgr_s
|
||||
|
||||
REQUIRES = nspr
|
||||
|
||||
EXPORTS = \
|
||||
nsCacheManager.h \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
nsCacheManager.cpp \
|
||||
nsCachedNetData.cpp \
|
||||
nsReplacementPolicy.cpp \
|
||||
nsCacheEntryChannel.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/../public -I$(srcdir)/../include
|
||||
|
||||
EXTRA_LIBS = $(NSPR_LIBS)
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
override NO_SHARED_LIB=1
|
||||
override NO_STATIC_LIB=
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
45
mozilla/netwerk/cache/mgr/Makefile.win
vendored
45
mozilla/netwerk/cache/mgr/Makefile.win
vendored
@@ -1,45 +0,0 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
DEPTH=..\..\..
|
||||
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
LIBRARY_NAME = nkcachemgr_s
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsCacheManager.obj \
|
||||
.\$(OBJDIR)\nsCachedNetData.obj \
|
||||
.\$(OBJDIR)\nsReplacementPolicy.obj \
|
||||
.\$(OBJDIR)\nsCacheEntryChannel.obj \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -rf $(OBJDIR)
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
|
||||
261
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.cpp
vendored
261
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.cpp
vendored
@@ -1,261 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#include "nsCacheManager.h"
|
||||
#include "nsCacheEntryChannel.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
nsCacheEntryChannel::nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel,
|
||||
nsILoadGroup* aLoadGroup):
|
||||
nsChannelProxy(aChannel), mCacheEntry(aCacheEntry), mLoadGroup(aLoadGroup), mLoadAttributes(0)
|
||||
{
|
||||
NS_ASSERTION(aCacheEntry->mChannelCount < 0xFF, "Overflowed channel counter");
|
||||
mCacheEntry->mChannelCount++;
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsCacheEntryChannel::~nsCacheEntryChannel()
|
||||
{
|
||||
mCacheEntry->mChannelCount--;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsCacheEntryChannel, nsISupports, nsIChannel, nsIRequest)
|
||||
|
||||
// A proxy for nsIOutputStream
|
||||
class CacheOutputStream : public nsIOutputStream {
|
||||
|
||||
public:
|
||||
CacheOutputStream(nsIOutputStream *aOutputStream, nsCachedNetData *aCacheEntry):
|
||||
mOutputStream(aOutputStream), mCacheEntry(aCacheEntry), mStartTime(PR_Now())
|
||||
{ NS_INIT_REFCNT(); }
|
||||
|
||||
virtual ~CacheOutputStream() {
|
||||
mCacheEntry->NoteDownloadTime(mStartTime, PR_Now());
|
||||
mCacheEntry->ClearFlag(nsCachedNetData::UPDATE_IN_PROGRESS);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Close() {
|
||||
return mOutputStream->Close();
|
||||
}
|
||||
|
||||
NS_IMETHOD Flush() { return mOutputStream->Flush(); }
|
||||
|
||||
NS_IMETHOD
|
||||
Write(const char *aBuf, PRUint32 aCount, PRUint32 *aActualBytes) {
|
||||
nsresult rv;
|
||||
|
||||
*aActualBytes = 0;
|
||||
rv = mOutputStream->Write(aBuf, aCount, aActualBytes);
|
||||
mCacheEntry->mLogicalLength += *aActualBytes;
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCacheManager::LimitCacheSize();
|
||||
return rv;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
nsCOMPtr<nsCachedNetData> mCacheEntry;
|
||||
|
||||
// Time at which stream was opened
|
||||
PRTime mStartTime;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CacheOutputStream, NS_GET_IID(nsIOutputStream))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIOutputStream> baseOutputStream;
|
||||
|
||||
rv = mChannel->OpenOutputStream(aStartPosition, getter_AddRefs(baseOutputStream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mCacheEntry->NoteUpdate();
|
||||
mCacheEntry->NoteAccess();
|
||||
mCacheEntry->mLogicalLength = aStartPosition;
|
||||
|
||||
*aOutputStream = new CacheOutputStream(baseOutputStream, mCacheEntry);
|
||||
if (!*aOutputStream)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aOutputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsIInputStream* *aInputStream)
|
||||
{
|
||||
mCacheEntry->NoteAccess();
|
||||
return mChannel->OpenInputStream(aStartPosition, aReadCount, aInputStream);
|
||||
}
|
||||
|
||||
class CacheManagerStreamListener: public nsIStreamListener {
|
||||
|
||||
public:
|
||||
|
||||
CacheManagerStreamListener(nsIStreamListener *aListener,
|
||||
nsILoadGroup *aLoadGroup, nsIChannel *aChannel):
|
||||
mListener(aListener), mLoadGroup(aLoadGroup), mChannel(aChannel)
|
||||
{ NS_INIT_REFCNT(); }
|
||||
|
||||
virtual ~CacheManagerStreamListener() {}
|
||||
|
||||
private:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD
|
||||
OnDataAvailable(nsIChannel *channel, nsISupports *aContext,
|
||||
nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count) {
|
||||
return mListener->OnDataAvailable(mChannel, aContext, inStr, sourceOffset, count);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnStartRequest(nsIChannel *channel, nsISupports *aContext) {
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->AddChannel(mChannel, aContext);
|
||||
return mListener->OnStartRequest(mChannel, aContext);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
OnStopRequest(nsIChannel *channel, nsISupports *aContext,
|
||||
nsresult status, const PRUnichar *errorMsg) {
|
||||
nsresult rv;
|
||||
rv = mListener->OnStopRequest(mChannel, aContext, status, errorMsg);
|
||||
if (mLoadGroup)
|
||||
mLoadGroup->RemoveChannel(mChannel, aContext, status, errorMsg);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
nsCOMPtr<nsIStreamListener> mListener;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(CacheManagerStreamListener, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports *aContext, nsIStreamListener *aListener)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mCacheEntry->NoteAccess();
|
||||
|
||||
nsCOMPtr<nsIStreamListener> headListener;
|
||||
if (mLoadGroup) {
|
||||
mLoadGroup->GetDefaultLoadAttributes(&mLoadAttributes);
|
||||
|
||||
// Create a load group "proxy" listener...
|
||||
nsCOMPtr<nsILoadGroupListenerFactory> factory;
|
||||
rv = mLoadGroup->GetGroupListenerFactory(getter_AddRefs(factory));
|
||||
if (NS_SUCCEEDED(rv) && factory) {
|
||||
rv = factory->CreateLoadGroupListener(aListener,
|
||||
getter_AddRefs(headListener));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
} else {
|
||||
headListener = aListener;
|
||||
}
|
||||
|
||||
CacheManagerStreamListener* cacheManagerStreamListener;
|
||||
nsIChannel *channelForListener;
|
||||
|
||||
channelForListener = mProxyChannel ? mProxyChannel.get() : NS_STATIC_CAST(nsIChannel*, this);
|
||||
cacheManagerStreamListener =
|
||||
new CacheManagerStreamListener(headListener, mLoadGroup, channelForListener);
|
||||
if (!cacheManagerStreamListener) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(cacheManagerStreamListener);
|
||||
rv = mChannel->AsyncRead(aStartPosition, aReadCount, aContext,
|
||||
cacheManagerStreamListener);
|
||||
NS_RELEASE(cacheManagerStreamListener);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// No async writes allowed to the cache yet
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
|
||||
PRInt32 aWriteCount, nsISupports *aContext,
|
||||
nsIStreamObserver *aObserver)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
|
||||
{
|
||||
*aLoadGroup = mLoadGroup;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetLoadAttributes(nsLoadFlags *aLoadAttributes)
|
||||
{
|
||||
*aLoadAttributes = mLoadAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes)
|
||||
{
|
||||
mLoadAttributes = aLoadAttributes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetURI(nsIURI * *aURI)
|
||||
{
|
||||
char* spec;
|
||||
nsresult rv;
|
||||
|
||||
rv = mCacheEntry->GetUriSpec(&spec);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIIOService, serv, kIOServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = serv->NewURI(spec, 0, aURI);
|
||||
nsAllocator::Free(spec);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheEntryChannel::GetOriginalURI(nsIURI * *aURI)
|
||||
{
|
||||
// FIXME - should return original URI passed into NewChannel() ?
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
82
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.h
vendored
82
mozilla/netwerk/cache/mgr/nsCacheEntryChannel.h
vendored
@@ -1,82 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#ifndef _nsCacheEntryChannel_h_
|
||||
#define _nsCacheEntryChannel_h_
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCachedNetData.h"
|
||||
#include "nsILoadGroup.h"
|
||||
|
||||
class nsIStreamListener;
|
||||
|
||||
// A proxy for an nsIChannel, useful when only a few nsIChannel
|
||||
// methods must be overridden
|
||||
class nsChannelProxy : public nsIChannel {
|
||||
|
||||
public:
|
||||
NS_FORWARD_NSICHANNEL(mChannel->)
|
||||
NS_FORWARD_NSIREQUEST(mChannel->)
|
||||
|
||||
protected:
|
||||
nsChannelProxy(nsIChannel* aChannel):mChannel(aChannel) {};
|
||||
virtual ~nsChannelProxy() {};
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
|
||||
// Override several nsIChannel methods so that they interact with the cache manager
|
||||
class nsCacheEntryChannel : public nsChannelProxy {
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD OpenOutputStream(PRUint32 aStartPosition, nsIOutputStream* *aOutputStream);
|
||||
NS_IMETHOD OpenInputStream(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsIInputStream* *aInputStream);
|
||||
NS_IMETHOD AsyncRead(PRUint32 aStartPosition, PRInt32 aReadCount,
|
||||
nsISupports *aContext, nsIStreamListener *aListener);
|
||||
NS_IMETHOD AsyncWrite(nsIInputStream *aFromStream, PRUint32 aStartPosition,
|
||||
PRInt32 aWriteCount, nsISupports *aContext,
|
||||
nsIStreamObserver *aObserver);
|
||||
NS_IMETHOD GetLoadAttributes(nsLoadFlags *aLoadAttributes);
|
||||
NS_IMETHOD SetLoadAttributes(nsLoadFlags aLoadAttributes);
|
||||
NS_IMETHOD GetLoadGroup(nsILoadGroup* *aLoadGroup);
|
||||
NS_IMETHOD GetURI(nsIURI * *aURI);
|
||||
NS_IMETHOD GetOriginalURI(nsIURI * *aURI);
|
||||
|
||||
protected:
|
||||
nsCacheEntryChannel(nsCachedNetData* aCacheEntry, nsIChannel* aChannel, nsILoadGroup* aLoadGroup);
|
||||
virtual ~nsCacheEntryChannel();
|
||||
|
||||
friend class nsCachedNetData;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsCachedNetData> mCacheEntry;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
nsCOMPtr<nsIChannel> mProxyChannel;
|
||||
nsLoadFlags mLoadAttributes;
|
||||
};
|
||||
|
||||
#endif // _nsCacheEntryChannel_h_
|
||||
497
mozilla/netwerk/cache/mgr/nsCacheManager.cpp
vendored
497
mozilla/netwerk/cache/mgr/nsCacheManager.cpp
vendored
@@ -1,497 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsCacheManager.h"
|
||||
#include "nsCachedNetData.h"
|
||||
#include "nsReplacementPolicy.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsINetDataDiskCache.h"
|
||||
|
||||
// Limit the number of entries in the cache to conserve memory space
|
||||
// in the nsReplacementPolicy code
|
||||
#define MAX_MEM_CACHE_ENTRIES 800
|
||||
#define MAX_DISK_CACHE_ENTRIES 3200
|
||||
|
||||
// Cache capacities in MB, overridable via APIs
|
||||
#define DEFAULT_MEMORY_CACHE_CAPACITY 1024
|
||||
#define DEFAULT_DISK_CACHE_CAPACITY 10000
|
||||
|
||||
#define CACHE_HIGH_WATER_MARK(capacity) ((PRUint32)(0.98 * (capacity)))
|
||||
#define CACHE_LOW_WATER_MARK(capacity) ((PRUint32)(0.97 * (capacity)))
|
||||
|
||||
nsCacheManager* gCacheManager = 0;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsCacheManager, NS_GET_IID(nsINetDataCacheManager))
|
||||
|
||||
nsCacheManager::nsCacheManager()
|
||||
: mActiveCacheRecords(0),
|
||||
mDiskCacheCapacity(DEFAULT_DISK_CACHE_CAPACITY),
|
||||
mMemCacheCapacity(DEFAULT_MEMORY_CACHE_CAPACITY)
|
||||
{
|
||||
NS_ASSERTION(!gCacheManager, "Multiple cache managers created");
|
||||
gCacheManager = this;
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
nsCacheManager::~nsCacheManager()
|
||||
{
|
||||
gCacheManager = 0;
|
||||
delete mActiveCacheRecords;
|
||||
delete mMemSpaceManager;
|
||||
delete mDiskSpaceManager;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mActiveCacheRecords = new nsHashtable(64);
|
||||
if (!mActiveCacheRecords)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Instantiate the memory cache component
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_MEMORY_CACHE_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(mMemCache));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_FLAT_CACHE_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
|
||||
getter_AddRefs(mFlatCache));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// For now, we don't require a flat cache module to be present
|
||||
if (rv != NS_ERROR_FACTORY_NOT_REGISTERED)
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef FILE_CACHE_IS_READY
|
||||
// Instantiate the file cache component
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_FILE_CACHE_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(mFileCache));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("No disk cache present");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set up linked list of caches in search order
|
||||
mCacheSearchChain = mMemCache;
|
||||
if (mFlatCache) {
|
||||
mMemCache->SetNextCache(mFlatCache);
|
||||
mFlatCache->SetNextCache(mFileCache);
|
||||
} else {
|
||||
mMemCache->SetNextCache(mFileCache);
|
||||
}
|
||||
|
||||
// TODO - Load any extension caches here
|
||||
|
||||
// Initialize replacement policy for memory cache module
|
||||
mMemSpaceManager = new nsReplacementPolicy;
|
||||
if (!mMemSpaceManager)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = mMemSpaceManager->Init(MAX_MEM_CACHE_ENTRIES);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = mMemSpaceManager->AddCache(mMemCache);
|
||||
|
||||
// Initialize replacement policy for disk cache modules (file
|
||||
// cache and flat cache)
|
||||
mDiskSpaceManager = new nsReplacementPolicy;
|
||||
if (!mDiskSpaceManager)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = mDiskSpaceManager->Init(MAX_DISK_CACHE_ENTRIES);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (mFileCache) {
|
||||
rv = mDiskSpaceManager->AddCache(mFileCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
if (mFlatCache) {
|
||||
rv = mDiskSpaceManager->AddCache(mFlatCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetCachedNetData(const char *aUriSpec, const char *aSecondaryKey,
|
||||
PRUint32 aSecondaryKeyLength,
|
||||
PRUint32 aFlags, nsICachedNetData* *aResult)
|
||||
{
|
||||
nsCachedNetData *cachedData;
|
||||
nsresult rv;
|
||||
nsINetDataCache *cache;
|
||||
nsReplacementPolicy *spaceManager;
|
||||
|
||||
if (aFlags & CACHE_AS_FILE) {
|
||||
cache = mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
|
||||
// Ensure that cache is initialized
|
||||
if (mDiskCacheCapacity == (PRUint32)-1)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
|
||||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
|
||||
cache = mMemCache;
|
||||
spaceManager = mMemSpaceManager;
|
||||
} else {
|
||||
cache = mFlatCache ? mFlatCache : mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
}
|
||||
|
||||
// Construct the cache key by appending the secondary key to the URI spec
|
||||
nsCAutoString cacheKey(aUriSpec);
|
||||
|
||||
// Insert NUL at end of URI spec
|
||||
cacheKey += '\0';
|
||||
if (aSecondaryKey)
|
||||
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
|
||||
|
||||
nsStringKey key(cacheKey);
|
||||
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
|
||||
|
||||
// There is no existing instance of nsCachedNetData for this URL.
|
||||
// Make one from the corresponding record in the cache module.
|
||||
if (cachedData) {
|
||||
NS_ASSERTION(cache == cachedData->mCache,
|
||||
"Cannot yet handle simultaneously active requests for the "
|
||||
"same URL using different caches");
|
||||
NS_ADDREF(cachedData);
|
||||
} else {
|
||||
rv = spaceManager->GetCachedNetData(cacheKey.GetBuffer(), cacheKey.Length(),
|
||||
cache, &cachedData);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mActiveCacheRecords->Put(&key, cachedData);
|
||||
}
|
||||
|
||||
*aResult = cachedData;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Remove this cache entry from the list of active ones
|
||||
nsresult
|
||||
nsCacheManager::NoteDormant(nsCachedNetData* aEntry)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 keyLength;
|
||||
char* key;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCachedNetData* deletedEntry;
|
||||
|
||||
rv = aEntry->GetRecord(getter_AddRefs(record));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = record->GetKey(&keyLength, &key);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsStringKey hashTableKey(nsCString(key, keyLength));
|
||||
deletedEntry = (nsCachedNetData*)gCacheManager->mActiveCacheRecords->Remove(&hashTableKey);
|
||||
// NS_ASSERTION(deletedEntry == aEntry, "Hash table inconsistency");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::Contains(const char *aUriSpec, const char *aSecondaryKey,
|
||||
PRUint32 aSecondaryKeyLength,
|
||||
PRUint32 aFlags, PRBool *aResult)
|
||||
{
|
||||
nsINetDataCache *cache;
|
||||
nsReplacementPolicy *spaceManager;
|
||||
nsCachedNetData *cachedData;
|
||||
|
||||
if (aFlags & CACHE_AS_FILE) {
|
||||
cache = mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
} else if ((aFlags & BYPASS_PERSISTENT_CACHE) ||
|
||||
(!mFileCache && !mFlatCache) || !mDiskCacheCapacity) {
|
||||
cache = mMemCache;
|
||||
spaceManager = mMemSpaceManager;
|
||||
} else {
|
||||
cache = mFlatCache ? mFlatCache : mFileCache;
|
||||
spaceManager = mDiskSpaceManager;
|
||||
}
|
||||
|
||||
// Construct the cache key by appending the secondary key to the URI spec
|
||||
nsCAutoString cacheKey(aUriSpec);
|
||||
|
||||
// Insert NUL between URI spec and secondary key
|
||||
cacheKey += '\0';
|
||||
cacheKey.Append(aSecondaryKey, aSecondaryKeyLength);
|
||||
|
||||
// Locate the record using (URI + secondary key)
|
||||
nsStringKey key(cacheKey);
|
||||
cachedData = (nsCachedNetData*)mActiveCacheRecords->Get(&key);
|
||||
|
||||
if (cachedData && (cache == cachedData->mCache)) {
|
||||
*aResult = PR_TRUE;
|
||||
return NS_OK;
|
||||
} else {
|
||||
// No active cache entry, see if there is a dormant one
|
||||
return cache->Contains(cacheKey.GetBuffer(), cacheKey.Length(), aResult);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetNumEntries(PRUint32 *aNumEntries)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsISupports> cacheSupports;
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
|
||||
PRUint32 totalEntries = 0;
|
||||
|
||||
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
while (1) {
|
||||
PRBool notDone;
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
iterator->GetNext(getter_AddRefs(cacheSupports));
|
||||
cache = do_QueryInterface(cacheSupports);
|
||||
|
||||
PRUint32 numEntries;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
totalEntries += numEntries;
|
||||
}
|
||||
|
||||
*aNumEntries = totalEntries;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::NewCacheEntryIterator(nsISimpleEnumerator* *aResult)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
class CacheEnumerator : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
CacheEnumerator(nsINetDataCache* aFirstCache):mCache(aFirstCache)
|
||||
{ NS_INIT_REFCNT(); }
|
||||
|
||||
virtual ~CacheEnumerator() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHODIMP
|
||||
HasMoreElements(PRBool* aMoreElements) {
|
||||
*aMoreElements = (mCache != 0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetNext(nsISupports* *aSupports) {
|
||||
*aSupports = mCache;
|
||||
if (!mCache)
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_ADDREF(*aSupports);
|
||||
|
||||
nsCOMPtr<nsINetDataCache> nextCache;
|
||||
nsresult rv = mCache->GetNextCache(getter_AddRefs(nextCache));
|
||||
mCache = nextCache;
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsINetDataCache> mCache;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CacheEnumerator, NS_GET_IID(nsISimpleEnumerator))
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::NewCacheModuleIterator(nsISimpleEnumerator* *aResult)
|
||||
{
|
||||
*aResult = new CacheEnumerator(mCacheSearchChain);
|
||||
if (!*aResult)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::RemoveAll(void)
|
||||
{
|
||||
nsresult rv, result;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
nsCOMPtr<nsISupports> iSupports;
|
||||
|
||||
result = NS_OK;
|
||||
rv = NewCacheModuleIterator(getter_AddRefs(iterator));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
while (1) {
|
||||
PRBool notDone;
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
iterator->GetNext(getter_AddRefs(iSupports));
|
||||
cache = do_QueryInterface(iSupports);
|
||||
|
||||
PRUint32 cacheFlags;
|
||||
rv = cache->GetFlags(&cacheFlags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if ((cacheFlags & nsINetDataCache::READ_ONLY) == 0) {
|
||||
rv = cache->RemoveAll();
|
||||
if (NS_FAILED(rv))
|
||||
result = rv;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::LimitMemCacheSize()
|
||||
{
|
||||
nsresult rv;
|
||||
nsReplacementPolicy* spaceManager;
|
||||
|
||||
NS_ASSERTION(gCacheManager, "No cache manager");
|
||||
|
||||
spaceManager = gCacheManager->mMemSpaceManager;
|
||||
|
||||
PRUint32 occupancy;
|
||||
rv = spaceManager->GetStorageInUse(&occupancy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 memCacheCapacity = gCacheManager->mMemCacheCapacity;
|
||||
if (occupancy > CACHE_HIGH_WATER_MARK(memCacheCapacity))
|
||||
return spaceManager->Evict(CACHE_LOW_WATER_MARK(memCacheCapacity));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::LimitDiskCacheSize()
|
||||
{
|
||||
nsresult rv;
|
||||
nsReplacementPolicy* spaceManager;
|
||||
|
||||
NS_ASSERTION(gCacheManager, "No cache manager");
|
||||
|
||||
spaceManager = gCacheManager->mDiskSpaceManager;
|
||||
|
||||
PRUint32 occupancy;
|
||||
rv = spaceManager->GetStorageInUse(&occupancy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 diskCacheCapacity = gCacheManager->mDiskCacheCapacity;
|
||||
if (occupancy > CACHE_HIGH_WATER_MARK(diskCacheCapacity))
|
||||
return spaceManager->Evict(CACHE_LOW_WATER_MARK(diskCacheCapacity));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCacheManager::LimitCacheSize()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = LimitDiskCacheSize();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = LimitMemCacheSize();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::SetMemCacheCapacity(PRUint32 aCapacity)
|
||||
{
|
||||
mMemCacheCapacity = aCapacity;
|
||||
LimitCacheSize();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetMemCacheCapacity(PRUint32* aCapacity)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCapacity);
|
||||
*aCapacity = mMemCacheCapacity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::SetDiskCacheCapacity(PRUint32 aCapacity)
|
||||
{
|
||||
mDiskCacheCapacity = aCapacity;
|
||||
LimitCacheSize();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetDiskCacheCapacity(PRUint32* aCapacity)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCapacity);
|
||||
*aCapacity = mDiskCacheCapacity;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::SetDiskCacheFolder(nsIFileSpec* aFolder)
|
||||
{
|
||||
NS_ENSURE_ARG(aFolder);
|
||||
|
||||
if (!mFileCache)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsINetDataDiskCache> fileCache;
|
||||
fileCache = do_QueryInterface(mFileCache);
|
||||
return fileCache->SetDiskCacheFolder(aFolder);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCacheManager::GetDiskCacheFolder(nsIFileSpec* *aFolder)
|
||||
{
|
||||
NS_ENSURE_ARG(aFolder);
|
||||
|
||||
if (!mFileCache)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsCOMPtr<nsINetDataDiskCache> fileCache;
|
||||
fileCache = do_QueryInterface(mFileCache);
|
||||
return fileCache->GetDiskCacheFolder(aFolder);
|
||||
}
|
||||
100
mozilla/netwerk/cache/mgr/nsCacheManager.h
vendored
100
mozilla/netwerk/cache/mgr/nsCacheManager.h
vendored
@@ -1,100 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#ifndef _nsCacheManager_h_
|
||||
#define _nsCacheManager_h_
|
||||
|
||||
// 2030f0b0-9567-11d3-90d3-0040056a906e
|
||||
#define NS_CACHE_MANAGER_CID \
|
||||
{ \
|
||||
0x2030f0b0, \
|
||||
0x9567, \
|
||||
0x11d3, \
|
||||
{0x90, 0xd3, 0x00, 0x40, 0x05, 0x6a, 0x90, 0x6e} \
|
||||
}
|
||||
|
||||
#include "nsINetDataCacheManager.h"
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsHashtable;
|
||||
class nsReplacementPolicy;
|
||||
class nsCachedNetData;
|
||||
|
||||
class nsCacheManager : public nsINetDataCacheManager {
|
||||
|
||||
public:
|
||||
nsCacheManager();
|
||||
virtual ~nsCacheManager();
|
||||
|
||||
NS_METHOD Init();
|
||||
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsINetDataCacheManager methods
|
||||
NS_DECL_NSINETDATACACHEMANAGER
|
||||
|
||||
private:
|
||||
|
||||
// Mapping from cache key to nsCachedNetData, but only for those cache
|
||||
// entries with external references, i.e. those referred to outside the
|
||||
// cache manager
|
||||
nsHashtable* mActiveCacheRecords;
|
||||
|
||||
// Memory cache
|
||||
nsCOMPtr<nsINetDataCache> mMemCache;
|
||||
|
||||
// Flat-file database cache; All content aggregated into single disk file
|
||||
nsCOMPtr<nsINetDataCache> mFlatCache;
|
||||
|
||||
// stream-as-file cache
|
||||
nsCOMPtr<nsINetDataCache> mFileCache;
|
||||
|
||||
// Unified replacement policy for flat-cache and file-cache
|
||||
nsReplacementPolicy* mDiskSpaceManager;
|
||||
|
||||
// Replacement policy for memory cache
|
||||
nsReplacementPolicy* mMemSpaceManager;
|
||||
|
||||
// List of caches in search order
|
||||
nsINetDataCache* mCacheSearchChain;
|
||||
|
||||
// Combined file/flat cache capacity, in KB
|
||||
PRUint32 mDiskCacheCapacity;
|
||||
|
||||
// Memory cache capacity, in KB
|
||||
PRUint32 mMemCacheCapacity;
|
||||
|
||||
protected:
|
||||
static nsresult NoteDormant(nsCachedNetData* aEntry);
|
||||
static nsresult LimitCacheSize();
|
||||
static nsresult LimitMemCacheSize();
|
||||
static nsresult LimitDiskCacheSize();
|
||||
|
||||
friend class nsCachedNetData;
|
||||
friend class CacheOutputStream;
|
||||
};
|
||||
|
||||
#endif // _nsCacheManager_h_
|
||||
1155
mozilla/netwerk/cache/mgr/nsCachedNetData.cpp
vendored
1155
mozilla/netwerk/cache/mgr/nsCachedNetData.cpp
vendored
File diff suppressed because it is too large
Load Diff
242
mozilla/netwerk/cache/mgr/nsCachedNetData.h
vendored
242
mozilla/netwerk/cache/mgr/nsCachedNetData.h
vendored
@@ -1,242 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#ifndef _nsCachedNetData_h_
|
||||
#define _nsCachedNetData_h_
|
||||
|
||||
#include "nsICachedNetData.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
|
||||
class nsINetDataCache;
|
||||
class nsIStreamAsFileObserver;
|
||||
class nsIStreamAsFile;
|
||||
class nsIArena;
|
||||
class StreamAsFileObserverClosure;
|
||||
class CacheMetaData;
|
||||
|
||||
// Number of recent access times recorded
|
||||
#define MAX_K 3
|
||||
|
||||
/**
|
||||
* FIXME - add comment. There are a lot of these data structures resident in
|
||||
* memory, so be careful about adding members unnecessarily.
|
||||
*/
|
||||
class nsCachedNetData : public nsICachedNetData {
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsICachedNetData methods
|
||||
NS_DECL_NSICACHEDNETDATA
|
||||
|
||||
NS_METHOD Init(nsINetDataCacheRecord *aRecord, nsINetDataCache *aCache);
|
||||
|
||||
protected:
|
||||
|
||||
// Bits for mFlags, below
|
||||
typedef enum {
|
||||
DIRTY = 1 << 0, // Cache entry data needs to be flushed to database
|
||||
|
||||
// ==== Flags that can be set by the protocol handler ====
|
||||
ALLOW_PARTIAL = 1 << 1, // Protocol handler supports partial fetching
|
||||
UPDATE_IN_PROGRESS = 1 << 2, // Protocol handler now modifying cache data
|
||||
|
||||
// ==== Cache-entry state flags. At most one of these flags can be set ====
|
||||
TRUNCATED_CONTENT = 1 << 4, // Entry contains valid content, but it has
|
||||
// been truncated by cache manager
|
||||
|
||||
// A previously-used cache entry, which has been purged of all cached
|
||||
// content and protocol-private data. This cache entry can be refilled
|
||||
// with new content or it may be retained in this vestigial state
|
||||
// because the usage statistics it contains will be used by the
|
||||
// replacement policy if the same URI is ever cached again.
|
||||
VESTIGIAL = 1 << 5,
|
||||
|
||||
// ==== Memory usage status bits. At most one of these flags can be set ====
|
||||
RECYCLED = 1 << 8, // Previously associated database record has
|
||||
// been deleted; This cache entry is available
|
||||
// for recycling.
|
||||
|
||||
DORMANT = 1 << 9, // No references to this cache entry, except by
|
||||
// the cache manager itself
|
||||
|
||||
// ==== Setter bits ====
|
||||
LAST_MODIFIED_KNOWN = 1 <<12, // Protocol handler called SetLastModifiedTime()
|
||||
EXPIRATION_KNOWN = 1 <<13, // Protocol handler called SetExpirationTime()
|
||||
STALE_TIME_KNOWN = 1 <<14, // Protocol handler called SetStaleTime()
|
||||
|
||||
// ==== Useful flag combinations ====
|
||||
// Cache entry not eligible for eviction
|
||||
UNEVICTABLE = VESTIGIAL | RECYCLED | UPDATE_IN_PROGRESS,
|
||||
|
||||
// State flags that are in-memory only, i.e. not persistent
|
||||
TRANSIENT_FLAGS = DIRTY | RECYCLED | DORMANT
|
||||
} Flag;
|
||||
|
||||
PRBool GetFlag(Flag aFlag) { return (mFlags & aFlag) != 0; }
|
||||
nsresult GetFlag(PRBool *aResult, Flag aFlag) { *aResult = GetFlag(aFlag); return NS_OK; }
|
||||
|
||||
// Set a boolean flag for the cache entry
|
||||
nsresult SetFlag(PRBool aValue, Flag aFlag);
|
||||
nsresult SetFlag(Flag aFlag) { return SetFlag(PR_TRUE, aFlag); }
|
||||
nsresult ClearFlag(Flag aFlag) { return SetFlag(PR_FALSE, aFlag); }
|
||||
|
||||
void ComputeProfit(PRUint32 aCurrentTime);
|
||||
static int Compare(const void *a, const void *b, void *unused);
|
||||
|
||||
void NoteAccess();
|
||||
void NoteUpdate();
|
||||
|
||||
// Get underlying raw cache database record.
|
||||
nsresult GetRecord(nsINetDataCacheRecord* *aRecord);
|
||||
|
||||
nsresult GetRecordID(PRInt32 *aRecordID);
|
||||
|
||||
nsresult Evict(PRUint32 aTruncatedContentLength);
|
||||
|
||||
nsresult GetFileSpec(nsIFileSpec* *aFileSpec);
|
||||
|
||||
void NoteDownloadTime(PRTime start, PRTime end);
|
||||
|
||||
// placement new for arena-allocation
|
||||
void *operator new (size_t aSize, nsIArena *aArena);
|
||||
|
||||
friend class nsReplacementPolicy;
|
||||
friend class nsCacheManager;
|
||||
friend class StreamAsFile;
|
||||
friend class nsCacheEntryChannel;
|
||||
friend class CacheOutputStream;
|
||||
friend class InterceptStreamListener;
|
||||
|
||||
private:
|
||||
|
||||
nsCachedNetData() {};
|
||||
virtual ~nsCachedNetData() {};
|
||||
|
||||
// Initialize internal fields of this nsCachedNetData instance from the
|
||||
// underlying raw cache database record.
|
||||
nsresult Deserialize(PRBool aDeserializeFlags);
|
||||
|
||||
// Notify stream-as-file observers about change in cache entry status
|
||||
nsresult Notify(PRUint32 aMessage, nsresult aError);
|
||||
|
||||
// Add/Remove stream-as-file observers
|
||||
nsresult AddObserver(nsIStreamAsFile *aStreamAsFile, nsIStreamAsFileObserver* aObserver);
|
||||
nsresult RemoveObserver(nsIStreamAsFileObserver* aObserver);
|
||||
|
||||
// Mark cache entry to indicate a write out to the cache database is required
|
||||
void SetDirty() { mFlags |= DIRTY; }
|
||||
|
||||
nsresult Resurrect(nsINetDataCacheRecord *aRecord);
|
||||
|
||||
nsresult CommitFlags();
|
||||
|
||||
CacheMetaData* FindTaggedMetaData(const char* aTag, PRBool aCreate);
|
||||
|
||||
private:
|
||||
|
||||
// List of nsIStreamAsFileObserver's that will receive notification events
|
||||
// when the cache manager or a client desires to delete/truncate a cache
|
||||
// entry file.
|
||||
StreamAsFileObserverClosure* mObservers;
|
||||
|
||||
// Protocol-specific meta-data, opaque to the cache manager
|
||||
CacheMetaData *mMetaData;
|
||||
|
||||
// Next in chain for a single bucket in the replacement policy hash table
|
||||
// that maps from record ID to nsCachedNetData
|
||||
nsCachedNetData* mNext;
|
||||
|
||||
// See flag bits, above
|
||||
// NOTE: 16 bit member is combined with members below for
|
||||
// struct packing efficiency. Do not change order of members!
|
||||
PRUint16 mFlags;
|
||||
|
||||
protected:
|
||||
|
||||
// Number of nsCacheEntryChannels referring to this record
|
||||
PRUint8 mChannelCount;
|
||||
|
||||
// Below members are statistics kept per cache-entry, used to decide how
|
||||
// profitable it will be to evict a record from the cache relative to other
|
||||
// existing records. Note: times are measured in *seconds* since the
|
||||
// 1/1/70 epoch, same as a unix time_t.
|
||||
|
||||
// Number of accesses for this cache record
|
||||
// NOTE: 8 bit member is combined with members above for
|
||||
// struct packing efficiency. Do not change order of members!
|
||||
PRUint8 mNumAccesses;
|
||||
|
||||
// A reference to the underlying, raw cache database record, either as a
|
||||
// pointer to an in-memory object or as a database record identifier
|
||||
union {
|
||||
nsINetDataCacheRecord* mRecord;
|
||||
|
||||
// Database record ID of associated cache record. See
|
||||
// nsINetDataCache::GetRecordByID().
|
||||
PRInt32 mRecordID;
|
||||
};
|
||||
|
||||
// Weak link to parent cache
|
||||
nsINetDataCache* mCache;
|
||||
|
||||
// Length of stored content, which may be less than storage consumed if
|
||||
// compression is used
|
||||
PRUint32 mLogicalLength;
|
||||
|
||||
// Most recent cache entry access times, used to compute access frequency
|
||||
PRUint32 mAccessTime[MAX_K];
|
||||
|
||||
// We use modification time of the original document for replacement policy
|
||||
// computations, i.e. to compute a document's age, but if we don't know it,
|
||||
// we use the time that the document was last written to the cache.
|
||||
union {
|
||||
// Document modification time, if known.
|
||||
PRUint32 mLastModifiedTime;
|
||||
|
||||
// Time of last cache update for this doc
|
||||
PRUint32 mLastUpdateTime;
|
||||
};
|
||||
|
||||
union {
|
||||
// Time until which document is fresh, i.e. does not have to be validated
|
||||
// with server and, therefore, data in cache is guaranteed usable
|
||||
PRUint32 mExpirationTime;
|
||||
|
||||
// Heuristic time at which cached document is likely to be out-of-date
|
||||
// with respect to canonical copy on server. Used for cache replacement
|
||||
// policy, not for validation.
|
||||
PRUint32 mStaleTime;
|
||||
};
|
||||
|
||||
// Download time per byte, measure roughly in units of KB/s
|
||||
float mDownloadRate;
|
||||
|
||||
// Heuristic estimate of cache entry future benefits, based on above values
|
||||
float mProfit;
|
||||
};
|
||||
|
||||
#endif // _nsCachedNetData_h_
|
||||
|
||||
666
mozilla/netwerk/cache/mgr/nsReplacementPolicy.cpp
vendored
666
mozilla/netwerk/cache/mgr/nsReplacementPolicy.cpp
vendored
@@ -1,666 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
#include "nsReplacementPolicy.h"
|
||||
#include "nsCachedNetData.h"
|
||||
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsIAllocator.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "prtime.h"
|
||||
#include "prbit.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include <math.h>
|
||||
|
||||
// Constant used to estimate frequency of access to a document based on size
|
||||
#define CACHE_CONST_B 1.35
|
||||
|
||||
// A cache whose space is managed by this replacement policy
|
||||
class nsReplacementPolicy::CacheInfo {
|
||||
public:
|
||||
CacheInfo(nsINetDataCache* aCache):mCache(aCache),mNext(0) {}
|
||||
|
||||
nsINetDataCache* mCache;
|
||||
CacheInfo* mNext;
|
||||
};
|
||||
|
||||
nsReplacementPolicy::nsReplacementPolicy()
|
||||
: mRankedEntries(0), mCaches(0), mRecordsRemovedSinceLastRanking(0),
|
||||
mNumEntries(0), mCapacityRankedEntriesArray(0), mLastRankTime(0) {}
|
||||
|
||||
nsReplacementPolicy::~nsReplacementPolicy()
|
||||
{
|
||||
if (mRankedEntries)
|
||||
nsAllocator::Free(mRankedEntries);
|
||||
if (mMapRecordIdToEntry)
|
||||
nsAllocator::Free(mMapRecordIdToEntry);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::Init(PRUint32 aMaxCacheEntries)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = NS_NewHeapArena(getter_AddRefs(mArena), sizeof(nsCachedNetData) * 32);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mMaxEntries = aMaxCacheEntries;
|
||||
|
||||
mHashArrayLength = PR_CeilingLog2(aMaxCacheEntries) >> 3;
|
||||
size_t numBytes = mHashArrayLength * sizeof(*mMapRecordIdToEntry);
|
||||
mMapRecordIdToEntry = (nsCachedNetData**)nsAllocator::Alloc(numBytes);
|
||||
if (!mMapRecordIdToEntry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCRT::zero(mMapRecordIdToEntry, numBytes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::AddCache(nsINetDataCache *aCache)
|
||||
{
|
||||
CacheInfo *cacheInfo = new CacheInfo(aCache);
|
||||
if (!cacheInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
cacheInfo->mNext = mCaches;
|
||||
mCaches = cacheInfo;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsReplacementPolicy::HashRecordID(PRInt32 aRecordID)
|
||||
{
|
||||
return ((aRecordID >> 16) ^ aRecordID) & (mHashArrayLength - 1);
|
||||
}
|
||||
|
||||
nsCachedNetData*
|
||||
nsReplacementPolicy::FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCachedNetData* cacheEntry;
|
||||
PRUint32 bucket = HashRecordID(aRecordID);
|
||||
|
||||
cacheEntry = mMapRecordIdToEntry[bucket];
|
||||
for (;cacheEntry; cacheEntry = cacheEntry->mNext) {
|
||||
|
||||
PRInt32 recordID;
|
||||
rv = cacheEntry->GetRecordID(&recordID);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
if ((recordID == aRecordID) && (cacheEntry->mCache == aCache))
|
||||
return cacheEntry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add a cache entry to the hash table that maps record ID to entries
|
||||
void
|
||||
nsReplacementPolicy::AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID)
|
||||
{
|
||||
nsCachedNetData** cacheEntryp;
|
||||
PRUint32 bucket = HashRecordID(aRecordID);
|
||||
|
||||
cacheEntryp = &mMapRecordIdToEntry[bucket];
|
||||
while (*cacheEntryp)
|
||||
cacheEntryp = &(*cacheEntryp)->mNext;
|
||||
*cacheEntryp = aCacheEntry;
|
||||
aCacheEntry->mNext = 0;
|
||||
}
|
||||
|
||||
// Delete a cache entry from the hash table that maps record ID to entries
|
||||
nsresult
|
||||
nsReplacementPolicy::DeleteCacheEntry(nsCachedNetData* aCacheEntry)
|
||||
{
|
||||
nsresult rv;
|
||||
PRInt32 recordID;
|
||||
rv = aCacheEntry->GetRecordID(&recordID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 bucket = HashRecordID(recordID);
|
||||
|
||||
nsCachedNetData** cacheEntryp;
|
||||
cacheEntryp = &mMapRecordIdToEntry[bucket];
|
||||
while (*cacheEntryp) {
|
||||
if (*cacheEntryp == aCacheEntry) {
|
||||
*cacheEntryp = aCacheEntry->mNext;
|
||||
return NS_OK;
|
||||
}
|
||||
cacheEntryp = &(*cacheEntryp)->mNext;
|
||||
}
|
||||
|
||||
NS_ASSERTION(0, "hash table inconsistency");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::AddAllRecordsInCache(nsINetDataCache *aCache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
nsCOMPtr<nsISupports> iSupports;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
rv = aCache->NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
PRBool notDone;
|
||||
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
rv = iterator->GetNext(getter_AddRefs(iSupports));
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
record = do_QueryInterface(iSupports);
|
||||
|
||||
rv = AssociateCacheEntryWithRecord(record, aCache, 0);
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Get current time and convert to seconds since the epoch
|
||||
static PRUint32
|
||||
now32()
|
||||
{
|
||||
double nowFP;
|
||||
PRInt64 now64 = PR_Now();
|
||||
LL_L2D(nowFP, now64);
|
||||
PRUint32 now = (PRUint32)(nowFP * 1e-6);
|
||||
return now;
|
||||
}
|
||||
|
||||
void
|
||||
nsCachedNetData::NoteDownloadTime(PRTime start, PRTime end)
|
||||
{
|
||||
double startFP, endFP, rate, duration;
|
||||
|
||||
LL_L2D(startFP, start);
|
||||
LL_L2D(endFP, end);
|
||||
|
||||
duration = endFP - startFP;
|
||||
|
||||
// If the data arrives so fast that it can not be timed due to the clock
|
||||
// granularity, assume a data arrival duration of 10 ms
|
||||
if (!duration)
|
||||
duration = 10000;
|
||||
|
||||
// Compute download rate in kB/s
|
||||
rate = mLogicalLength / (duration * (1e-6 * 1024.0));
|
||||
|
||||
if (mDownloadRate) {
|
||||
// Exponentially smooth download rate
|
||||
const double alpha = 0.5;
|
||||
mDownloadRate = (float)(mDownloadRate * alpha + rate * (1.0 - alpha));
|
||||
} else {
|
||||
mDownloadRate = (float)rate;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 hour
|
||||
#define MIN_HALFLIFE (60 * 60)
|
||||
|
||||
// 1 week
|
||||
#define TYPICAL_HALFLIFE (7 * 24 * 60 * 60)
|
||||
|
||||
/**
|
||||
* Estimate the profit that would be lost if the given cache entry was evicted
|
||||
* from the cache. Profit is defined as the future expected download delay per
|
||||
* byte of cached content. The profit computation is made based on projected
|
||||
* frequency of access, prior download performance and a heuristic staleness
|
||||
* criteria. The technique used is a variation of that described in the
|
||||
* following paper:
|
||||
*
|
||||
* "A Case for Delay-Conscious Caching of Web Documents"
|
||||
* http://www.bell-labs.com/user/rvingral/www97.html
|
||||
*
|
||||
* Briefly, expected profit is:
|
||||
*
|
||||
* (projected frequency of access) * (download time per byte) * (probability freshness)
|
||||
*/
|
||||
void
|
||||
nsCachedNetData::ComputeProfit(PRUint32 aNow)
|
||||
{
|
||||
PRUint32 K, now;
|
||||
|
||||
if (aNow)
|
||||
now = aNow;
|
||||
else
|
||||
now = now32();
|
||||
|
||||
K = PR_MIN(MAX_K, mNumAccesses);
|
||||
if (!K) {
|
||||
mProfit = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute time, in seconds, since k'th most recent access
|
||||
double timeSinceKthAccess = now - mAccessTime[K - 1];
|
||||
if (timeSinceKthAccess <= 0.0) // Sanity check
|
||||
timeSinceKthAccess = 1.0;
|
||||
|
||||
// Estimate frequency of future document access based on past
|
||||
// access frequency
|
||||
double frequencyAccess = K / timeSinceKthAccess;
|
||||
|
||||
// If we don't have much historical data on access frequency
|
||||
// use a heuristic based on document size as an estimate
|
||||
if (mLogicalLength) {
|
||||
if (K == 1) {
|
||||
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B);
|
||||
} else if (K == 2) {
|
||||
frequencyAccess /= pow(mLogicalLength, CACHE_CONST_B / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Estimate likelihood that data in cache is fresh, i.e.
|
||||
// that it corresponds to the document on the server
|
||||
double probabilityFreshness;
|
||||
PRInt32 halfLife, age, docTime;
|
||||
PRBool potentiallyStale;
|
||||
|
||||
docTime = GetFlag(LAST_MODIFIED_KNOWN) ? mLastModifiedTime : mLastUpdateTime;
|
||||
age = now - docTime;
|
||||
|
||||
probabilityFreshness = 1.0; // Optimistic
|
||||
|
||||
if (GetFlag(EXPIRATION_KNOWN)) {
|
||||
potentiallyStale = now > mExpirationTime;
|
||||
halfLife = mExpirationTime - mLastModifiedTime;
|
||||
} else if (GetFlag(STALE_TIME_KNOWN)) {
|
||||
potentiallyStale = PR_TRUE;
|
||||
halfLife = mStaleTime - docTime;
|
||||
} else {
|
||||
potentiallyStale = PR_TRUE;
|
||||
halfLife = TYPICAL_HALFLIFE;
|
||||
}
|
||||
|
||||
if (potentiallyStale) {
|
||||
if (halfLife < MIN_HALFLIFE)
|
||||
halfLife = MIN_HALFLIFE;
|
||||
|
||||
probabilityFreshness = pow(0.5, (double)age / (double)halfLife);
|
||||
}
|
||||
|
||||
mProfit = (float)(frequencyAccess * probabilityFreshness);
|
||||
if (mDownloadRate)
|
||||
mProfit /= mDownloadRate;
|
||||
}
|
||||
|
||||
// Number of entries to grow mRankedEntries array when it's full
|
||||
#define STATS_GROWTH_INCREMENT 256
|
||||
|
||||
|
||||
// Sorting predicate for NS_Quicksort
|
||||
int
|
||||
nsCachedNetData::Compare(const void *a, const void *b, void *unused)
|
||||
{
|
||||
nsCachedNetData* entryA = *(nsCachedNetData**)a;
|
||||
nsCachedNetData* entryB = *(nsCachedNetData**)b;
|
||||
|
||||
// Percolate deleted or empty entries to the end of the mRankedEntries
|
||||
// array, so that they can be recycled.
|
||||
if (!entryA || entryA->GetFlag(RECYCLED)) {
|
||||
if (!entryB || entryB->GetFlag(RECYCLED))
|
||||
return 0;
|
||||
else
|
||||
return +1;
|
||||
}
|
||||
if (!entryB || entryB->GetFlag(RECYCLED))
|
||||
return -1;
|
||||
|
||||
// Evicted entries (those with no content data) and active entries (those
|
||||
// currently being updated) are collected towards the end of the sorted
|
||||
// array just prior to the deleted cache entries, since evicted entries
|
||||
// can't be re-evicted.
|
||||
if (entryA->GetFlag(UPDATE_IN_PROGRESS)) {
|
||||
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
|
||||
return 0;
|
||||
else
|
||||
return +1;
|
||||
}
|
||||
if (entryB->GetFlag(UPDATE_IN_PROGRESS))
|
||||
return -1;
|
||||
|
||||
PRUint16 Ka = PR_MIN(MAX_K, entryA->mNumAccesses);
|
||||
PRUint16 Kb = PR_MIN(MAX_K, entryB->mNumAccesses);
|
||||
|
||||
// Order cache entries by the number of times they've been accessed
|
||||
if (Ka < Kb)
|
||||
return -1;
|
||||
if (Ka > Kb)
|
||||
return +1;
|
||||
|
||||
/*
|
||||
* Among records that have been accessed an equal number of times, order
|
||||
* them by profit.
|
||||
*/
|
||||
if (entryA->mProfit > entryB->mProfit)
|
||||
return +1;
|
||||
if (entryA->mProfit < entryB->mProfit)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rank cache entries in terms of their elegibility for eviction.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::RankRecords()
|
||||
{
|
||||
PRUint32 i, now;
|
||||
|
||||
// Add all cache records if this is the first ranking
|
||||
if (!mLastRankTime) {
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
rv = AddAllRecordsInCache(cacheInfo->mCache);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
// Get current time and convert to seconds since the epoch
|
||||
now = now32();
|
||||
|
||||
// Recompute profit for every known cache record, except deleted ones
|
||||
for (i = 0; i < mNumEntries; i++) {
|
||||
nsCachedNetData* entry = mRankedEntries[i];
|
||||
if (entry && !entry->GetFlag(nsCachedNetData::RECYCLED))
|
||||
entry->ComputeProfit(now);
|
||||
}
|
||||
NS_QuickSort(mRankedEntries, mNumEntries, sizeof *mRankedEntries,
|
||||
nsCachedNetData::Compare, 0);
|
||||
|
||||
mNumEntries -= mRecordsRemovedSinceLastRanking;
|
||||
mRecordsRemovedSinceLastRanking = 0;
|
||||
mLastRankTime = now;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// A heuristic policy to avoid the cost of re-ranking cache records by
|
||||
// profitability every single time space must be made available in the cache.
|
||||
void
|
||||
nsReplacementPolicy::MaybeRerankRecords()
|
||||
{
|
||||
// Rank at most once per minute
|
||||
PRUint32 now = now32();
|
||||
if ((now - mLastRankTime) >= 60)
|
||||
RankRecords();
|
||||
}
|
||||
|
||||
void
|
||||
nsReplacementPolicy::CompactRankedEntriesArray()
|
||||
{
|
||||
if (mRecordsRemovedSinceLastRanking || !mLastRankTime)
|
||||
RankRecords();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::CheckForTooManyCacheEntries()
|
||||
{
|
||||
if (mCapacityRankedEntriesArray == mMaxEntries) {
|
||||
return DeleteOneEntry(0);
|
||||
} else {
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
PRUint32 numEntries, maxEntries;
|
||||
|
||||
rv = cacheInfo->mCache->GetNumEntries(&numEntries);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = cacheInfo->mCache->GetMaxEntries(&maxEntries);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (numEntries == maxEntries)
|
||||
return DeleteOneEntry(cacheInfo->mCache);
|
||||
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new association between a low-level cache database record and a
|
||||
* cache entry. Add the entry to the set of entries eligible for eviction from
|
||||
* the cache. This would typically be done when the cache entry is created.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult)
|
||||
{
|
||||
nsCachedNetData* cacheEntry;
|
||||
nsresult rv;
|
||||
|
||||
// First, see if the record is already known to the replacement policy
|
||||
PRInt32 recordID;
|
||||
rv = aRecord->GetRecordID(&recordID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
cacheEntry = FindCacheEntryByRecordID(recordID, aCache);
|
||||
if (cacheEntry) {
|
||||
if (aResult) {
|
||||
if (cacheEntry->GetFlag(nsCachedNetData::DORMANT))
|
||||
cacheEntry->Resurrect(aRecord);
|
||||
NS_ADDREF(cacheEntry);
|
||||
*aResult = cacheEntry;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Compact the array of cache entry statistics, so that free entries appear
|
||||
// at the end, for possible reuse.
|
||||
if (mNumEntries && (mNumEntries == mCapacityRankedEntriesArray))
|
||||
CompactRankedEntriesArray();
|
||||
|
||||
// If compaction doesn't yield available entries in the
|
||||
// mRankedEntries array, then extend the array.
|
||||
if (mNumEntries == mCapacityRankedEntriesArray) {
|
||||
PRUint32 newCapacity;
|
||||
|
||||
rv = CheckForTooManyCacheEntries();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
newCapacity = mCapacityRankedEntriesArray + STATS_GROWTH_INCREMENT;
|
||||
if (newCapacity > mMaxEntries)
|
||||
newCapacity = mMaxEntries;
|
||||
|
||||
nsCachedNetData** newRankedEntriesArray;
|
||||
PRUint32 numBytes = sizeof(nsCachedNetData*) * newCapacity;
|
||||
newRankedEntriesArray =
|
||||
(nsCachedNetData**)nsAllocator::Realloc(mRankedEntries, numBytes);
|
||||
if (!newRankedEntriesArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mRankedEntries = newRankedEntriesArray;
|
||||
mCapacityRankedEntriesArray = newCapacity;
|
||||
|
||||
PRUint32 i;
|
||||
for (i = mNumEntries; i < newCapacity; i++)
|
||||
mRankedEntries[i] = 0;
|
||||
}
|
||||
|
||||
// Recycle the record after the last in-use record in the array
|
||||
nsCachedNetData *entry = mRankedEntries[mNumEntries];
|
||||
NS_ASSERTION(!entry || !entry->GetFlag(nsCachedNetData::RECYCLED),
|
||||
"Only deleted cache entries should appear at end of array");
|
||||
|
||||
if (!entry) {
|
||||
entry = new(mArena) nsCachedNetData;
|
||||
if (!entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mRankedEntries[mNumEntries] = entry;
|
||||
} else {
|
||||
// Clear out recycled data structure
|
||||
nsCRT::zero(entry, sizeof(*entry));
|
||||
}
|
||||
|
||||
entry->Init(aRecord, aCache);
|
||||
AddCacheEntry(entry, recordID);
|
||||
|
||||
// Add one reference to the cache entry from the cache manager
|
||||
NS_ADDREF(entry);
|
||||
|
||||
if (aResult) {
|
||||
// And one reference from our caller
|
||||
NS_ADDREF(entry);
|
||||
*aResult = entry;
|
||||
}
|
||||
|
||||
mNumEntries++;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
|
||||
rv = aCache->GetCachedNetData(cacheKey, cacheKeyLength,
|
||||
getter_AddRefs(record));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return AssociateCacheEntryWithRecord(record, aCache, aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the least desirable record from the cache database. This is used
|
||||
* when the addition of another record would exceed either the cache manager or
|
||||
* the cache's maximum permitted number of records.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::DeleteOneEntry(nsINetDataCache *aCache)
|
||||
{
|
||||
PRUint32 i;
|
||||
nsresult rv;
|
||||
nsCachedNetData *entry;
|
||||
|
||||
i = 0;
|
||||
while (1) {
|
||||
MaybeRerankRecords();
|
||||
for (; i < mNumEntries; i++) {
|
||||
entry = mRankedEntries[i];
|
||||
if (!entry || entry->GetFlag(nsCachedNetData::RECYCLED))
|
||||
continue;
|
||||
if (!aCache || (entry->mCache == aCache))
|
||||
break;
|
||||
}
|
||||
|
||||
// Report error if no record found to delete
|
||||
if (i == mNumEntries)
|
||||
return NS_ERROR_FAILURE;
|
||||
rv = entry->Delete();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = DeleteCacheEntry(entry);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsReplacementPolicy::GetStorageInUse(PRUint32* aStorageInUse)
|
||||
{
|
||||
nsresult rv;
|
||||
CacheInfo *cacheInfo;
|
||||
|
||||
*aStorageInUse = 0;
|
||||
cacheInfo = mCaches;
|
||||
while (cacheInfo) {
|
||||
PRUint32 cacheStorage;
|
||||
rv = cacheInfo->mCache->GetStorageInUse(&cacheStorage);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
*aStorageInUse += cacheStorage;
|
||||
cacheInfo = cacheInfo->mNext;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the least desirable records from the cache until the occupancy of the
|
||||
* cache has been reduced by the given number of KB. This is used when the
|
||||
* addition of more cache data would exceed the cache's capacity.
|
||||
*/
|
||||
nsresult
|
||||
nsReplacementPolicy::Evict(PRUint32 aTargetOccupancy)
|
||||
{
|
||||
PRUint32 i;
|
||||
nsCachedNetData *entry;
|
||||
nsresult rv;
|
||||
PRUint32 occupancy;
|
||||
PRInt32 truncatedLength;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
|
||||
MaybeRerankRecords();
|
||||
for (i = 0; i < mNumEntries; i++) {
|
||||
rv = GetStorageInUse(&occupancy);
|
||||
if (!NS_SUCCEEDED(rv)) return rv;
|
||||
|
||||
if (occupancy <= aTargetOccupancy)
|
||||
return NS_OK;
|
||||
|
||||
entry = mRankedEntries[i];
|
||||
|
||||
// Skip deleted/empty cache entries and ones that have already been evicted
|
||||
if (!entry || entry->GetFlag(nsCachedNetData::UNEVICTABLE))
|
||||
continue;
|
||||
|
||||
if (entry->GetFlag(nsCachedNetData::ALLOW_PARTIAL)) {
|
||||
rv = entry->GetRecord(getter_AddRefs(record));
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
PRUint32 contentLength;
|
||||
rv = record->GetStoredContentLength(&contentLength);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
// Additional cache storage required, in KB
|
||||
PRUint32 storageToReclaim = (occupancy - aTargetOccupancy) << 10;
|
||||
|
||||
truncatedLength = (PRInt32)(contentLength - storageToReclaim);
|
||||
if (truncatedLength < 0)
|
||||
truncatedLength = 0;
|
||||
} else {
|
||||
truncatedLength = 0;
|
||||
}
|
||||
rv = entry->Evict(truncatedLength);
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
136
mozilla/netwerk/cache/mgr/nsReplacementPolicy.h
vendored
136
mozilla/netwerk/cache/mgr/nsReplacementPolicy.h
vendored
@@ -1,136 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class manages one or more caches that share a storage resource, e.g. a
|
||||
* file cache and a flat-database cache might each occupy space on the disk and
|
||||
* they would share a single instance of nsReplacementPolicy. The replacement
|
||||
* policy heuristically chooses which cache entries to evict when storage is
|
||||
* required to accommodate incoming cache data.
|
||||
*/
|
||||
|
||||
#ifndef _nsReplacementPolicy_h_
|
||||
#define _nsReplacementPolicy_h_
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsICachedNetData.h"
|
||||
#include "nsIArena.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
class nsCachedNetData;
|
||||
struct PL_HashTable;
|
||||
|
||||
/**
|
||||
* This private class is responsible for implementing the network data cache's
|
||||
* replacement policy, i.e. it decides which cache data should be evicted to
|
||||
* make room for new incoming data.
|
||||
*/
|
||||
class nsReplacementPolicy {
|
||||
|
||||
public:
|
||||
|
||||
nsReplacementPolicy();
|
||||
~nsReplacementPolicy();
|
||||
|
||||
protected:
|
||||
|
||||
nsresult Init(PRUint32 aMaxCacheEntries);
|
||||
nsresult AddCache(nsINetDataCache *aCache);
|
||||
nsresult GetCachedNetData(const char* cacheKey, PRUint32 cacheKeyLength,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult);
|
||||
nsresult GetStorageInUse(PRUint32* aNumKBytes);
|
||||
|
||||
friend class nsCacheManager;
|
||||
|
||||
private:
|
||||
nsresult RankRecords();
|
||||
void MaybeRerankRecords();
|
||||
void CompactRankedEntriesArray();
|
||||
nsresult DeleteOneEntry(nsINetDataCache* aCache);
|
||||
nsresult Evict(PRUint32 aTargetOccupancy);
|
||||
|
||||
nsCachedNetData* FindCacheEntryByRecordID(PRInt32 aRecordID, nsINetDataCache *aCache);
|
||||
void AddCacheEntry(nsCachedNetData* aCacheEntry, PRInt32 aRecordID);
|
||||
nsresult DeleteCacheEntry(nsCachedNetData* aCacheEntry);
|
||||
PRUint32 HashRecordID(PRInt32 aRecordID);
|
||||
nsresult AssociateCacheEntryWithRecord(nsINetDataCacheRecord *aRecord,
|
||||
nsINetDataCache* aCache,
|
||||
nsCachedNetData** aResult);
|
||||
|
||||
nsresult AddAllRecordsInCache(nsINetDataCache *aCache);
|
||||
nsresult CheckForTooManyCacheEntries();
|
||||
|
||||
class CacheInfo;
|
||||
|
||||
private:
|
||||
|
||||
// Growable array of pointers to individual cache entries; It is sorted by
|
||||
// profitability, such that low-numbered array indices refer to cache
|
||||
// entries that are the least profitable to retain. New cache entries are
|
||||
// added to the end of the array. Deleted cache entries are specially
|
||||
// marked and percolate to the end of the array for recycling whenever
|
||||
// mRankedEntries is sorted. Evicted cache entries (those with no
|
||||
// associated content data) are retained for the purpose of improving the
|
||||
// replacement policy efficacy, and are percolated towards the end of the
|
||||
// array, just prior to the deleted cache entries.
|
||||
//
|
||||
// The array is not in sorted order 100% of the time; For efficiency
|
||||
// reasons, sorting is only done when heuristically deemed necessary.
|
||||
nsCachedNetData** mRankedEntries;
|
||||
|
||||
// Hash table buckets to map Record ID to cache entry. We use this instead
|
||||
// of a PL_HashTable to reduce storage requirements
|
||||
nsCachedNetData** mMapRecordIdToEntry;
|
||||
|
||||
// Length of mMapRecordIdToEntry array
|
||||
PRUint32 mHashArrayLength;
|
||||
|
||||
// Linked list of caches that share this replacement policy
|
||||
CacheInfo* mCaches;
|
||||
|
||||
// Allocation area for cache entry (nsCachedNetData) instances
|
||||
nsCOMPtr<nsIArena> mArena;
|
||||
|
||||
// Bookkeeping
|
||||
PRUint32 mRecordsRemovedSinceLastRanking;
|
||||
|
||||
// Maximum permitted length of mRankedEntries array
|
||||
PRUint32 mMaxEntries;
|
||||
|
||||
// Number of occupied slots in mRankedEntries array
|
||||
PRUint32 mNumEntries;
|
||||
|
||||
// Capacity of mRankedEntries array
|
||||
PRUint32 mCapacityRankedEntriesArray;
|
||||
|
||||
// Time at which cache entries were last ranked by profitability
|
||||
PRUint32 mLastRankTime;
|
||||
};
|
||||
|
||||
|
||||
#endif // _nsReplacementPolicy_h_
|
||||
43
mozilla/netwerk/cache/public/Makefile.in
vendored
43
mozilla/netwerk/cache/public/Makefile.in
vendored
@@ -1,43 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsICachedNetData.idl \
|
||||
nsINetDataCacheManager.idl \
|
||||
nsINetDataCache.idl \
|
||||
nsINetDataCacheRecord.idl \
|
||||
nsINetDataDiskCache.idl \
|
||||
nsIStreamAsFile.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
41
mozilla/netwerk/cache/public/Makefile.win
vendored
41
mozilla/netwerk/cache/public/Makefile.win
vendored
@@ -1,41 +0,0 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
MODULE = nkcache
|
||||
|
||||
DEPTH = ..\..\..
|
||||
include <$(DEPTH)/config/config.mak>
|
||||
|
||||
|
||||
EXPORTS = \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
.\nsICachedNetData.idl \
|
||||
.\nsINetDataCacheManager.idl \
|
||||
.\nsINetDataCache.idl \
|
||||
.\nsINetDataCacheRecord.idl \
|
||||
.\nsINetDataDiskCache.idl \
|
||||
.\nsIStreamAsFile.idl \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
||||
229
mozilla/netwerk/cache/public/nsICachedNetData.idl
vendored
229
mozilla/netwerk/cache/public/nsICachedNetData.idl
vendored
@@ -1,229 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsrootidl.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
interface nsIURI;
|
||||
interface nsIObserver;
|
||||
interface nsIChannel;
|
||||
interface nsINetDataCache;
|
||||
interface nsINetDataCacheRecord;
|
||||
interface nsILoadGroup;
|
||||
interface nsIStreamListener;
|
||||
|
||||
/**
|
||||
* The nsICachedNetData interface represents a single entry in a database that
|
||||
* caches data retrieved from the network. This interface is implemented by the
|
||||
* cache manager on top of the low-level nsINetDataCacheRecord and
|
||||
* nsINetDataCache interfaces that are implemented by the database.
|
||||
*
|
||||
* Each cache record may contain both content and metadata. The content may
|
||||
* be, for example, GIF image data or HTML, and it is accessed through
|
||||
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
|
||||
* headers among other things, is stored as a byte array. Each entry in the
|
||||
* cache is indexed by two different keys: a record id number and a key created
|
||||
* by combining the URI with a "secondary key", e.g. HTTP post data.
|
||||
*
|
||||
* @See nsINetDataCacheRecord
|
||||
* @See nsINetDataCache
|
||||
* @See nsINetDataDiskCache
|
||||
* @See nsINetDataCacheManager
|
||||
*/
|
||||
[scriptable, uuid(6aeb2a40-6d43-11d3-90c8-000064657374)]
|
||||
interface nsICachedNetData : nsISupports
|
||||
{
|
||||
/**
|
||||
* String form of the URI provided as an argument to the call to
|
||||
* nsINetDataCacheManager::GetCachedNetData() that created this record.
|
||||
*/
|
||||
readonly attribute string uriSpec;
|
||||
|
||||
/**
|
||||
* Getter for the opaque secondary database key provided as an argument to
|
||||
* the call to nsINetDataCacheManager::GetCachedNetData() that created this
|
||||
* record.
|
||||
*/
|
||||
void getSecondaryKey(out unsigned long length,
|
||||
[retval, size_is(length)] out string secondaryKey);
|
||||
|
||||
/**
|
||||
* This flag may be set by a protocol handler to indicate that it supports
|
||||
* partial fetching of data. In that case, the cache manager is permitted
|
||||
* to truncate the entry's content to accommodate incoming data for other
|
||||
* cache entries rather than deleting it wholesale.
|
||||
*/
|
||||
attribute boolean allowPartial;
|
||||
|
||||
/**
|
||||
* This flag indicates that the write stream supplying content data for the
|
||||
* cache did not complete normally and, therefore, the content may be
|
||||
* truncated.
|
||||
*/
|
||||
readonly attribute boolean partialFlag;
|
||||
|
||||
/**
|
||||
* This flag can be set and cleared by a protocol handler as a form of
|
||||
* self-notification, so as to avoid race conditions in which a protocol
|
||||
* handler issues two identical network requests to fill the same cache
|
||||
* entry. The cache manager itself largely ignores this flag.
|
||||
*/
|
||||
attribute boolean updateInProgress;
|
||||
|
||||
/**
|
||||
* inUse is set if any existing channels are associated with this cache
|
||||
* entry or if the updateInProgess flag is set. This can be used to
|
||||
* prevent writing to a cache entry by a protocol handler if it's being
|
||||
* read or written elsewhere.
|
||||
*/
|
||||
readonly attribute boolean inUse;
|
||||
|
||||
/**
|
||||
* Date/time that the document was last stored on the origin server, as
|
||||
* supplied by the protocol handler. This value is used as input to the
|
||||
* cache replacement policy, i.e. it is not used for validation. If the
|
||||
* protocol can't supply a last-modified time, this attribute should remain
|
||||
* unset. When unset, the value of this attribute is zero.
|
||||
*
|
||||
* FIXME: Should use nsIDateTime interface, once it's created
|
||||
* instead of PRTime, for improved scriptability ?
|
||||
*/
|
||||
attribute PRTime lastModifiedTime;
|
||||
|
||||
/**
|
||||
* Supplied by the protocol handler, the expirationTime attribute specifies
|
||||
* the time until which the document is guaranteed fresh, i.e. the document
|
||||
* does not have to be validated with the server and, therefore, any data
|
||||
* in cache is definitely usable. The value of this attribute serves as a
|
||||
* hint to the cache replacement policy. Only one of either staleTime or
|
||||
* expirationTime may be set for a single cache record. When unset, the
|
||||
* value of this attribute is zero.
|
||||
*/
|
||||
attribute PRTime expirationTime;
|
||||
|
||||
/**
|
||||
* Date/time supplied by the protocol handler, at which point the content
|
||||
* is *likely* to be stale, i.e. the data in the cache may be out-of-date
|
||||
* with respect to the data on the server. This heuristic date does not
|
||||
* necessarily correspond to the HTTP Expires header, as it does not
|
||||
* determine when cached network data must be validated with the origin
|
||||
* server, but only serves as a hint to the cache replacement policy. Only
|
||||
* one of either staleTime or expirationTime may be set for a single cache
|
||||
* record. When unset, the value of this attribute is zero.
|
||||
*/
|
||||
attribute PRTime staleTime;
|
||||
|
||||
/**
|
||||
* Date/time of last access of the data in this cache record, as determined
|
||||
* by the cache manager.
|
||||
*/
|
||||
readonly attribute PRTime lastAccessTime;
|
||||
|
||||
/**
|
||||
* Number of times this record has been accessed since it was first stored.
|
||||
*/
|
||||
readonly attribute PRUint16 numberAccesses;
|
||||
|
||||
/**
|
||||
* Accessor methods for opaque meta-data which can be read and updated
|
||||
* independently of the content data.
|
||||
*
|
||||
* The aTag argument can be used to accommodate multiple clients of the
|
||||
* cache API, each of which wants to store its own private meta-data into
|
||||
* the cache. For example, there could be a "headers" tag that the HTTP
|
||||
* protocol handler uses to store http response headers and a "image size"
|
||||
* tag used to store the image dimensions of a GIF file. The aData
|
||||
* argument refers to an opaque blob of arbitrary bytes.
|
||||
*
|
||||
* IMPORTANT: If aData does not contain byte-oriented data, i.e. it's not a
|
||||
* string, the contents of aData must be byte-swapped by the,
|
||||
* caller, so as to make the cache files endian-independent.
|
||||
*/
|
||||
void getAnnotation(in string aTag,
|
||||
out PRUint32 aLength, [size_is(aLength), retval] out string aData);
|
||||
void setAnnotation(in string aTag,
|
||||
in PRUint32 aLength, [size_is(aLength)] in string aData);
|
||||
|
||||
/**
|
||||
* As a getter, return the number of content bytes stored in the cache,
|
||||
* i.e. via the nsIChannel streaming APIs. This may be less than the
|
||||
* complete content length if a partial cache fill occurred. The cached
|
||||
* content can be truncated by setting the value of this attribute. The
|
||||
* value of the attribute represents a logical, not a physical, length. If
|
||||
* compression has been used, the content may consume less storage than
|
||||
* indicated by this attribute.
|
||||
*
|
||||
* When this attribute is set to zero the associated cache disk file, if
|
||||
* any, should be deleted.
|
||||
*/
|
||||
attribute PRUint32 storedContentLength;
|
||||
|
||||
/**
|
||||
* Notify any observers associated with this cache entry of the deletion
|
||||
* request. If all observers drop their reference to the cache entry,
|
||||
* proceed to delete the underlying cache database record and associated
|
||||
* content storage.
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Flush any changes in this entry's data to the cache database. This
|
||||
* method will automatically be called when the last reference to the cache
|
||||
* is dropped, but it can also be called explicitly for a synchronous
|
||||
* effect.
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Parent container cache for this entry.
|
||||
*/
|
||||
readonly attribute nsINetDataCache cache;
|
||||
|
||||
/**
|
||||
* Create a channel for reading or writing a stream of content into the
|
||||
* entry. It is expected that many of the nsIChannel methods return
|
||||
* NS_NOT_IMPLEMENTED, including:
|
||||
*
|
||||
* + GetURI()
|
||||
* + GetContentType()
|
||||
* + GetContentLength()
|
||||
*
|
||||
* Though nsIChannel provides for both async and synchronous I/O APIs, both
|
||||
* may not be implemented. Only AsyncRead() and OpenOutputStream() is
|
||||
* required. The aProxyChannel argument allows another channel to be
|
||||
* specified as the proffered argument to nsIStreamListener methods rather
|
||||
* than the cache's own channel.
|
||||
*/
|
||||
nsIChannel newChannel(in nsILoadGroup aLoadGroup,
|
||||
in nsIChannel aProxyChannel);
|
||||
|
||||
/**
|
||||
* This method can be used by a caching protocol handler to store data in
|
||||
* the cache by forking an asynchronous read stream so that it is
|
||||
* simultaneously sent to a requester and written into the cache. This
|
||||
* method implicitly sets the updateInProgress flag, if it has not already
|
||||
* been set.
|
||||
*/
|
||||
nsIStreamListener interceptAsyncRead(in nsIStreamListener aOriginalListener,
|
||||
in PRUint32 aStartOffset);
|
||||
};
|
||||
143
mozilla/netwerk/cache/public/nsINetDataCache.idl
vendored
143
mozilla/netwerk/cache/public/nsINetDataCache.idl
vendored
@@ -1,143 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsINetDataCacheRecord;
|
||||
interface nsISimpleEnumerator;
|
||||
interface nsIFileSpec;
|
||||
|
||||
/**
|
||||
* The nsINetDataCache defines the low-level API for a network-data
|
||||
* cache, used to cache the responses to network retrieval commands.
|
||||
* This interface, along with nsINetDataCacheRecord, is implemented by
|
||||
* the memory cache, the file cache and, optionally, by some extension
|
||||
* caches. This interface is essentially a pseudo-private API for the
|
||||
* cache manager. Other clients should never use this interface.
|
||||
*
|
||||
* Each cache entry may contain both content, e.g. GIF image data, and
|
||||
* associated metadata, e.g. HTTP headers. Each entry is indexed by two
|
||||
* different keys: a record id number and a key created by combining the URI
|
||||
* with a "secondary key", e.g. HTTP post data.
|
||||
*
|
||||
* The nsINetDataCache interface is agnostic as to where the data is
|
||||
* stored and whether the storage is volatile or persistent. The
|
||||
* memory cache, any disk caches and any extension caches must all
|
||||
* implement this interface.
|
||||
*
|
||||
*/
|
||||
[scriptable, uuid(ccfc58c0-6dde-11d3-90c8-000064657374)]
|
||||
interface nsINetDataCache : nsISupports
|
||||
{
|
||||
/**
|
||||
* Human-readable description of the cache module, e.g. "Disk Cache"
|
||||
*/
|
||||
readonly attribute wstring description;
|
||||
|
||||
/**
|
||||
* Returns true if cached data is available for the given opaque key,
|
||||
* even if only partial data is stored.
|
||||
*/
|
||||
boolean contains([size_is(length)] in string key, in PRUint32 length);
|
||||
|
||||
/**
|
||||
* Fetch the cache entry record for the given opaque key. If one does not
|
||||
* exist, create a new, empty record.
|
||||
*/
|
||||
nsINetDataCacheRecord getCachedNetData([size_is(length)] in string key,
|
||||
in PRUint32 length);
|
||||
|
||||
/**
|
||||
* Fetch the cache entry record for the given URI using the record ID as a key.
|
||||
*/
|
||||
nsINetDataCacheRecord getCachedNetDataByID(in PRInt32 RecordID);
|
||||
|
||||
/**
|
||||
* False indicates that this cache is entirely bypassed.
|
||||
*/
|
||||
attribute boolean enabled;
|
||||
|
||||
/**
|
||||
* Constants for flags attribute, below
|
||||
*/
|
||||
|
||||
// Used for extension caches, e.g. a CD-ROM cache
|
||||
const long READ_ONLY = 1 << 0;
|
||||
|
||||
// One of these bits must be set
|
||||
const long MEMORY_CACHE = 1 << 1;
|
||||
const long FLAT_FILE_CACHE = 1 << 2;
|
||||
const long FILE_PER_URL_CACHE = 1 << 3;
|
||||
|
||||
/**
|
||||
* See constants defined above.
|
||||
*/
|
||||
readonly attribute PRUint32 flags;
|
||||
|
||||
/**
|
||||
* Total number of URI entries stored in the cache.
|
||||
*/
|
||||
readonly attribute PRUint32 numEntries;
|
||||
|
||||
/**
|
||||
* Maximum number of URI entries that may be stored in the cache.
|
||||
*/
|
||||
readonly attribute PRUint32 maxEntries;
|
||||
|
||||
/**
|
||||
* Enumerate the URI entries stored in the cache.
|
||||
*/
|
||||
nsISimpleEnumerator newCacheEntryIterator();
|
||||
|
||||
/**
|
||||
* Contains a reference to the next cache in search order. For the memory
|
||||
* cache, this attribute always references the disk cache. For the disk
|
||||
* cache, it contains a reference to the first extension cache.
|
||||
*/
|
||||
attribute nsINetDataCache nextCache;
|
||||
|
||||
/**
|
||||
* An estimate of the amount of storage occupied by the cache, in kB.
|
||||
* Actual use may be slightly higher than reported due to cache overhead
|
||||
* and heap fragmentation (in the memory cache) or block quantization (in
|
||||
* the disk cache).
|
||||
*/
|
||||
readonly attribute PRUint32 storageInUse;
|
||||
|
||||
/**
|
||||
* Remove all entries from a writable cache. This could be used, for
|
||||
* example, after a guest ends a browser session. This is equivalent to
|
||||
* setting the cache's Capacity to zero, except that all cache entries,
|
||||
* even those in active use, will be deleted. Also, any global cache
|
||||
* database files will be deleted.
|
||||
*/
|
||||
void removeAll();
|
||||
};
|
||||
|
||||
%{ C++
|
||||
// ProgID prefix for Components that implement this interface
|
||||
#define NS_NETWORK_CACHE_PROGID "component://netscape/network/cache"
|
||||
#define NS_NETWORK_MEMORY_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=memory-cache"
|
||||
#define NS_NETWORK_FLAT_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=flat-cache"
|
||||
#define NS_NETWORK_FILE_CACHE_PROGID NS_NETWORK_CACHE_PROGID "?name=file-cache"
|
||||
%}
|
||||
@@ -1,163 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsISimpleEnumerator;
|
||||
interface nsICachedNetData;
|
||||
interface nsINetDataCache;
|
||||
interface nsINetDataDiskCache;
|
||||
interface nsIURI;
|
||||
interface nsIFileSpec;
|
||||
|
||||
/**
|
||||
* The network-response cache manager is partly responsible for the caching of
|
||||
* content and associated metadata that has been retrieved via the network.
|
||||
* (The remaining responsibility for caching lies with individual network
|
||||
* protocol handlers.)
|
||||
*
|
||||
* The cache manager supervises the actions of individual cache components,
|
||||
* such as the memory cache, the disk cache and any extension caches, e.g. a
|
||||
* read-only CD-ROM cache.
|
||||
*
|
||||
* @See nsINetDataCache
|
||||
* @See nsICachedNetData
|
||||
*/
|
||||
[scriptable, uuid(71c8ab00-6d5c-11d3-90c8-000064657374)]
|
||||
interface nsINetDataCacheManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Flag for the GetCachedNetData() method: If set, the memory cache is
|
||||
* neither searched nor will any data be stored into it. This might be
|
||||
* appropriate, for example, with images, because they have their own
|
||||
* cache for storing *decoded* images.
|
||||
*/
|
||||
const unsigned long BYPASS_MEMORY_CACHE = 1 << 0;
|
||||
|
||||
/**
|
||||
* Flag for the GetCachedNetData() method: If set, the disk cache
|
||||
* is neither searched nor will any be data stored into it.
|
||||
* However, read-only extension caches may be searched. This
|
||||
* might be used to avoid leaving persistent records of secure
|
||||
* data.
|
||||
*/
|
||||
const unsigned long BYPASS_PERSISTENT_CACHE = 1 << 1;
|
||||
|
||||
/**
|
||||
* Flag for the GetCachedNetData() method: If set, any stream
|
||||
* content is stored in the cache as a single disk file. Content
|
||||
* will not be cached in the memory cache nor is it cached in a
|
||||
* flat-file cache database. This is used to implement the jar
|
||||
* protocol handler and to provide the stream-as-file semantics
|
||||
* required by the classic bowser plugin API.
|
||||
*/
|
||||
const unsigned long CACHE_AS_FILE = 1 << 2;
|
||||
|
||||
/**
|
||||
* Fetch the cache entry record for the given URI. If one does not exist,
|
||||
* create a new, empty record. The normal search order for caches is:
|
||||
* + Memory cache
|
||||
* + Disk cache
|
||||
* + File cache (stream-as-file cache)
|
||||
* + All extension caches
|
||||
*
|
||||
* When writing, data is typically stored in both the memory cache and the
|
||||
* disk cache. Both the search order and this write policy can be modified by
|
||||
* setting one or more of the flag argument bits, as defined above.
|
||||
*
|
||||
* The optionally-NULL secondaryKey argument can be used, e.g. for form
|
||||
* post data or for HTTP headers in the case of HTTP.
|
||||
*/
|
||||
nsICachedNetData getCachedNetData(in string uri,
|
||||
[size_is(secondaryKeyLength)] in string secondaryKey,
|
||||
in PRUint32 secondaryKeyLength,
|
||||
in PRUint32 flags);
|
||||
|
||||
/**
|
||||
* Returns true if cached content is available for the given URI, even if
|
||||
* only partial data is stored. The flags argument behaves the same as for
|
||||
* the GetCachedNetData() method, above.
|
||||
*/
|
||||
boolean contains(in string uri,
|
||||
[size_is(secondaryKeyLength)] in string secondaryKey,
|
||||
in PRUint32 secondaryKeyLength,
|
||||
in PRUint32 flags);
|
||||
|
||||
/**
|
||||
* Total number of unexpired URI entries stored in all caches. This number
|
||||
* does not take into account duplicate URIs, e.g. because the memory cache
|
||||
* and the disk cache might each contain an entry for the same URI.
|
||||
*/
|
||||
readonly attribute PRUint32 numEntries;
|
||||
|
||||
/**
|
||||
* Enumerate the unexpired URI entries stored in all caches. Some URIs may
|
||||
* be enumerated more than once, e.g. because the the memory cache and the
|
||||
* disk cache might each contain an entry for the same URI.
|
||||
*/
|
||||
nsISimpleEnumerator newCacheEntryIterator();
|
||||
|
||||
/*
|
||||
* Enumerate all the loaded nsINetDataCache-implementing cache modules.
|
||||
* The first module enumerated will be the memory cache, the second will be
|
||||
* the disk cache, then the file cache, followed by all the extension
|
||||
* caches, in search order.
|
||||
*/
|
||||
nsISimpleEnumerator newCacheModuleIterator();
|
||||
|
||||
/**
|
||||
* Remove all entries from all writable caches. This could be used, for
|
||||
* example, after a guest ends a browser session. This is equivalent to
|
||||
* setting the DiskCacheCapacity to zero, except that all cache entries,
|
||||
* even those in active use, will be deleted. Also, any global cache
|
||||
* database files will be deleted.
|
||||
*/
|
||||
void RemoveAll();
|
||||
|
||||
/**
|
||||
* The disk cache is made up of the file cache (for stream-as-file
|
||||
* requests) and a (possibly independent) persistent cache that handles all
|
||||
* other cache requests. This attribute sets/gets the combined capacity of
|
||||
* these caches, measured in KBytes. Setting the capacity lower than the
|
||||
* current amount of space currently in use may cause cache entries to be
|
||||
* evicted from the cache to accomodate the requested capacity.
|
||||
*/
|
||||
attribute PRUint32 diskCacheCapacity;
|
||||
|
||||
/**
|
||||
* This attribute sets/gets the capacity of the memory cache, measured in
|
||||
* KBytes. Setting the capacity lower than the current amount of space
|
||||
* currently in use may cause cache entries to be evicted from the cache to
|
||||
* accomodate the requested capacity.
|
||||
*/
|
||||
attribute PRUint32 memCacheCapacity;
|
||||
|
||||
/**
|
||||
* This attribute must be set before attempting to store into the disk cache.
|
||||
*/
|
||||
attribute nsIFileSpec diskCacheFolder;
|
||||
};
|
||||
|
||||
%{ C++
|
||||
// ProgID prefix for Components that implement this interface
|
||||
#define NS_NETWORK_CACHE_MANAGER_PROGID NS_NETWORK_CACHE_PROGID "?name=manager"
|
||||
%}
|
||||
@@ -1,125 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsrootidl.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
interface nsIChannel;
|
||||
interface nsINetDataCache;
|
||||
|
||||
/**
|
||||
* The nsINetDataCacheRecord represents a single entry in a database that
|
||||
* caches data retrieved from the network. On top of this low-level interface
|
||||
* to the raw record data, the cache manager implements a higher-level record
|
||||
* interface, nsICachedNetData. Each instance of nsINetDataCacheRecord is
|
||||
* (internally) associated with a parent database, an instance of the
|
||||
* nsINetDataCache interface. This interface is essentially a pseudo-private
|
||||
* API for the cache manager. Other clients should never use this interface.
|
||||
*
|
||||
* Each cache record may contain both content and metadata. The content may
|
||||
* be, for example, GIF image data or HTML, and it is accessed through
|
||||
* nsIChannel's streaming API. The opaque metadata, which may contain HTTP
|
||||
* headers among other things, is accessed as a contiguous byte array. Each
|
||||
* entry in the cache is indexed by two different keys: a unique record id
|
||||
* number, generated by the cache, and an opaque string. The latter contains
|
||||
* the URI and other secondary key information, e.g. HTTP form post key/value
|
||||
* pairs.
|
||||
*
|
||||
* The nsINetDataCacheRecord interface is agnostic as to where the data is
|
||||
* stored and whether the storage is volatile or persistent. The memory cache,
|
||||
* the disk cache, a flat-file cache and any read-only extension caches must
|
||||
* all implement this interface.
|
||||
*
|
||||
* @See nsICachedNetData
|
||||
* @See nsINetDataCache
|
||||
* @See nsINetDataDiskCache
|
||||
* @See nsINetDataCacheManager
|
||||
*/
|
||||
|
||||
interface nsILoadGroup;
|
||||
|
||||
[scriptable, uuid(fdcdd6a0-7461-11d3-90ca-0040056a906e)]
|
||||
interface nsINetDataCacheRecord : nsISupports
|
||||
{
|
||||
/**
|
||||
* As far as the nsINetDataCacheRecord implementation is concerned, the
|
||||
* cache entry database key is an opaque blob, but it's intended to contain
|
||||
* both the URI and any secondary keys, such as HTTP post data.
|
||||
*/
|
||||
void getKey(out unsigned long length, [size_is(length), retval] out string key);
|
||||
|
||||
/**
|
||||
* A persistent record number assigned by the cache which must be unique
|
||||
* among all entries stored within the same cache. The record ID serves as
|
||||
* an alternate key to the cache record. Providing that they satisfy the
|
||||
* afforementioned uniqueness requirement, record IDs can be assigned any
|
||||
* value by the database except that they may never be zero.
|
||||
*/
|
||||
readonly attribute PRInt32 recordID;
|
||||
|
||||
/**
|
||||
* Opaque data which can be updated for each cache entry independently of
|
||||
* the content data. This data is a combination of protocol-independent
|
||||
* data provided by the cache manager and protocol-specific meta-data,
|
||||
* e.g. HTTP headers.
|
||||
*/
|
||||
void getMetaData(out PRUint32 length, [size_is(length), retval] out string metaData);
|
||||
void setMetaData(in PRUint32 length, [size_is(length)] in string data);
|
||||
|
||||
/**
|
||||
* Number of content bytes stored in the cache, i.e. via the nsIChannel
|
||||
* streaming APIs. This may be less than the complete content length if a
|
||||
* partial cache fill occurred. Additionally, the cached content can be
|
||||
* truncated by reducing the value of this attribute. When this attribute
|
||||
* is set to zero the associated cache disk file, if any, should be
|
||||
* deleted.
|
||||
*/
|
||||
attribute PRUint32 storedContentLength;
|
||||
|
||||
/**
|
||||
* Delete this cache entry and its associated content.
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Create a channel for reading or writing a stream of content into the
|
||||
* entry. However, many of the nsIChannel methods may return
|
||||
* NS_NOT_IMPLEMENTED, including:
|
||||
*
|
||||
* + GetURI()
|
||||
* + GetContentType()
|
||||
* + GetContentLength()
|
||||
*/
|
||||
nsIChannel newChannel(in nsILoadGroup loadGroup);
|
||||
|
||||
/**
|
||||
* If a cache is implemented such that it stores each URI's content in an
|
||||
* individual disk file, this method will identify the file corresponding
|
||||
* to this record. This may be used to implement the "stream-as-file"
|
||||
* semantics required by some plugins and by the 'jar:' protocol handler.
|
||||
* However, not all cache implementations are *required* to store the data
|
||||
* from each URI in an individual file, so it is acceptable for an
|
||||
* implementation of this method to signal NS_NOT_IMPLEMENTED.
|
||||
*/
|
||||
readonly attribute nsIFileSpec filename;
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsINetDataCache.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
|
||||
/**
|
||||
/**
|
||||
* A network-data disk cache is used to persistently cache the responses to
|
||||
* network retrieval commands. Each cache entry may contain both content,
|
||||
* e.g. GIF image data, and associated metadata, e.g. HTTP headers.
|
||||
*/
|
||||
[scriptable, uuid(6408e390-6f13-11d3-90c8-000064657374)]
|
||||
interface nsINetDataDiskCache : nsINetDataCache
|
||||
{
|
||||
/**
|
||||
* This attribute must be set before calling any other methods of this
|
||||
* interface.
|
||||
*/
|
||||
attribute nsIFileSpec diskCacheFolder;
|
||||
};
|
||||
|
||||
106
mozilla/netwerk/cache/public/nsIStreamAsFile.idl
vendored
106
mozilla/netwerk/cache/public/nsIStreamAsFile.idl
vendored
@@ -1,106 +0,0 @@
|
||||
/* -*- 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.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/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, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Furman, fur@netscape.com
|
||||
*/
|
||||
#include "nsrootidl.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIFileSpec;
|
||||
interface nsIStreamAsFileObserver;
|
||||
|
||||
/**
|
||||
* In addition to enhancing effective network response time via caching, the
|
||||
* cache manager serves a second purpose by providing the stream-as-file
|
||||
* service required by traditional browser plugins and the jar: protocol
|
||||
* handler. The interface below provides a means for a client to determine the
|
||||
* filename associated with a stream and to detect modification/deletion of
|
||||
* that file.
|
||||
*/
|
||||
[scriptable, uuid(0eedbbf0-92d9-11d3-90d3-0040056a906e)]
|
||||
interface nsIStreamAsFile : nsISupports
|
||||
{
|
||||
/**
|
||||
* Filename containing stream-as-file
|
||||
*/
|
||||
readonly attribute nsIFileSpec fileSpec;
|
||||
|
||||
/**
|
||||
* Add an observer for this cache record. When the cache wants to delete
|
||||
* or truncate a record, so as to make space for another cache entry's
|
||||
* content data, it will call <code>aObserver</code>'s Observe() method,
|
||||
* passing the nsIStreamAsFile instance as the <code>aSubject</code>
|
||||
* argument and an appropriate message. If the observer does not wish to
|
||||
* inhibit deletion/truncation, it should Release() any references it has to the
|
||||
* cache record.
|
||||
*
|
||||
* @See nsIStreamAsFileObserver
|
||||
*/
|
||||
void addObserver(in nsIStreamAsFileObserver aObserver);
|
||||
|
||||
/**
|
||||
* Delete an observer that was added by the AddObserver() method.
|
||||
*/
|
||||
void removeObserver(in nsIStreamAsFileObserver aObserver);
|
||||
};
|
||||
|
||||
/**
|
||||
* This interface can be implemented by a client to receive notifications of
|
||||
* either modification or deletion of a file created by the cache manager using
|
||||
* the stream-as-file semantics.
|
||||
*/
|
||||
[scriptable, uuid(a26e27c0-92da-11d3-90d3-0040056a906e)]
|
||||
interface nsIStreamAsFileObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
* Flag bits for argument to Observe() method.
|
||||
*/
|
||||
const long NOTIFY_AVAILABLE = 1 << 0; // Stream-as-file now available for reading
|
||||
const long NOTIFY_ERROR = 1 << 1; // Error while loading stream / creating file
|
||||
const long REQUEST_DELETION = 1 << 2; // Cache manager wishes to delete/truncate file
|
||||
const long INVALIDATE = 1 << 3; // File is out-of-date
|
||||
|
||||
// Convenience value
|
||||
const long MAKE_UNAVAILABLE = REQUEST_DELETION | INVALIDATE;
|
||||
|
||||
/**
|
||||
* Receive either a notification or a request concerning a file that has
|
||||
* been opened using stream-as-file. The aMessage and aError arguments
|
||||
* have varying values depending on the nature of the notification.
|
||||
* aMessage is set to NOTIFY_AVAILABLE when a complete stream has been read
|
||||
* and stored on disk in a file. At that point, and no sooner, may the
|
||||
* filename attribute of the associated nsIStreamAsFile be accessed via the
|
||||
* associated nsIStreamAsFile interface. If the aMessage argument is
|
||||
* NOTIFY_ERROR, the aError argument contains the relevant error code. If
|
||||
* the aMessage argument is either REQUEST_DELETION or REQUEST_TRUNCATION,
|
||||
* the callee should immediately Release() all references to the
|
||||
* nsIStreamAsFile (and any references to its associated nsICachedNetData
|
||||
* instances), unless it wishes to inhibit the requested file modification.
|
||||
* If the aMessage argument is INVALIDATE, the cache manager is replacing
|
||||
* the file with a more recent version. If a client wants to continue
|
||||
* using the (now out-of-date) file, it must delete it when it has finished,
|
||||
* as the cache manager will effectively relinquished ownership of the
|
||||
* file.
|
||||
*/
|
||||
void ObserveStreamAsFile(in nsIStreamAsFile aStreamAsFile,
|
||||
in PRUint32 aMessage,
|
||||
in nsresult aError);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
DEPTH = ..
|
||||
|
||||
MODULE = necko
|
||||
|
||||
DIRS= \
|
||||
base \
|
||||
dns \
|
||||
build \
|
||||
protocol \
|
||||
socket \
|
||||
util \
|
||||
mime \
|
||||
streamconv \
|
||||
cache \
|
||||
test \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
@@ -1,32 +0,0 @@
|
||||
/* -*- Mode: IDL; 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIAtom;
|
||||
|
||||
[scriptable, uuid(a3ec67f0-465a-11d3-9a89-0080c7cb1080)]
|
||||
interface nsIHTTPHeader : nsISupports
|
||||
{
|
||||
nsIAtom GetField();
|
||||
string GetValue();
|
||||
};
|
||||
@@ -1,603 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamObserver.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataCacheManager.h"
|
||||
#include "nsICachedNetData.h"
|
||||
|
||||
|
||||
// Number of test entries to be placed in the cache
|
||||
// FIXME - temporary
|
||||
#define NUM_CACHE_ENTRIES 25
|
||||
|
||||
// Cache content stream length will have random length between zero and
|
||||
// MAX_CONTENT_LENGTH bytes
|
||||
#define MAX_CONTENT_LENGTH 20000
|
||||
|
||||
// Limits, converted to KB
|
||||
#define DISK_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 4) >> 10)
|
||||
#define MEM_CACHE_CAPACITY ((MAX_CONTENT_LENGTH * 3) >> 10)
|
||||
|
||||
// Length of random-data cache entry URI key
|
||||
#define CACHE_KEY_LENGTH 13
|
||||
|
||||
// Length of random-data cache entry secondary key
|
||||
#define CACHE_SECONDARY_KEY_LENGTH 10
|
||||
|
||||
// Length of random-data cache entry meta-data
|
||||
#define CACHE_PROTOCOL_PRIVATE_LENGTH 10
|
||||
|
||||
// Mapping from test case number to RecordID
|
||||
static PRInt32 recordID[NUM_CACHE_ENTRIES];
|
||||
|
||||
static PRInt32
|
||||
mapRecordIdToTestNum(PRInt32 aRecordID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
|
||||
if (recordID[i] == aRecordID)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// A supply of stream data to either store or compare with
|
||||
class nsITestDataStream {
|
||||
public:
|
||||
virtual ~nsITestDataStream() {};
|
||||
virtual PRUint32 Next() = 0;
|
||||
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void ReadString(char* aBuf, PRUint32 aCount) = 0;
|
||||
|
||||
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual PRBool MatchString(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void Skip(PRUint32 aCount) = 0;
|
||||
virtual void SkipString(PRUint32 aCount) = 0;
|
||||
};
|
||||
|
||||
// A reproducible stream of random data.
|
||||
class RandomStream : public nsITestDataStream {
|
||||
public:
|
||||
RandomStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState = 1103515245 * mState + 12345 ^ (mState >> 16);
|
||||
return mState;
|
||||
}
|
||||
|
||||
PRUint8 NextChar() {
|
||||
PRUint8 c;
|
||||
do {
|
||||
c = Next();
|
||||
} while (!isalnum(c));
|
||||
return c;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
// Same as Read(), but using only printable chars and
|
||||
// with a terminating NUL
|
||||
void ReadString(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = NextChar();
|
||||
}
|
||||
*aBuf = 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(Next() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
MatchString(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(NextChar() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Check for terminating NUL character
|
||||
if (*aBuf)
|
||||
return PR_FALSE;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
Next();
|
||||
}
|
||||
|
||||
void
|
||||
SkipString(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
NextChar();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
static int gNumReaders = 0;
|
||||
static PRUint32 gTotalBytesRead = 0;
|
||||
static PRUint32 gTotalBytesWritten = 0;
|
||||
static PRUint32 gTotalDuration = 0;
|
||||
|
||||
class nsReader : public nsIStreamListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsReader()
|
||||
: mStartTime(0), mBytesRead(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
gNumReaders++;
|
||||
}
|
||||
|
||||
virtual ~nsReader() {
|
||||
delete mTestDataStream;
|
||||
gNumReaders--;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
|
||||
mTestDataStream = aRandomStream;
|
||||
mExpectedStreamLength = aExpectedStreamLength;
|
||||
mRefCnt = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStartRequest(nsIChannel* channel,
|
||||
nsISupports* context) {
|
||||
mStartTime = PR_IntervalNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aSourceOffset,
|
||||
PRUint32 aLength) {
|
||||
char buf[1025];
|
||||
while (aLength > 0) {
|
||||
PRUint32 amt;
|
||||
PRBool match;
|
||||
aIStream->Read(buf, sizeof buf, &amt);
|
||||
if (amt == 0) break;
|
||||
aLength -= amt;
|
||||
mBytesRead += amt;
|
||||
match = mTestDataStream->Match(buf, amt);
|
||||
NS_ASSERTION(match, "Stored data was corrupted on read");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStopRequest(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsresult aStatus,
|
||||
const PRUnichar* aMsg) {
|
||||
PRIntervalTime endTime;
|
||||
PRIntervalTime duration;
|
||||
|
||||
endTime = PR_IntervalNow();
|
||||
duration = (endTime - mStartTime);
|
||||
|
||||
if (NS_FAILED(aStatus)) printf("channel failed.\n");
|
||||
// printf("read %d bytes\n", mBytesRead);
|
||||
|
||||
//FIXME NS_ASSERTION(mBytesRead == mExpectedStreamLength,
|
||||
// "Stream in cache is wrong length");
|
||||
|
||||
gTotalBytesRead += mBytesRead;
|
||||
gTotalDuration += duration;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
PRIntervalTime mStartTime;
|
||||
PRUint32 mBytesRead;
|
||||
nsITestDataStream* mTestDataStream;
|
||||
PRUint32 mExpectedStreamLength;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
static nsIEventQueue* eventQueue;
|
||||
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
nsresult
|
||||
InitQueue() {
|
||||
nsresult rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
|
||||
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Process events until all streams are OnStopRequest'ed
|
||||
nsresult
|
||||
WaitForEvents() {
|
||||
while (gNumReaders) {
|
||||
eventQueue->ProcessPendingEvents();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read data for a single cache record and compare against testDataStream
|
||||
nsresult
|
||||
TestReadStream(nsICachedNetData *cacheEntry, nsITestDataStream *testDataStream,
|
||||
PRUint32 expectedStreamLength)
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv;
|
||||
PRUint32 actualContentLength;
|
||||
|
||||
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = cacheEntry->GetStoredContentLength(&actualContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
// FIXME NS_ASSERTION(actualContentLength == expectedStreamLength,
|
||||
// "nsICachedNetData::GetContentLength() busted ?");
|
||||
|
||||
nsReader *reader = new nsReader;
|
||||
reader->AddRef();
|
||||
rv = reader->Init(testDataStream, expectedStreamLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->AsyncRead(0, -1, 0, reader);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
reader->Release();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch
|
||||
static PRUint32
|
||||
convertPRTimeToSeconds(PRTime aTime64)
|
||||
{
|
||||
double fpTime;
|
||||
LL_L2D(fpTime, aTime64);
|
||||
return (PRUint32)(fpTime * 1e-6 + 0.5);
|
||||
}
|
||||
|
||||
// Convert unix-style time_t, i.e. seconds since the epoch, to PRTime
|
||||
static PRTime
|
||||
convertSecondsToPRTime(PRUint32 aSeconds)
|
||||
{
|
||||
PRInt64 t64;
|
||||
LL_L2I(t64, aSeconds);
|
||||
LL_MUL(t64, t64, 1000000);
|
||||
return t64;
|
||||
}
|
||||
|
||||
// Read the test data that was written in FillCache(), checking for
|
||||
// corruption, truncation.
|
||||
nsresult
|
||||
TestRead(nsINetDataCacheManager *aCache, PRUint32 aFlags)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsICachedNetData> cacheEntry;
|
||||
RandomStream *randomStream;
|
||||
char uriCacheKey[CACHE_KEY_LENGTH];
|
||||
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
|
||||
char *storedUriKey;
|
||||
PRUint32 testNum;
|
||||
|
||||
gTotalBytesRead = 0;
|
||||
gTotalDuration = 0;
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->ReadString(uriCacheKey, sizeof uriCacheKey - 1);
|
||||
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
|
||||
|
||||
// Ensure that entry is in the cache
|
||||
rv = aCache->Contains(uriCacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
|
||||
|
||||
rv = aCache->GetCachedNetData(uriCacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags,
|
||||
getter_AddRefs(cacheEntry));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
// Test GetUriSpec() method
|
||||
rv = cacheEntry->GetUriSpec(&storedUriKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
!memcmp(storedUriKey, &uriCacheKey[0], sizeof uriCacheKey),
|
||||
"nsICachedNetData::GetKey failed");
|
||||
nsAllocator::Free(storedUriKey);
|
||||
|
||||
// Test GetSecondaryKey() method
|
||||
PRUint32 storedSecondaryKeyLength;
|
||||
char* storedSecondaryKey;
|
||||
rv = cacheEntry->GetSecondaryKey(&storedSecondaryKeyLength, &storedSecondaryKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
!memcmp(storedSecondaryKey, &secondaryCacheKey[0],
|
||||
sizeof secondaryCacheKey),
|
||||
"nsICachedNetData::GetSecondaryKey failed");
|
||||
|
||||
// Compare against stored protocol data
|
||||
char *storedProtocolData;
|
||||
PRUint32 storedProtocolDataLength;
|
||||
rv = cacheEntry->GetAnnotation("test data", &storedProtocolDataLength, &storedProtocolData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
storedProtocolDataLength == CACHE_PROTOCOL_PRIVATE_LENGTH,
|
||||
"nsICachedNetData::GetAnnotation() failed");
|
||||
randomStream->Match(storedProtocolData, storedProtocolDataLength);
|
||||
|
||||
// Test GetAllowPartial()
|
||||
PRBool allowPartial;
|
||||
rv = cacheEntry->GetAllowPartial(&allowPartial);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
(allowPartial == (PRBool)(randomStream->Next() & 1)),
|
||||
"nsICachedNetData::GetAllowPartial() failed");
|
||||
|
||||
// Test GetExpirationTime()
|
||||
PRTime expirationTime;
|
||||
PRTime expectedExpirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
|
||||
rv = cacheEntry->GetExpirationTime(&expirationTime);
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && LL_EQ(expirationTime, expectedExpirationTime),
|
||||
"nsICachedNetData::GetExpirationTime() failed");
|
||||
|
||||
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
|
||||
TestReadStream(cacheEntry, randomStream, expectedStreamLength);
|
||||
}
|
||||
|
||||
WaitForEvents();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
|
||||
rate *= NUM_CACHE_ENTRIES;
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Read %7d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesRead, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create entries in the network data cache, using random data for the
|
||||
// key, the meta-data and the stored content data.
|
||||
nsresult
|
||||
FillCache(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsICachedNetData> cacheEntry;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
nsCOMPtr<nsINetDataCache> containingCache;
|
||||
char buf[1000];
|
||||
PRUint32 protocolDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char secondaryCacheKey[CACHE_SECONDARY_KEY_LENGTH];
|
||||
char protocolData[CACHE_PROTOCOL_PRIVATE_LENGTH];
|
||||
PRUint32 testNum;
|
||||
RandomStream *randomStream;
|
||||
|
||||
gTotalBytesWritten = 0;
|
||||
PRIntervalTime startTime = PR_IntervalNow();
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->ReadString(cacheKey, sizeof cacheKey - 1);
|
||||
randomStream->Read(secondaryCacheKey, sizeof secondaryCacheKey);
|
||||
|
||||
// No entry should be in cache until we add it
|
||||
rv = aCache->Contains(cacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(!inCache, "nsINetDataCacheManager::Contains error");
|
||||
|
||||
rv = aCache->GetCachedNetData(cacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags,
|
||||
getter_AddRefs(cacheEntry));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access cacheEntry via cache key");
|
||||
|
||||
// Test nsINetDataCacheManager::GetNumEntries()
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = aCache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
|
||||
|
||||
// Record meta-data should be initially empty
|
||||
char *protocolDatap;
|
||||
rv = cacheEntry->GetAnnotation("test data", &protocolDataLength, &protocolDatap);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
if ((protocolDataLength != 0) || (protocolDatap != 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Store random data as meta-data
|
||||
randomStream->Read(protocolData, sizeof protocolData);
|
||||
cacheEntry->SetAnnotation("test data", sizeof protocolData, protocolData);
|
||||
|
||||
// Store random data as allow-partial flag
|
||||
PRBool allowPartial = randomStream->Next() & 1;
|
||||
rv = cacheEntry->SetAllowPartial(allowPartial);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsICachedNetData::SetAllowPartial() failed");
|
||||
|
||||
// Store random data as expiration time
|
||||
PRTime expirationTime = convertSecondsToPRTime(randomStream->Next() & 0xffffff);
|
||||
rv = cacheEntry->SetExpirationTime(expirationTime);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsICachedNetData::SetExpirationTime() failed");
|
||||
|
||||
// Cache manager complains if expiration set without setting last-modified time
|
||||
rv = cacheEntry->SetLastModifiedTime(expirationTime);
|
||||
|
||||
rv = cacheEntry->NewChannel(0, 0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = cacheEntry->GetCache(getter_AddRefs(containingCache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
int remaining = streamLength;
|
||||
while (remaining) {
|
||||
PRUint32 numWritten;
|
||||
int amount = PR_MIN(sizeof buf, remaining);
|
||||
randomStream->Read(buf, amount);
|
||||
|
||||
rv = outStream->Write(buf, amount, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
|
||||
|
||||
remaining -= amount;
|
||||
|
||||
PRUint32 storageInUse;
|
||||
rv = containingCache->GetStorageInUse(&storageInUse);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (storageInUse <= aCacheCapacity),
|
||||
"Cache manager failed to limit cache growth");
|
||||
}
|
||||
outStream->Close();
|
||||
gTotalBytesWritten += streamLength;
|
||||
|
||||
// *Now* there should be an entry in the cache
|
||||
rv = aCache->Contains(cacheKey,
|
||||
secondaryCacheKey, sizeof secondaryCacheKey,
|
||||
aFlags, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCacheManager::Contains error");
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesWritten, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_AutoregisterComponents()
|
||||
{
|
||||
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
NULL /* default */);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Test(nsINetDataCacheManager *aCache, PRUint32 aFlags, PRUint32 aCacheCapacity)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aCache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = aCache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
rv = FillCache(aCache, aFlags, aCacheCapacity);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
|
||||
|
||||
rv = TestRead(aCache, aFlags);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
|
||||
|
||||
rv = aCache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
rv = aCache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheManager> cache;
|
||||
|
||||
rv = NS_AutoregisterComponents();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
|
||||
|
||||
rv = nsComponentManager::CreateInstance(NS_NETWORK_CACHE_MANAGER_PROGID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsINetDataCacheManager),
|
||||
getter_AddRefs(cache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create cache manager factory") ;
|
||||
|
||||
cache->SetDiskCacheCapacity(DISK_CACHE_CAPACITY);
|
||||
cache->SetMemCacheCapacity(MEM_CACHE_CAPACITY);
|
||||
|
||||
InitQueue();
|
||||
|
||||
Test(cache, nsINetDataCacheManager::BYPASS_PERSISTENT_CACHE, MEM_CACHE_CAPACITY);
|
||||
Test(cache, nsINetDataCacheManager::BYPASS_MEMORY_CACHE, DISK_CACHE_CAPACITY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,820 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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.
|
||||
*/
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIStreamObserver.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nsINetDataCache.h"
|
||||
#include "nsINetDataDiskCache.h"
|
||||
#include "nsINetDataCacheRecord.h"
|
||||
#include "nsMemCacheCID.h"
|
||||
// file cache include
|
||||
#include "nsNetDiskCacheCID.h"
|
||||
#include "nsIPref.h"
|
||||
#include "prenv.h"
|
||||
#include "nsIFileStream.h"
|
||||
|
||||
|
||||
// Number of test entries to be placed in the cache
|
||||
#define NUM_CACHE_ENTRIES 250
|
||||
|
||||
// Cache content stream length will have random length between zero and
|
||||
// MAX_CONTENT_LENGTH bytes
|
||||
#define MAX_CONTENT_LENGTH 20000
|
||||
|
||||
// Length of random-data cache entry key
|
||||
#define CACHE_KEY_LENGTH 15
|
||||
|
||||
// Length of random-data cache entry meta-data
|
||||
#define CACHE_METADATA_LENGTH 100
|
||||
|
||||
static NS_DEFINE_CID(kMemCacheCID, NS_MEM_CACHE_FACTORY_CID);
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
|
||||
// file cache cid
|
||||
static NS_DEFINE_CID(kDiskCacheCID, NS_NETDISKCACHE_CID) ;
|
||||
static NS_DEFINE_CID(kPrefCID, NS_PREF_CID);
|
||||
static NS_DEFINE_IID(kIPrefIID, NS_IPREF_IID);
|
||||
|
||||
// Mapping from test case number to RecordID
|
||||
static PRInt32 recordID[NUM_CACHE_ENTRIES];
|
||||
|
||||
static PRInt32
|
||||
mapRecordIdToTestNum(PRInt32 aRecordID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NUM_CACHE_ENTRIES; i++) {
|
||||
if (recordID[i] == aRecordID)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// A supply of stream data to either store or compare with
|
||||
class nsITestDataStream {
|
||||
public:
|
||||
virtual ~nsITestDataStream() {};
|
||||
virtual PRUint32 Next() = 0;
|
||||
virtual void Read(char* aBuf, PRUint32 aCount) = 0;
|
||||
|
||||
virtual PRBool Match(char* aBuf, PRUint32 aCount) = 0;
|
||||
virtual void Skip(PRUint32 aCount) = 0;
|
||||
};
|
||||
|
||||
// A reproducible stream of random data.
|
||||
class RandomStream : public nsITestDataStream {
|
||||
public:
|
||||
RandomStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState = 1103515245 * mState + 12345;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)(Next() & 0xff))
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
while (aCount--)
|
||||
Next();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
// A stream of data that increments on each byte that is read, modulo 256
|
||||
class CounterStream : public nsITestDataStream {
|
||||
public:
|
||||
CounterStream(PRUint32 aSeed) {
|
||||
mStartSeed = mState = aSeed;
|
||||
}
|
||||
|
||||
PRUint32 GetStartSeed() {
|
||||
return mStartSeed;
|
||||
}
|
||||
|
||||
PRUint32 Next() {
|
||||
mState += 1;
|
||||
mState &= 0xff;
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Read(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
*aBuf++ = Next();
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
Match(char* aBuf, PRUint32 aCount) {
|
||||
PRUint32 i;
|
||||
for (i = 0; i < aCount; i++) {
|
||||
if (*aBuf++ != (char)Next())
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Skip(PRUint32 aCount) {
|
||||
mState += aCount;
|
||||
mState &= 0xff;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
PRUint32 mState;
|
||||
PRUint32 mStartSeed;
|
||||
};
|
||||
|
||||
static int gNumReaders = 0;
|
||||
static PRUint32 gTotalBytesRead = 0;
|
||||
static PRUint32 gTotalDuration = 0;
|
||||
|
||||
class nsReader : public nsIStreamListener {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsReader()
|
||||
: mStartTime(0), mBytesRead(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
gNumReaders++;
|
||||
}
|
||||
|
||||
virtual ~nsReader() {
|
||||
delete mTestDataStream;
|
||||
gNumReaders--;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init(nsITestDataStream* aRandomStream, PRUint32 aExpectedStreamLength) {
|
||||
mTestDataStream = aRandomStream;
|
||||
mExpectedStreamLength = aExpectedStreamLength;
|
||||
mRefCnt = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStartRequest(nsIChannel* channel,
|
||||
nsISupports* context) {
|
||||
mStartTime = PR_IntervalNow();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnDataAvailable(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsIInputStream *aIStream,
|
||||
PRUint32 aSourceOffset,
|
||||
PRUint32 aLength) {
|
||||
char buf[1025];
|
||||
while (aLength > 0) {
|
||||
PRUint32 amt;
|
||||
PRBool match;
|
||||
aIStream->Read(buf, sizeof buf, &amt);
|
||||
if (amt == 0) break;
|
||||
aLength -= amt;
|
||||
mBytesRead += amt;
|
||||
match = mTestDataStream->Match(buf, amt);
|
||||
NS_ASSERTION(match, "Stored data was corrupted on read");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnStopRequest(nsIChannel* channel,
|
||||
nsISupports* context,
|
||||
nsresult aStatus,
|
||||
const PRUnichar* aMsg) {
|
||||
PRIntervalTime endTime;
|
||||
PRIntervalTime duration;
|
||||
|
||||
endTime = PR_IntervalNow();
|
||||
duration = (endTime - mStartTime);
|
||||
|
||||
if (NS_FAILED(aStatus)) printf("channel failed.\n");
|
||||
// printf("read %d bytes\n", mBytesRead);
|
||||
|
||||
NS_ASSERTION(mBytesRead == mExpectedStreamLength,
|
||||
"Stream in cache is wrong length");
|
||||
|
||||
gTotalBytesRead += mBytesRead;
|
||||
gTotalDuration += duration;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
PRIntervalTime mStartTime;
|
||||
PRUint32 mBytesRead;
|
||||
nsITestDataStream* mTestDataStream;
|
||||
PRUint32 mExpectedStreamLength;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsReader, nsIStreamListener, nsIStreamObserver)
|
||||
|
||||
static nsIEventQueue* eventQueue;
|
||||
|
||||
nsresult
|
||||
InitQueue() {
|
||||
nsresult rv;
|
||||
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue service");
|
||||
|
||||
rv = eventQService->CreateThreadEventQueue();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create event queue");
|
||||
|
||||
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), &eventQueue);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get event queue for main thread");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Process events until all streams are OnStopRequest'ed
|
||||
nsresult
|
||||
WaitForEvents() {
|
||||
while (gNumReaders) {
|
||||
eventQueue->ProcessPendingEvents();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read data for a single cache record and compare against testDataStream
|
||||
nsresult
|
||||
TestReadStream(nsINetDataCacheRecord *record, nsITestDataStream *testDataStream,
|
||||
PRUint32 expectedStreamLength)
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv;
|
||||
PRUint32 actualContentLength;
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = record->GetStoredContentLength(&actualContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(actualContentLength == expectedStreamLength,
|
||||
"nsINetDataCacheRecord::GetContentLength() busted ?");
|
||||
|
||||
nsReader *reader = new nsReader;
|
||||
rv = reader->Init(testDataStream, expectedStreamLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->AsyncRead(0, -1, 0, reader);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
reader->Release();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that records can be retrieved using their record-ID, in addition
|
||||
// to using the opaque key.
|
||||
nsresult
|
||||
TestRecordID(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetDataByID(recordID[testNum], getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't obtain record using record ID");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
|
||||
nsAllocator::Free(metaData);
|
||||
delete randomStream;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check that all cache entries in the database are enumerated and that
|
||||
// no duplicates appear.
|
||||
nsresult
|
||||
TestEnumeration(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsISupports> tempISupports;
|
||||
nsCOMPtr<nsISimpleEnumerator> iterator;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData;
|
||||
PRUint32 testNum;
|
||||
PRBool match;
|
||||
PRInt32 recID;
|
||||
|
||||
int numRecords = 0;
|
||||
|
||||
// Iterate over all records in the cache
|
||||
rv = cache->NewCacheEntryIterator(getter_AddRefs(iterator));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create new cache entry iterator");
|
||||
|
||||
PRBool notDone;
|
||||
while (1) {
|
||||
|
||||
// Done iterating ?
|
||||
rv = iterator->HasMoreElements(¬Done);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (!notDone)
|
||||
break;
|
||||
|
||||
// Get next record in iteration
|
||||
rv = iterator->GetNext(getter_AddRefs(tempISupports));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "iterator bustage");
|
||||
record = do_QueryInterface(tempISupports);
|
||||
|
||||
numRecords++;
|
||||
|
||||
// Get record ID
|
||||
rv = record->GetRecordID(&recID);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
testNum = mapRecordIdToTestNum(recID);
|
||||
NS_ASSERTION(testNum != -1, "Corrupted Record ID ?");
|
||||
|
||||
// Erase mapping from table, so that duplicate enumerations are detected
|
||||
recordID[testNum] = -1;
|
||||
|
||||
// Make sure stream matches test data
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Match against previously stored meta-data
|
||||
rv = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get record meta-data");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
NS_ASSERTION(numRecords == NUM_CACHE_ENTRIES, "Iteration bug");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Read the test data that was written in FillCache(), checking for
|
||||
// corruption, truncation.
|
||||
nsresult
|
||||
TestRead(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char *metaData, *storedCacheKey;
|
||||
PRUint32 testNum, storedCacheKeyLength;
|
||||
PRBool match;
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// Ensure that entry is in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
// Match against previously stored meta-data
|
||||
match = record->GetMetaData(&metaDataLength, &metaData);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
match = randomStream->Match(metaData, metaDataLength);
|
||||
NS_ASSERTION(match, "Meta-data corrupted or incorrect");
|
||||
nsAllocator::Free(metaData);
|
||||
|
||||
// Test GetKey() method
|
||||
rv = record->GetKey(&storedCacheKeyLength, &storedCacheKey);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) &&
|
||||
(storedCacheKeyLength == sizeof cacheKey) &&
|
||||
!memcmp(storedCacheKey, &cacheKey[0], sizeof cacheKey),
|
||||
"nsINetDataCacheRecord::GetKey failed");
|
||||
nsAllocator::Free(storedCacheKey);
|
||||
|
||||
PRUint32 expectedStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
}
|
||||
|
||||
WaitForEvents();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = gTotalBytesRead / PR_IntervalToMilliseconds(gTotalDuration);
|
||||
rate *= NUM_CACHE_ENTRIES;
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Read %d bytes at a rate of %5.1f MB per second \n",
|
||||
gTotalBytesRead, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Repeatedly call SetStoredContentLength() on a cache entry and make
|
||||
// read the stream's data to ensure that it's not corrupted by the effect
|
||||
nsresult
|
||||
TestTruncation(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
RandomStream *randomStream;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
randomStream->Skip(CACHE_METADATA_LENGTH);
|
||||
PRUint32 initialStreamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
delete randomStream;
|
||||
|
||||
PRUint32 i;
|
||||
PRUint32 delta = initialStreamLength / 64;
|
||||
for (i = initialStreamLength; i >= delta; i -= delta) {
|
||||
PRUint32 expectedStreamLength = i;
|
||||
|
||||
// Do the truncation
|
||||
record->SetStoredContentLength(expectedStreamLength);
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Skip(CACHE_KEY_LENGTH + CACHE_METADATA_LENGTH + 1);
|
||||
|
||||
PRUint32 afterContentLength;
|
||||
rv = record->GetStoredContentLength(&afterContentLength);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
NS_ASSERTION(afterContentLength == expectedStreamLength,
|
||||
"nsINetDataCacheRecord::SetContentLength() failed to truncate record");
|
||||
|
||||
TestReadStream(record, randomStream, expectedStreamLength);
|
||||
WaitForEvents();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Write known data to random offsets in a single cache entry and test
|
||||
// resulting stream for correctness.
|
||||
nsresult
|
||||
TestOffsetWrites(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[512];
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
RandomStream *randomStream;
|
||||
|
||||
randomStream = new RandomStream(0);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
|
||||
// Write buffer-fulls of data at random offsets into the cache entry.
|
||||
// Data written is (offset % 0xff)
|
||||
PRUint32 startingOffset;
|
||||
PRUint32 streamLength = 0;
|
||||
CounterStream *counterStream;
|
||||
int i;
|
||||
for (i = 0; i < 100; i++) {
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
startingOffset = streamLength ? streamLength - (randomStream->Next() % sizeof buf): 0;
|
||||
rv = channel->OpenOutputStream(startingOffset, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
counterStream = new CounterStream(startingOffset);
|
||||
counterStream->Read(buf, sizeof buf);
|
||||
|
||||
PRUint32 numWritten;
|
||||
rv = outStream->Write(buf, sizeof buf, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == sizeof buf, "Write() bug?");
|
||||
streamLength = startingOffset + sizeof buf;
|
||||
|
||||
rv = outStream->Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't close channel");
|
||||
delete counterStream;
|
||||
}
|
||||
|
||||
delete randomStream;
|
||||
|
||||
counterStream = new CounterStream(0);
|
||||
TestReadStream(record, counterStream, streamLength);
|
||||
WaitForEvents();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Create entries in the network data cache, using random data for the
|
||||
// key, the meta-data and the stored content data.
|
||||
nsresult
|
||||
FillCache(nsINetDataCache *cache)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool inCache;
|
||||
nsCOMPtr<nsINetDataCacheRecord> record;
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
char buf[1000];
|
||||
PRUint32 metaDataLength;
|
||||
char cacheKey[CACHE_KEY_LENGTH];
|
||||
char metaData[CACHE_METADATA_LENGTH];
|
||||
PRUint32 testNum;
|
||||
char *data;
|
||||
RandomStream *randomStream;
|
||||
PRUint32 totalBytesWritten = 0;
|
||||
|
||||
PRIntervalTime startTime = PR_IntervalNow();
|
||||
|
||||
for (testNum = 0; testNum < NUM_CACHE_ENTRIES; testNum++) {
|
||||
randomStream = new RandomStream(testNum);
|
||||
randomStream->Read(cacheKey, sizeof cacheKey);
|
||||
|
||||
// No entry should be in cache until we add it
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(!inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
rv = cache->GetCachedNetData(cacheKey, sizeof cacheKey, getter_AddRefs(record));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't access record via opaque cache key");
|
||||
|
||||
// Test nsINetDataCacheRecord::GetRecordID()
|
||||
rv = record->GetRecordID(&recordID[testNum]);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get Record ID");
|
||||
|
||||
// Test nsINetDataCache::GetNumEntries()
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == testNum + 1, "GetNumEntries failure");
|
||||
|
||||
// Record meta-data should be initially empty
|
||||
rv = record->GetMetaData(&metaDataLength, &data);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
if ((metaDataLength != 0) || (data != 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Store random data as meta-data
|
||||
randomStream->Read(metaData, sizeof metaData);
|
||||
record->SetMetaData(sizeof metaData, metaData);
|
||||
|
||||
rv = record->NewChannel(0, getter_AddRefs(channel));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
rv = channel->OpenOutputStream(0, getter_AddRefs(outStream));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
|
||||
PRUint32 beforeOccupancy;
|
||||
rv = cache->GetStorageInUse(&beforeOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
int streamLength = randomStream->Next() % MAX_CONTENT_LENGTH;
|
||||
int remaining = streamLength;
|
||||
while (remaining) {
|
||||
PRUint32 numWritten;
|
||||
int amount = PR_MIN(sizeof buf, remaining);
|
||||
randomStream->Read(buf, amount);
|
||||
|
||||
rv = outStream->Write(buf, amount, &numWritten);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(numWritten == (PRUint32)amount, "Write() bug?");
|
||||
|
||||
remaining -= amount;
|
||||
}
|
||||
outStream->Close();
|
||||
totalBytesWritten += streamLength;
|
||||
|
||||
PRUint32 afterOccupancy;
|
||||
rv = cache->GetStorageInUse(&afterOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
PRUint32 streamLengthInKB = streamLength >> 10;
|
||||
NS_ASSERTION((afterOccupancy - beforeOccupancy) >= streamLengthInKB,
|
||||
"nsINetDataCache::GetStorageInUse() is busted");
|
||||
|
||||
|
||||
// *Now* there should be an entry in the cache
|
||||
rv = cache->Contains(cacheKey, sizeof cacheKey, &inCache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), " ");
|
||||
NS_ASSERTION(inCache, "nsINetDataCache::Contains error");
|
||||
|
||||
delete randomStream;
|
||||
}
|
||||
|
||||
PRIntervalTime endTime = PR_IntervalNow();
|
||||
|
||||
// Compute rate in MB/s
|
||||
double rate = totalBytesWritten / PR_IntervalToMilliseconds(endTime - startTime);
|
||||
rate *= 1000;
|
||||
rate /= (1024 * 1024);
|
||||
printf("Wrote %7d bytes at a rate of %5.1f MB per second \n",
|
||||
totalBytesWritten, rate);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult NS_AutoregisterComponents()
|
||||
{
|
||||
nsresult rv = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup,
|
||||
NULL /* default */);
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRBool initPref ()
|
||||
{
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIPref, prefPtr, kPrefCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCOMPtr<nsIFileSpec> fileSpec;
|
||||
rv = NS_NewFileSpec (getter_AddRefs(fileSpec));
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
nsCString defaultPrefFile = PR_GetEnv ("MOZILLA_FIVE_HOME");
|
||||
if (defaultPrefFile.Length())
|
||||
defaultPrefFile += "/";
|
||||
else
|
||||
defaultPrefFile = "./";
|
||||
defaultPrefFile += "default_prefs.js";
|
||||
|
||||
fileSpec->SetUnixStyleFilePath (defaultPrefFile.GetBuffer());
|
||||
|
||||
PRBool exists = false;
|
||||
fileSpec->Exists(&exists);
|
||||
if (exists)
|
||||
prefPtr->ReadUserPrefsFrom(fileSpec);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if(argc <2) {
|
||||
printf(" %s -f to test filecache\n", argv[0]) ;
|
||||
printf(" %s -m to test memcache\n", argv[0]) ;
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
|
||||
rv = NS_AutoregisterComponents();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't register XPCOM components");
|
||||
|
||||
nsCOMPtr<nsINetDataCache> cache;
|
||||
|
||||
if (PL_strcasecmp(argv[1], "-m") == 0) {
|
||||
rv = nsComponentManager::CreateInstance(kMemCacheCID, nsnull,
|
||||
NS_GET_IID(nsINetDataCache),
|
||||
getter_AddRefs(cache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create memory cache factory");
|
||||
} else if (PL_strcasecmp(argv[1], "-f") == 0) {
|
||||
|
||||
nsCOMPtr<nsINetDataDiskCache> diskcache ;
|
||||
|
||||
rv = nsComponentManager::CreateInstance(kDiskCacheCID, nsnull,
|
||||
NS_GET_IID(nsINetDataDiskCache),
|
||||
getter_AddRefs(diskcache));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't create disk cache factory") ;
|
||||
|
||||
nsCOMPtr<nsIFileSpec> folder ;
|
||||
NS_NewFileSpec(getter_AddRefs(folder)) ;
|
||||
folder->SetUnixStyleFilePath("/tmp") ;
|
||||
diskcache->SetDiskCacheFolder(folder) ;
|
||||
|
||||
cache = diskcache ;
|
||||
|
||||
} else {
|
||||
printf(" %s -f to test filecache\n", argv[0]) ;
|
||||
printf(" %s -m to test memcache\n", argv[0]) ;
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
InitQueue();
|
||||
|
||||
PRUnichar* description;
|
||||
rv = cache->GetDescription(&description);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache description");
|
||||
nsCAutoString descStr(description);
|
||||
printf("Testing: %s\n", descStr.GetBuffer());
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
|
||||
PRUint32 startOccupancy;
|
||||
rv = cache->GetStorageInUse(&startOccupancy);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
PRUint32 numEntries = (PRUint32)-1;
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
rv = FillCache(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't fill cache with random test data");
|
||||
|
||||
rv = TestRead(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't read random test data from cache");
|
||||
|
||||
rv = TestRecordID(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't index records using record ID");
|
||||
|
||||
rv = TestEnumeration(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully enumerate records");
|
||||
|
||||
rv = TestTruncation(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully truncate records");
|
||||
|
||||
rv = TestOffsetWrites(cache);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't successfully write to records using non-zero offsets");
|
||||
|
||||
rv = cache->RemoveAll();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't clear cache");
|
||||
rv = cache->GetNumEntries(&numEntries);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get number of cache entries");
|
||||
NS_ASSERTION(numEntries == 0, "Couldn't clear cache");
|
||||
|
||||
PRUint32 endOccupancy;
|
||||
rv = cache->GetStorageInUse(&endOccupancy);
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't get cache occupancy");
|
||||
|
||||
NS_ASSERTION(startOccupancy == endOccupancy, "Cache occupancy not correctly computed ?");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
DEPTH=..\..
|
||||
|
||||
MAKE_OBJ_TYPE = EXE
|
||||
PROG1 = .\$(OBJDIR)\TestFileInput.exe
|
||||
PROG2 = .\$(OBJDIR)\TestSocketInput.exe
|
||||
PROG3 = .\$(OBJDIR)\TestSocketIO.exe
|
||||
PROG4 = .\$(OBJDIR)\TestProtocols.exe
|
||||
PROG5 = .\$(OBJDIR)\TestSocketTransport.exe
|
||||
PROG6 = .\$(OBJDIR)\urltest.exe
|
||||
PROG7 = .\$(OBJDIR)\TestFileInput2.exe
|
||||
PROG8 = .\$(OBJDIR)\TestFileTransport.exe
|
||||
PROG9 = .\$(OBJDIR)\TestRes.exe
|
||||
PROGA = .\$(OBJDIR)\TestRawCache.exe
|
||||
PROGB = .\$(OBJDIR)\TestCacheMgr.exe
|
||||
PROGRAMS = \
|
||||
#$(PROG1) $(PROG2) $(PROG3) $(PROG4) $(PROG5) $(PROG6) $(PROG7) $(PROG8) $(PROG9)\
|
||||
$(PROGA) $(PROGB)
|
||||
|
||||
LCFLAGS=-DUSE_NSREG -GX
|
||||
|
||||
REQUIRES=libreg
|
||||
|
||||
INCS = $(INCS) \
|
||||
-I$(DEPTH)\dist\include \
|
||||
$(NULL)
|
||||
|
||||
LLIBS= \
|
||||
$(DIST)\lib\xpcom.lib \
|
||||
$(LIBNSPR) \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(PROGRAMS)
|
||||
-for %p in ($(PROGRAMS)) do $(MAKE_INSTALL) %p $(DIST)\bin
|
||||
|
||||
clobber::
|
||||
-for %p in ($(PROGRAMS)) do $(RM) %p $(DIST)\bin\%p
|
||||
|
||||
$(PROG1): $(OBJDIR) TestFileInput.cpp
|
||||
|
||||
$(PROG2): $(OBJDIR) TestSocketInput.cpp
|
||||
|
||||
$(PROG3): $(OBJDIR) TestSocketIO.cpp
|
||||
|
||||
$(PROG4): $(OBJDIR) TestProtocols.cpp
|
||||
|
||||
$(PROG5): $(OBJDIR) TestSocketTransport.cpp
|
||||
|
||||
$(PROG6): $(OBJDIR) urltest.cpp
|
||||
|
||||
$(PROG7): $(OBJDIR) TestFileInput2.cpp
|
||||
|
||||
$(PROG8): $(OBJDIR) TestFileTransport.cpp
|
||||
|
||||
$(PROG9): $(OBJDIR) TestRes.cpp
|
||||
|
||||
$(PROGA): $(OBJDIR) TestRawCache.cpp
|
||||
|
||||
$(PROGB): $(OBJDIR) TestCacheMgr.cpp
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,226 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsError_h
|
||||
#define nsError_h
|
||||
|
||||
#ifndef prtypes_h___
|
||||
#include "prtypes.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Generic result data type
|
||||
*/
|
||||
|
||||
typedef PRUint32 nsresult;
|
||||
|
||||
/*
|
||||
* To add error code to your module, you need to do the following:
|
||||
*
|
||||
* 1) Add a module offset code. Add yours to the bottom of the list
|
||||
* right below this comment, adding 1.
|
||||
*
|
||||
* 2) In your module, define a header file which uses one of the
|
||||
* NE_ERROR_GENERATExxxxxx macros. Some examples below:
|
||||
*
|
||||
* #define NS_ERROR_MYMODULE_MYERROR1 NS_ERROR_GENERATE(NS_ERROR_SEVERITY_ERROR,NS_ERROR_MODULE_MYMODULE,1)
|
||||
* #define NS_ERROR_MYMODULE_MYERROR2 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_MYMODULE,2)
|
||||
* #define NS_ERROR_MYMODULE_MYERROR3 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_MYMODULE,3)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @name Standard Module Offset Code. Each Module should identify a unique number
|
||||
* and then all errors associated with that module become offsets from the
|
||||
* base associated with that module id. There are 16 bits of code bits for
|
||||
* each module.
|
||||
*/
|
||||
|
||||
#define NS_ERROR_MODULE_XPCOM 1
|
||||
#define NS_ERROR_MODULE_BASE 2
|
||||
#define NS_ERROR_MODULE_GFX 3
|
||||
#define NS_ERROR_MODULE_WIDGET 4
|
||||
#define NS_ERROR_MODULE_CALENDAR 5
|
||||
#define NS_ERROR_MODULE_NETWORK 6
|
||||
#define NS_ERROR_MODULE_PLUGINS 7
|
||||
#define NS_ERROR_MODULE_LAYOUT 8
|
||||
#define NS_ERROR_MODULE_HTMLPARSER 9
|
||||
#define NS_ERROR_MODULE_RDF 10
|
||||
#define NS_ERROR_MODULE_UCONV 11
|
||||
#define NS_ERROR_MODULE_REG 12
|
||||
#define NS_ERROR_MODULE_FILES 13
|
||||
#define NS_ERROR_MODULE_DOM 14
|
||||
#define NS_ERROR_MODULE_IMGLIB 15
|
||||
#define NS_ERROR_MODULE_MAILNEWS 16
|
||||
#define NS_ERROR_MODULE_EDITOR 17
|
||||
#define NS_ERROR_MODULE_XPCONNECT 18
|
||||
|
||||
/**
|
||||
* @name Standard Error Handling Macros
|
||||
*/
|
||||
|
||||
#define NS_FAILED(_nsresult) ((_nsresult) & 0x80000000)
|
||||
#define NS_SUCCEEDED(_nsresult) (!((_nsresult) & 0x80000000))
|
||||
|
||||
/**
|
||||
* @name Severity Code. This flag identifies the level of warning
|
||||
*/
|
||||
|
||||
#define NS_ERROR_SEVERITY_SUCCESS 0
|
||||
#define NS_ERROR_SEVERITY_ERROR 1
|
||||
|
||||
/**
|
||||
* @name Mozilla Code. This flag separates consumers of mozilla code
|
||||
* from the native platform
|
||||
*/
|
||||
|
||||
#define NS_ERROR_MODULE_BASE_OFFSET 0x45
|
||||
|
||||
/**
|
||||
* @name Standard Error Generating Macros
|
||||
*/
|
||||
|
||||
#define NS_ERROR_GENERATE(sev,module,code) \
|
||||
((nsresult) (((PRUint32)(sev)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
|
||||
|
||||
#define NS_ERROR_GENERATE_SUCCESS(module,code) \
|
||||
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_SUCCESS)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
|
||||
|
||||
#define NS_ERROR_GENERATE_FAILURE(module,code) \
|
||||
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_ERROR)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
|
||||
|
||||
/**
|
||||
* @name Standard Macros for retrieving error bits
|
||||
*/
|
||||
|
||||
#define NS_ERROR_GET_CODE(err) ((err) & 0xffff)
|
||||
#define NS_ERROR_GET_MODULE(err) (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff))
|
||||
#define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1)
|
||||
|
||||
/**
|
||||
* @name Standard return values
|
||||
*/
|
||||
|
||||
/*@{*/
|
||||
|
||||
/* Standard "it worked" return value */
|
||||
#define NS_OK 0
|
||||
|
||||
/* The backwards COM false */
|
||||
#define NS_COMFALSE 1
|
||||
|
||||
#define NS_ERROR_BASE ((nsresult) 0xC1F30000)
|
||||
|
||||
/* Returned when an instance is not initialized */
|
||||
#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1)
|
||||
|
||||
/* Returned when an instance is already initialized */
|
||||
#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2)
|
||||
|
||||
/* Returned by a not implemented function */
|
||||
#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L)
|
||||
|
||||
/* Returned when a given interface is not supported. */
|
||||
#define NS_NOINTERFACE ((nsresult) 0x80004002L)
|
||||
#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE
|
||||
|
||||
#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L)
|
||||
#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER
|
||||
|
||||
/* Returned when a function aborts */
|
||||
#define NS_ERROR_ABORT ((nsresult) 0x80004004L)
|
||||
|
||||
/* Returned when a function fails */
|
||||
#define NS_ERROR_FAILURE ((nsresult) 0x80004005L)
|
||||
|
||||
/* Returned when an unexpected error occurs */
|
||||
#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL)
|
||||
|
||||
/* Returned when a memory allocation failes */
|
||||
#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL)
|
||||
|
||||
/* Returned when an illegal value is passed */
|
||||
#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L)
|
||||
#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE
|
||||
|
||||
/* Returned when a class doesn't allow aggregation */
|
||||
#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L)
|
||||
|
||||
/* Returned when an operation can't complete due to an unavailable resource */
|
||||
#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L)
|
||||
|
||||
/* Returned when a class is not registered */
|
||||
#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L)
|
||||
|
||||
/* Returned when a class cannot be registered, but may be tried again later */
|
||||
#define NS_ERROR_FACTORY_REGISTER_AGAIN ((nsresult) 0x80040155L)
|
||||
|
||||
/* Returned when a dynamically loaded factory couldn't be found */
|
||||
#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L)
|
||||
|
||||
/* Returned when a factory doesn't support signatures */
|
||||
#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \
|
||||
(NS_ERROR_BASE + 0x101)
|
||||
|
||||
/* Returned when a factory already is registered */
|
||||
#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100)
|
||||
|
||||
|
||||
/* For COM compatibility reasons, we want to use exact error code numbers
|
||||
for NS_ERROR_PROXY_INVALID_IN_PARAMETER and NS_ERROR_PROXY_INVALID_OUT_PARAMETER.
|
||||
The first matches:
|
||||
|
||||
#define RPC_E_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80010010L)
|
||||
|
||||
Errors returning this mean that the xpcom proxy code could not create a proxy for
|
||||
one of the in paramaters.
|
||||
|
||||
Because of this, we are ignoring the convention if using a base and offset for
|
||||
error numbers.
|
||||
|
||||
*/
|
||||
|
||||
/* Returned when a proxy could not be create a proxy for one of the IN parameters
|
||||
This is returned only when the "real" meathod has NOT been invoked.
|
||||
*/
|
||||
|
||||
#define NS_ERROR_PROXY_INVALID_IN_PARAMETER ((nsresult) 0x80010010L)
|
||||
|
||||
/* Returned when a proxy could not be create a proxy for one of the OUT parameters
|
||||
This is returned only when the "real" meathod has ALREADY been invoked.
|
||||
*/
|
||||
|
||||
#define NS_ERROR_PROXY_INVALID_OUT_PARAMETER ((nsresult) 0x80010011L)
|
||||
|
||||
|
||||
/*@}*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef XP_PC
|
||||
#pragma warning(disable: 4251) // 'nsCOMPtr<class nsIInputStream>' needs to have dll-interface to be used by clients of class 'nsInputStream'
|
||||
#pragma warning(disable: 4275) // non dll-interface class 'nsISupports' used as base for dll-interface class 'nsIRDFNode'
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape 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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
// Force references to all of the symbols that we want exported from
|
||||
// the dll that are located in the .lib files we link with
|
||||
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsFileSpec.h"
|
||||
//#include "nsIBuffer.h"
|
||||
//#include "nsIByteBufferInputStream.h"
|
||||
#include "nsFileStream.h"
|
||||
#include "nsFileSpecStreaming.h"
|
||||
#include "nsSpecialSystemDirectory.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsObserver.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "nsIEnumerator.h"
|
||||
#include "nsEnumeratorUtils.h"
|
||||
#include "nsQuickSort.h"
|
||||
#include "nsString2.h"
|
||||
#include "nsProxyEventPrivate.h"
|
||||
#include "xpt_xdr.h"
|
||||
#include "nsInterfaceInfo.h"
|
||||
#include "xptcall.h"
|
||||
#include "nsIFileSpec.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsAVLTree.h"
|
||||
#include "nsHashtableEnumerator.h"
|
||||
#include "nsPipe2.h"
|
||||
#include "nsCWeakReference.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsISizeOfHandler.h"
|
||||
#include "nsTextFormater.h"
|
||||
#include "nsStorageStream.h"
|
||||
#include "nsIBinaryInputStream.h"
|
||||
#ifdef DEBUG
|
||||
#include "pure.h"
|
||||
#endif
|
||||
|
||||
class dummyComparitor: public nsAVLNodeComparitor {
|
||||
public:
|
||||
virtual PRInt32 operator()(void* anItem1,void* anItem2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
extern NS_COM void
|
||||
TestSegmentedBuffer();
|
||||
#endif
|
||||
|
||||
void XXXNeverCalled()
|
||||
{
|
||||
nsTextFormater::snprintf(nsnull,0,nsnull);
|
||||
dummyComparitor dummy;
|
||||
nsVoidArray();
|
||||
nsAVLTree(dummy, nsnull);
|
||||
NS_GetNumberOfAtoms();
|
||||
nsFileURL(NULL);
|
||||
// NS_NewPipe(NULL, NULL, 0, 0, 0, NULL);
|
||||
NS_NewPipe(NULL, NULL, NULL, 0, 0);
|
||||
nsFileSpec s;
|
||||
NS_NewIOFileStream(NULL, s, 0, 0);
|
||||
nsInputFileStream(s, 0, 0);
|
||||
nsPersistentFileDescriptor d;
|
||||
ReadDescriptor(NULL, d);
|
||||
new nsSpecialSystemDirectory(nsSpecialSystemDirectory::OS_DriveDirectory);
|
||||
nsIThread::GetCurrent(NULL);
|
||||
nsDeque(NULL);
|
||||
NS_NewObserver(NULL, NULL);
|
||||
nsTraceRefcnt::DumpStatistics();
|
||||
nsXPIDLCString::Copy(NULL);
|
||||
NS_NewEmptyEnumerator(NULL);
|
||||
nsArrayEnumerator(NULL);
|
||||
NS_NewIntersectionEnumerator(NULL, NULL, NULL);
|
||||
NS_QuickSort(NULL, 0, 0, NULL, NULL);
|
||||
nsString2();
|
||||
nsProxyObject(NULL, 0, NULL);
|
||||
XPT_DoString(NULL, NULL);
|
||||
XPT_DoHeader(NULL, NULL);
|
||||
nsInterfaceInfo* info = NULL;
|
||||
info->GetName(NULL);
|
||||
#ifdef DEBUG
|
||||
info->print(NULL);
|
||||
PurePrintf(0);
|
||||
#endif
|
||||
XPTC_InvokeByIndex(NULL, 0, 0, NULL);
|
||||
NS_NewFileSpec(NULL);
|
||||
xptc_dummy();
|
||||
xptc_dummy2();
|
||||
XPTI_GetInterfaceInfoManager();
|
||||
NS_NewGenericFactory(NULL, NULL, NULL);
|
||||
NS_NewHashtableEnumerator(NULL, NULL, NULL, NULL);
|
||||
nsCWeakProxy(0, 0);
|
||||
nsCWeakReferent(0);
|
||||
NS_GetWeakReference(NULL);
|
||||
#ifdef DEBUG
|
||||
TestSegmentedBuffer();
|
||||
#endif
|
||||
NS_NewSizeOfHandler(0);
|
||||
nsStorageStream();
|
||||
NS_NewBinaryInputStream(0, 0);
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsIGenericFactory_h___
|
||||
#define nsIGenericFactory_h___
|
||||
|
||||
#include "nsIFactory.h"
|
||||
|
||||
// {3bc97f01-ccdf-11d2-bab8-b548654461fc}
|
||||
#define NS_GENERICFACTORY_CID \
|
||||
{ 0x3bc97f01, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
|
||||
|
||||
// {3bc97f00-ccdf-11d2-bab8-b548654461fc}
|
||||
#define NS_IGENERICFACTORY_IID \
|
||||
{ 0x3bc97f00, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
|
||||
|
||||
#define NS_GENERICFACTORY_PROGID "component:/netscape/generic-factory"
|
||||
#define NS_GENERICFACTORY_CLASSNAME "Generic Factory"
|
||||
/**
|
||||
* Provides a Generic nsIFactory implementation that can be used by
|
||||
* DLLs with very simple factory needs.
|
||||
*/
|
||||
class nsIGenericFactory : public nsIFactory {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }
|
||||
|
||||
typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
typedef NS_CALLBACK(DestructorProcPtr) (void);
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's constructor function, which will be called
|
||||
* by CreateInstance.
|
||||
*/
|
||||
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's destructor function, which will be called
|
||||
* whe the generic factory is deleted. This is used to notify the DLL that
|
||||
* an instance of one of its generic factories is going away.
|
||||
*/
|
||||
NS_IMETHOD SetDestructor(DestructorProcPtr destructor) = 0;
|
||||
};
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewGenericFactory(nsIGenericFactory* *result,
|
||||
nsIGenericFactory::ConstructorProcPtr constructor,
|
||||
nsIGenericFactory::DestructorProcPtr destructor = NULL);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Generic Modules
|
||||
//
|
||||
// (See xpcom/sample/nsSampleModule.cpp to see how to use this.)
|
||||
|
||||
#include "nsIModule.h"
|
||||
|
||||
/**
|
||||
* Use this type to define a list of module component info to pass to
|
||||
* NS_NewGenericModule. E.g.:
|
||||
* static nsModuleComponentInfo components[] = { ... };
|
||||
* See xpcom/sample/nsSampleModule.cpp for more info.
|
||||
*/
|
||||
struct nsModuleComponentInfo {
|
||||
const char* mDescription;
|
||||
nsCID mCID;
|
||||
const char* mProgID;
|
||||
nsIGenericFactory::ConstructorProcPtr mConstructor;
|
||||
};
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewGenericModule(const char* moduleName,
|
||||
PRUint32 componentCount,
|
||||
nsModuleComponentInfo* components,
|
||||
nsIModule* *result);
|
||||
|
||||
#define NS_IMPL_NSGETMODULE(_name, _components) \
|
||||
extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, \
|
||||
nsIFileSpec* location, \
|
||||
nsIModule** result) \
|
||||
{ \
|
||||
return NS_NewGenericModule((_name), \
|
||||
sizeof(_components) / sizeof(_components[0]), \
|
||||
(_components), result); \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NS_GENERIC_FACTORY_CONSTRUCTOR(_InstanceClass) \
|
||||
static NS_IMETHODIMP \
|
||||
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
|
||||
{ \
|
||||
nsresult rv; \
|
||||
\
|
||||
_InstanceClass * inst; \
|
||||
\
|
||||
if (NULL == aResult) { \
|
||||
rv = NS_ERROR_NULL_POINTER; \
|
||||
return rv; \
|
||||
} \
|
||||
*aResult = NULL; \
|
||||
if (NULL != aOuter) { \
|
||||
rv = NS_ERROR_NO_AGGREGATION; \
|
||||
return rv; \
|
||||
} \
|
||||
\
|
||||
NS_NEWXPCOM(inst, _InstanceClass); \
|
||||
if (NULL == inst) { \
|
||||
rv = NS_ERROR_OUT_OF_MEMORY; \
|
||||
return rv; \
|
||||
} \
|
||||
NS_ADDREF(inst); \
|
||||
rv = inst->QueryInterface(aIID, aResult); \
|
||||
NS_RELEASE(inst); \
|
||||
\
|
||||
return rv; \
|
||||
} \
|
||||
|
||||
|
||||
#define NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(_InstanceClass, _InitMethod) \
|
||||
static NS_IMETHODIMP \
|
||||
_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) \
|
||||
{ \
|
||||
nsresult rv; \
|
||||
\
|
||||
_InstanceClass * inst; \
|
||||
\
|
||||
if (NULL == aResult) { \
|
||||
rv = NS_ERROR_NULL_POINTER; \
|
||||
return rv; \
|
||||
} \
|
||||
*aResult = NULL; \
|
||||
if (NULL != aOuter) { \
|
||||
rv = NS_ERROR_NO_AGGREGATION; \
|
||||
return rv; \
|
||||
} \
|
||||
\
|
||||
NS_NEWXPCOM(inst, _InstanceClass); \
|
||||
if (NULL == inst) { \
|
||||
rv = NS_ERROR_OUT_OF_MEMORY; \
|
||||
return rv; \
|
||||
} \
|
||||
NS_ADDREF(inst); \
|
||||
rv = inst->_InitMethod(); \
|
||||
if(NS_SUCCEEDED(rv)) { \
|
||||
rv = inst->QueryInterface(aIID, aResult); \
|
||||
} \
|
||||
NS_RELEASE(inst); \
|
||||
\
|
||||
return rv; \
|
||||
} \
|
||||
|
||||
#endif /* nsIGenericFactory_h___ */
|
||||
@@ -1,521 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
//
|
||||
// Key operations
|
||||
//
|
||||
|
||||
static PR_CALLBACK PLHashNumber _hashValue(const void *key)
|
||||
{
|
||||
return ((const nsHashKey *) key)->HashValue();
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashKeyCompare(const void *key1, const void *key2) {
|
||||
return ((const nsHashKey *) key1)->Equals((const nsHashKey *) key2);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashValueCompare(const void *value1,
|
||||
const void *value2) {
|
||||
// We're not going to make any assumptions about value equality
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Memory callbacks
|
||||
//
|
||||
|
||||
static PR_CALLBACK void *_hashAllocTable(void *pool, PRSize size) {
|
||||
return PR_MALLOC(size);
|
||||
}
|
||||
|
||||
static PR_CALLBACK void _hashFreeTable(void *pool, void *item) {
|
||||
PR_DELETE(item);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PLHashEntry *_hashAllocEntry(void *pool, const void *key) {
|
||||
return PR_NEW(PLHashEntry);
|
||||
}
|
||||
|
||||
static PR_CALLBACK void _hashFreeEntry(void *pool, PLHashEntry *entry,
|
||||
PRUintn flag) {
|
||||
if (flag == HT_FREE_ENTRY) {
|
||||
delete (nsHashKey *) (entry->key);
|
||||
PR_DELETE(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static PLHashAllocOps _hashAllocOps = {
|
||||
_hashAllocTable, _hashFreeTable,
|
||||
_hashAllocEntry, _hashFreeEntry
|
||||
};
|
||||
|
||||
//
|
||||
// Enumerator callback
|
||||
//
|
||||
|
||||
struct _HashEnumerateArgs {
|
||||
nsHashtableEnumFunc fn;
|
||||
void* arg;
|
||||
};
|
||||
|
||||
static PR_CALLBACK PRIntn _hashEnumerate(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
|
||||
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
|
||||
? HT_ENUMERATE_NEXT
|
||||
: HT_ENUMERATE_STOP;
|
||||
}
|
||||
|
||||
//
|
||||
// HashKey
|
||||
//
|
||||
nsHashKey::nsHashKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
nsHashKey::~nsHashKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe)
|
||||
: mLock(NULL)
|
||||
{
|
||||
hashtable = PL_NewHashTable(aInitSize,
|
||||
_hashValue,
|
||||
_hashKeyCompare,
|
||||
_hashValueCompare,
|
||||
&_hashAllocOps,
|
||||
NULL);
|
||||
if (threadSafe == PR_TRUE)
|
||||
{
|
||||
mLock = PR_NewLock();
|
||||
if (mLock == NULL)
|
||||
{
|
||||
// Cannot create a lock. If running on a multiprocessing system
|
||||
// we are sure to die.
|
||||
PR_ASSERT(mLock != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsHashtable::~nsHashtable() {
|
||||
PL_HashTableDestroy(hashtable);
|
||||
if (mLock) PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
PRBool nsHashtable::Exists(nsHashKey *aKey)
|
||||
{
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return *hep != NULL;
|
||||
}
|
||||
|
||||
void *nsHashtable::Put(nsHashKey *aKey, void *aData) {
|
||||
void *res = NULL;
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
|
||||
if ((he = *hep) != NULL) {
|
||||
res = he->value;
|
||||
he->value = aData;
|
||||
} else {
|
||||
PL_HashTableRawAdd(hashtable, hep, hash,
|
||||
(void *) aKey->Clone(), aData);
|
||||
}
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *nsHashtable::Get(nsHashKey *aKey) {
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
void *ret = PL_HashTableLookup(hashtable, (void *) aKey);
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *nsHashtable::Remove(nsHashKey *aKey) {
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
void *res = NULL;
|
||||
|
||||
if ((he = *hep) != NULL) {
|
||||
res = he->value;
|
||||
PL_HashTableRawRemove(hashtable, hep, he);
|
||||
}
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
|
||||
// I don't know how this was supposed to work since the elements are neither copied
|
||||
// nor refcounted.
|
||||
static PR_CALLBACK PRIntn _hashEnumerateShare(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsHashtable *newHashtable = (nsHashtable *)arg;
|
||||
newHashtable->Put((nsHashKey *) he->key, he->value);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsHashtable * nsHashtable::Clone() {
|
||||
PRBool threadSafe = PR_FALSE;
|
||||
if (mLock)
|
||||
threadSafe = PR_TRUE;
|
||||
nsHashtable *newHashTable = new nsHashtable(hashtable->nentries, threadSafe);
|
||||
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateShare, newHashTable);
|
||||
return newHashTable;
|
||||
}
|
||||
|
||||
void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure) {
|
||||
_HashEnumerateArgs thunk;
|
||||
thunk.fn = aEnumFunc;
|
||||
thunk.arg = closure;
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerate, &thunk);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashEnumerateRemove(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
|
||||
if (thunk)
|
||||
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
|
||||
? HT_ENUMERATE_REMOVE
|
||||
: HT_ENUMERATE_STOP;
|
||||
else
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
void nsHashtable::Reset() {
|
||||
Reset(NULL);
|
||||
}
|
||||
|
||||
void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* closure)
|
||||
{
|
||||
if (destroyFunc != NULL)
|
||||
{
|
||||
_HashEnumerateArgs thunk;
|
||||
thunk.fn = destroyFunc;
|
||||
thunk.arg = closure;
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, &thunk);
|
||||
}
|
||||
else
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsStringKey::nsStringKey(const char* str)
|
||||
{
|
||||
mStr.Assign(str);
|
||||
}
|
||||
|
||||
nsStringKey::nsStringKey(const PRUnichar* str)
|
||||
{
|
||||
mStr.Assign(str);
|
||||
}
|
||||
|
||||
nsStringKey::nsStringKey(const nsStr& str)
|
||||
{
|
||||
mStr.Assign(str);
|
||||
}
|
||||
|
||||
nsStringKey::~nsStringKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
PRUint32 nsStringKey::HashValue(void) const
|
||||
{
|
||||
if(mStr.IsUnicode())
|
||||
{
|
||||
PRUint32 h;
|
||||
PRUint32 n;
|
||||
PRUint32 m;
|
||||
const PRUnichar* c;
|
||||
|
||||
h = 0;
|
||||
n = mStr.Length();
|
||||
c = mStr.GetUnicode();
|
||||
if(n < 16)
|
||||
{ /* Hash every char in a short string. */
|
||||
for(; n; c++, n--)
|
||||
h = (h >> 28) ^ (h << 4) ^ *c;
|
||||
}
|
||||
else
|
||||
{ /* Sample a la jave.lang.String.hash(). */
|
||||
for(m = n / 8; n >= m; c += m, n -= m)
|
||||
h = (h >> 28) ^ (h << 4) ^ *c;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
return (PRUint32)PL_HashString((const void*) mStr.GetBuffer());
|
||||
}
|
||||
|
||||
PRBool nsStringKey::Equals(const nsHashKey* aKey) const
|
||||
{
|
||||
return ((nsStringKey*)aKey)->mStr == mStr;
|
||||
}
|
||||
|
||||
nsHashKey* nsStringKey::Clone() const
|
||||
{
|
||||
return new nsStringKey(mStr);
|
||||
}
|
||||
|
||||
const nsString& nsStringKey::GetString() const
|
||||
{
|
||||
return mStr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
|
||||
// deleted
|
||||
|
||||
nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
|
||||
void* cloneElementClosure,
|
||||
nsHashtableEnumFunc destroyElementFun,
|
||||
void* destroyElementClosure,
|
||||
PRUint32 aSize, PRBool threadSafe)
|
||||
: nsHashtable(aSize, threadSafe),
|
||||
mCloneElementFun(cloneElementFun),
|
||||
mCloneElementClosure(cloneElementClosure),
|
||||
mDestroyElementFun(destroyElementFun),
|
||||
mDestroyElementClosure(destroyElementClosure)
|
||||
{
|
||||
}
|
||||
|
||||
nsObjectHashtable::~nsObjectHashtable()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
PR_CALLBACK PRIntn
|
||||
nsObjectHashtable::CopyElement(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
|
||||
void* newElement =
|
||||
newHashtable->mCloneElementFun((nsHashKey*)he->key, he->value,
|
||||
newHashtable->mCloneElementClosure);
|
||||
if (newElement == nsnull)
|
||||
return HT_ENUMERATE_STOP;
|
||||
newHashtable->Put((nsHashKey*)he->key, newElement);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsHashtable*
|
||||
nsObjectHashtable::Clone()
|
||||
{
|
||||
PRBool threadSafe = PR_FALSE;
|
||||
if (mLock)
|
||||
threadSafe = PR_TRUE;
|
||||
nsObjectHashtable* newHashTable =
|
||||
new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
|
||||
mDestroyElementFun, mDestroyElementClosure,
|
||||
hashtable->nentries, threadSafe);
|
||||
|
||||
PL_HashTableEnumerateEntries(hashtable, CopyElement, newHashTable);
|
||||
return newHashTable;
|
||||
}
|
||||
|
||||
void
|
||||
nsObjectHashtable::Reset()
|
||||
{
|
||||
nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
|
||||
{
|
||||
void *value = Remove(aKey);
|
||||
if (value && mDestroyElementFun)
|
||||
{
|
||||
return (*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
|
||||
}
|
||||
else
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
|
||||
|
||||
static PR_CALLBACK PRBool
|
||||
_ReleaseElement(nsHashKey *aKey, void *aData, void* closure)
|
||||
{
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
|
||||
NS_IF_RELEASE(element);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsSupportsHashtable::~nsSupportsHashtable()
|
||||
{
|
||||
Enumerate(_ReleaseElement, nsnull);
|
||||
}
|
||||
|
||||
void*
|
||||
nsSupportsHashtable::Put(nsHashKey *aKey, void *aData)
|
||||
{
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, aData);
|
||||
NS_IF_ADDREF(element);
|
||||
return nsHashtable::Put(aKey, aData);
|
||||
}
|
||||
|
||||
void*
|
||||
nsSupportsHashtable::Get(nsHashKey *aKey)
|
||||
{
|
||||
void* data = nsHashtable::Get(aKey);
|
||||
if (!data)
|
||||
return nsnull;
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
|
||||
NS_IF_ADDREF(element);
|
||||
return data;
|
||||
}
|
||||
|
||||
void*
|
||||
nsSupportsHashtable::Remove(nsHashKey *aKey)
|
||||
{
|
||||
void* data = nsHashtable::Remove(aKey);
|
||||
if (!data)
|
||||
return nsnull;
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, data);
|
||||
NS_IF_RELEASE(element);
|
||||
return data;
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn
|
||||
_hashEnumerateCopy(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsHashtable *newHashtable = (nsHashtable *)arg;
|
||||
nsISupports* element = NS_STATIC_CAST(nsISupports*, he->value);
|
||||
NS_IF_ADDREF(element);
|
||||
newHashtable->Put((nsHashKey*)he->key, he->value);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsHashtable*
|
||||
nsSupportsHashtable::Clone()
|
||||
{
|
||||
PRBool threadSafe = PR_FALSE;
|
||||
if (mLock)
|
||||
threadSafe = PR_TRUE;
|
||||
nsSupportsHashtable* newHashTable =
|
||||
new nsSupportsHashtable(hashtable->nentries, threadSafe);
|
||||
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateCopy, newHashTable);
|
||||
return newHashTable;
|
||||
}
|
||||
|
||||
void
|
||||
nsSupportsHashtable::Reset()
|
||||
{
|
||||
Enumerate(_ReleaseElement, nsnull);
|
||||
nsHashtable::Reset();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsOpaqueKey: Where keys are opaque byte array blobs
|
||||
//
|
||||
|
||||
// Note opaque keys are not copied by this constructor. If you want a private
|
||||
// copy in each hash key, you must create one and pass it in to this function.
|
||||
nsOpaqueKey::nsOpaqueKey(const char *aOpaqueKey, PRUint32 aKeyLength)
|
||||
{
|
||||
mOpaqueKey = aOpaqueKey;
|
||||
mKeyLength = aKeyLength;
|
||||
}
|
||||
|
||||
nsOpaqueKey::~nsOpaqueKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsOpaqueKey::HashValue(void) const
|
||||
{
|
||||
PRUint32 h, i, k;
|
||||
|
||||
h = 0;
|
||||
|
||||
// Same hashing technique as for java.lang.String.hashCode()
|
||||
if (mKeyLength <= 15) {
|
||||
// A short key; Use a dense sampling to compute the hash code
|
||||
for (i = 0; i < mKeyLength; i++)
|
||||
h += 37 * mOpaqueKey[i];
|
||||
} else {
|
||||
// A long key; Use a sparse sampling to compute the hash code
|
||||
k = mKeyLength >> 3;
|
||||
for (i = 0; i < mKeyLength; i += k)
|
||||
h += 39 * mOpaqueKey[i];
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsOpaqueKey::Equals(const nsHashKey* aKey) const
|
||||
{
|
||||
nsOpaqueKey *otherKey = (nsOpaqueKey*)aKey;
|
||||
if (mKeyLength != otherKey->mKeyLength)
|
||||
return PR_FALSE;
|
||||
return !(PRBool)memcmp(otherKey->mOpaqueKey, mOpaqueKey, mKeyLength);
|
||||
}
|
||||
|
||||
nsHashKey*
|
||||
nsOpaqueKey::Clone() const
|
||||
{
|
||||
return new nsOpaqueKey(mOpaqueKey, mKeyLength);
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsOpaqueKey::GetKeyLength() const
|
||||
{
|
||||
return mKeyLength;
|
||||
}
|
||||
|
||||
const char*
|
||||
nsOpaqueKey::GetKey() const
|
||||
{
|
||||
return mOpaqueKey;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
/* -*- 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.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/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.org 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.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#ifndef nsHashtable_h__
|
||||
#define nsHashtable_h__
|
||||
|
||||
#include "plhash.h"
|
||||
#include "prlock.h"
|
||||
#include "nsCom.h"
|
||||
|
||||
class NS_COM nsHashKey {
|
||||
protected:
|
||||
nsHashKey(void);
|
||||
public:
|
||||
virtual ~nsHashKey(void);
|
||||
virtual PRUint32 HashValue(void) const = 0;
|
||||
virtual PRBool Equals(const nsHashKey *aKey) const = 0;
|
||||
virtual nsHashKey *Clone(void) const = 0;
|
||||
};
|
||||
|
||||
// Enumerator callback function. Use
|
||||
|
||||
typedef PRBool (*nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* closure);
|
||||
|
||||
class NS_COM nsHashtable {
|
||||
protected:
|
||||
// members
|
||||
PLHashTable *hashtable;
|
||||
PRLock *mLock;
|
||||
|
||||
public:
|
||||
nsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
|
||||
~nsHashtable();
|
||||
|
||||
PRInt32 Count(void) { return hashtable->nentries; }
|
||||
PRBool Exists(nsHashKey *aKey);
|
||||
void *Put(nsHashKey *aKey, void *aData);
|
||||
void *Get(nsHashKey *aKey);
|
||||
void *Remove(nsHashKey *aKey);
|
||||
nsHashtable *Clone();
|
||||
void Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure = NULL);
|
||||
void Reset();
|
||||
void Reset(nsHashtableEnumFunc destroyFunc, void* closure = NULL);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
|
||||
// deleted
|
||||
|
||||
typedef void* (*nsHashtableCloneElementFunc)(nsHashKey *aKey, void *aData, void* closure);
|
||||
|
||||
class NS_COM nsObjectHashtable : public nsHashtable {
|
||||
public:
|
||||
nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
|
||||
void* cloneElementClosure,
|
||||
nsHashtableEnumFunc destroyElementFun,
|
||||
void* destroyElementClosure,
|
||||
PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
|
||||
~nsObjectHashtable();
|
||||
|
||||
nsHashtable *Clone();
|
||||
void Reset();
|
||||
PRBool RemoveAndDelete(nsHashKey *aKey);
|
||||
|
||||
protected:
|
||||
static PR_CALLBACK PRIntn CopyElement(PLHashEntry *he, PRIntn i, void *arg);
|
||||
|
||||
nsHashtableCloneElementFunc mCloneElementFun;
|
||||
void* mCloneElementClosure;
|
||||
nsHashtableEnumFunc mDestroyElementFun;
|
||||
void* mDestroyElementClosure;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
|
||||
|
||||
class NS_COM nsSupportsHashtable : public nsHashtable {
|
||||
public:
|
||||
nsSupportsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE)
|
||||
: nsHashtable(aSize, threadSafe) {}
|
||||
~nsSupportsHashtable();
|
||||
|
||||
void *Put(nsHashKey *aKey, void *aData);
|
||||
void *Get(nsHashKey *aKey);
|
||||
void *Remove(nsHashKey *aKey);
|
||||
nsHashtable *Clone();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsISupportsKey: Where keys are nsISupports objects that get refcounted.
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsISupportsKey : public nsHashKey {
|
||||
protected:
|
||||
nsISupports* mKey;
|
||||
|
||||
public:
|
||||
nsISupportsKey(nsISupports* key) {
|
||||
mKey = key;
|
||||
NS_IF_ADDREF(mKey);
|
||||
}
|
||||
|
||||
~nsISupportsKey(void) {
|
||||
NS_IF_RELEASE(mKey);
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return (PRUint32)mKey;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mKey == ((nsISupportsKey *) aKey)->mKey);
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsISupportsKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsVoidKey: Where keys are void* objects that don't get refcounted.
|
||||
|
||||
class nsVoidKey : public nsHashKey {
|
||||
protected:
|
||||
const void* mKey;
|
||||
|
||||
public:
|
||||
nsVoidKey(const void* key) {
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return (PRUint32)mKey;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mKey == ((const nsVoidKey *) aKey)->mKey);
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsVoidKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID).
|
||||
|
||||
#include "nsID.h"
|
||||
|
||||
class nsIDKey : public nsHashKey {
|
||||
protected:
|
||||
nsID mID;
|
||||
|
||||
public:
|
||||
nsIDKey(const nsID &aID) {
|
||||
mID = aID;
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return mID.m0;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mID.Equals(((const nsIDKey *) aKey)->mID));
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsIDKey(mID);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsStringKey: Where keys are PRUnichar* or char*
|
||||
// Some uses: hashing ProgIDs, filenames, URIs
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class NS_COM nsStringKey : public nsHashKey {
|
||||
protected:
|
||||
nsAutoString mStr;
|
||||
|
||||
public:
|
||||
nsStringKey(const char* str);
|
||||
nsStringKey(const PRUnichar* str);
|
||||
nsStringKey(const nsStr& str);
|
||||
|
||||
~nsStringKey(void);
|
||||
|
||||
PRUint32 HashValue(void) const;
|
||||
|
||||
PRBool Equals(const nsHashKey* aKey) const;
|
||||
|
||||
nsHashKey* Clone() const;
|
||||
|
||||
// For when the owner of the hashtable wants to peek at the actual
|
||||
// string in the key. No copy is made, so be careful.
|
||||
const nsString& GetString() const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsOpaqueKey: Where keys are opaque byte-array blobs
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
class NS_COM nsOpaqueKey : public nsHashKey {
|
||||
protected:
|
||||
const char* mOpaqueKey; // Byte array of opaque data
|
||||
PRUint32 mKeyLength; // Length, in bytes, of mOpaqueKey
|
||||
|
||||
public:
|
||||
// Note opaque keys are not copied by this constructor. If you want a private
|
||||
// copy in each hash key, you must create one and pass it in to this function.
|
||||
nsOpaqueKey(const char* aOpaqueKey, PRUint32 aKeyLength);
|
||||
|
||||
~nsOpaqueKey(void);
|
||||
|
||||
PRUint32 HashValue(void) const;
|
||||
PRBool Equals(const nsHashKey* aKey) const;
|
||||
nsHashKey* Clone() const;
|
||||
|
||||
// For when the owner of the hashtable wants to peek at the actual
|
||||
// opaque array in the key. No copy is made, so be careful.
|
||||
const char* GetKey() const;
|
||||
PRUint32 GetKeyLength() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,247 +0,0 @@
|
||||
/* -*- 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.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/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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implementation of nsHashEnumerator.
|
||||
* Use it to expose nsIEnumerator interfaces around nsHashtable objects.
|
||||
* Contributed by Rob Ginda, rginda@ix.netcom.com
|
||||
*/
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsHashtableEnumerator.h"
|
||||
|
||||
class nsHashtableEnumerator : public nsIBidirectionalEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIENUMERATOR
|
||||
NS_DECL_NSIBIDIRECTIONALENUMERATOR
|
||||
|
||||
public:
|
||||
virtual ~nsHashtableEnumerator ();
|
||||
nsHashtableEnumerator (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData);
|
||||
nsHashtableEnumerator (); /* no implementation */
|
||||
|
||||
private:
|
||||
NS_IMETHOD Reset(nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData);
|
||||
NS_IMETHOD ReleaseElements();
|
||||
|
||||
nsISupports **mElements;
|
||||
PRInt16 mCount, mCurrent;
|
||||
PRBool mDoneFlag;
|
||||
|
||||
};
|
||||
|
||||
struct nsHashEnumClosure
|
||||
{
|
||||
NS_HASH_ENUMERATOR_CONVERTER Converter;
|
||||
nsISupports **Elements;
|
||||
PRInt16 Current;
|
||||
void *Data;
|
||||
};
|
||||
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewHashtableEnumerator (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData, nsIEnumerator **retval)
|
||||
{
|
||||
NS_PRECONDITION (retval, "null ptr");
|
||||
|
||||
*retval = nsnull;
|
||||
|
||||
nsHashtableEnumerator *hte = new nsHashtableEnumerator (aHash, aConverter,
|
||||
aData);
|
||||
if (!hte)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return hte->QueryInterface (nsCOMTypeInfo<nsIEnumerator>::GetIID(),
|
||||
(void **)retval);
|
||||
}
|
||||
|
||||
nsHashtableEnumerator::nsHashtableEnumerator (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData)
|
||||
: mElements(nsnull), mCount(0), mDoneFlag(PR_TRUE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
Reset (aHash, aConverter, aData);
|
||||
|
||||
}
|
||||
|
||||
PRBool
|
||||
hash_enumerator (nsHashKey *aKey, void *aObject, void *closure)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsHashEnumClosure *c = (nsHashEnumClosure *)closure;
|
||||
|
||||
rv = c->Converter (aKey, (void *)aObject, (void *)c->Data,
|
||||
&c->Elements[c->Current]);
|
||||
|
||||
if (!NS_FAILED(rv))
|
||||
c->Current++;
|
||||
|
||||
return PR_TRUE;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Reset (nsHashtable *aHash,
|
||||
NS_HASH_ENUMERATOR_CONVERTER aConverter,
|
||||
void *aData)
|
||||
{
|
||||
nsHashEnumClosure c;
|
||||
|
||||
ReleaseElements();
|
||||
|
||||
mCurrent = c.Current = 0;
|
||||
mCount = aHash->Count();
|
||||
if (mCount == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mElements = c.Elements = new nsISupports*[mCount];
|
||||
c.Data = aData;
|
||||
c.Converter = aConverter;
|
||||
aHash->Enumerate (&hash_enumerator, &c);
|
||||
|
||||
mCount = c.Current; /* some items may not have converted correctly */
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::ReleaseElements()
|
||||
{
|
||||
|
||||
for (; mCount > 0; mCount--)
|
||||
if (mElements[mCount - 1])
|
||||
NS_RELEASE(mElements[mCount - 1]);
|
||||
|
||||
delete[] mElements;
|
||||
mElements = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsHashtableEnumerator, nsIBidirectionalEnumerator, nsIEnumerator)
|
||||
|
||||
nsHashtableEnumerator::~nsHashtableEnumerator()
|
||||
{
|
||||
ReleaseElements();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::First ()
|
||||
{
|
||||
if (!mElements || (mCount == 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mCurrent = 0;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Last ()
|
||||
{
|
||||
if (!mElements || (mCount == 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mCurrent = mCount - 1;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Prev ()
|
||||
{
|
||||
if (!mElements || (mCount == 0) || (mCurrent == 0)) {
|
||||
mDoneFlag = PR_TRUE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mCurrent--;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::Next ()
|
||||
{
|
||||
if (!mElements || (mCount == 0) || (mCurrent == mCount - 1)) {
|
||||
mDoneFlag = PR_TRUE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mCurrent++;
|
||||
mDoneFlag = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::CurrentItem (nsISupports **retval)
|
||||
{
|
||||
NS_PRECONDITION (retval, "null ptr");
|
||||
NS_PRECONDITION (mElements, "invalid state");
|
||||
NS_ASSERTION (mCurrent >= 0, "mCurrent less than zero");
|
||||
|
||||
if (mCount == 0)
|
||||
{
|
||||
*retval = nsnull;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ASSERTION (mCurrent <= mCount - 1, "mCurrent too high");
|
||||
|
||||
*retval = mElements[mCurrent];
|
||||
|
||||
/* who says the item can't be null? */
|
||||
if (*retval)
|
||||
NS_ADDREF(*retval);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsHashtableEnumerator::IsDone ()
|
||||
{
|
||||
|
||||
if ((!mElements) || (mCount == 0) || (mDoneFlag))
|
||||
return NS_OK;
|
||||
|
||||
return NS_COMFALSE;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user