public Object getDefaultValue(Class<?> hint) { Object value; if (hint == null) { if (javaObject instanceof Boolean) { hint = ScriptRuntime.BooleanClass; } } if (hint == null || hint == ScriptRuntime.StringClass) { value = javaObject.toString(); } else { String converterName; if (hint == ScriptRuntime.BooleanClass) { converterName = "booleanValue"; } else if (hint == ScriptRuntime.NumberClass) { converterName = "doubleValue"; } else { throw Context.reportRuntimeError0("msg.default.value"); } Object converterObject = get(converterName, this); if (converterObject instanceof Function) { Function f = (Function) converterObject; value = f.call(Context.getContext(), f.getParentScope(), this, ScriptRuntime.emptyArgs); } else { if (hint == ScriptRuntime.NumberClass && javaObject instanceof Boolean) { boolean b = ((Boolean) javaObject).booleanValue(); value = ScriptRuntime.wrapNumber(b ? 1.0 : 0.0); } else { value = javaObject.toString(); } } } return value; }
/* * ECMA 3, 15.1.3 URI Handling Function Properties * * The following are implementations of the algorithms * given in the ECMA specification for the hidden functions * 'Encode' and 'Decode'. */ private static String encode(String str, boolean fullUri) { byte[] utf8buf = null; StringBuffer sb = null; for (int k = 0, length = str.length(); k != length; ++k) { char C = str.charAt(k); if (encodeUnescaped(C, fullUri)) { if (sb != null) { sb.append(C); } } else { if (sb == null) { sb = new StringBuffer(length + 3); sb.append(str); sb.setLength(k); utf8buf = new byte[6]; } if (0xDC00 <= C && C <= 0xDFFF) { throw Context.reportRuntimeError0("msg.bad.uri"); } int V; if (C < 0xD800 || 0xDBFF < C) { V = C; } else { k++; if (k == length) { throw Context.reportRuntimeError0("msg.bad.uri"); } char C2 = str.charAt(k); if (!(0xDC00 <= C2 && C2 <= 0xDFFF)) { throw Context.reportRuntimeError0("msg.bad.uri"); } V = ((C - 0xD800) << 10) + (C2 - 0xDC00) + 0x10000; } int L = oneUcs4ToUtf8Char(utf8buf, V); for (int j = 0; j < L; j++) { int d = 0xff & utf8buf[j]; sb.append('%'); sb.append(toHexChar(d >>> 4)); sb.append(toHexChar(d & 0xf)); } } } return (sb == null) ? str : sb.toString(); }
public Scriptable construct(Context cx, Scriptable scope, Object[] args) { ClassLoader loader = null; if (args.length != 0) { Object arg = args[0]; if (arg instanceof Wrapper) { arg = ((Wrapper) arg).unwrap(); } if (arg instanceof ClassLoader) { loader = (ClassLoader) arg; } } if (loader == null) { Context.reportRuntimeError0("msg.not.classloader"); return null; } NativeJavaPackage pkg = new NativeJavaPackage(true, "", loader); ScriptRuntime.setObjectProtoAndParent(pkg, scope); return pkg; }
private Scriptable js_getClass(Context cx, Scriptable scope, Object[] args) { if (args.length > 0 && args[0] instanceof Wrapper) { Scriptable result = this; Class<?> cl = ((Wrapper) args[0]).unwrap().getClass(); // Evaluate the class name by getting successive properties of // the string to find the appropriate NativeJavaClass object String name = cl.getName(); int offset = 0; for (; ; ) { int index = name.indexOf('.', offset); String propName = index == -1 ? name.substring(offset) : name.substring(offset, index); Object prop = result.get(propName, result); if (!(prop instanceof Scriptable)) break; // fall through to error result = (Scriptable) prop; if (index == -1) return result; offset = index + 1; } } throw Context.reportRuntimeError0("msg.not.java.obj"); }
@Override public void put(int index, Scriptable start, Object value) { throw Context.reportRuntimeError0("msg.pkg.int"); }
public Scriptable construct(Context cx, Scriptable scope, Object[] args) { throw Context.reportRuntimeError0("msg.script.is.not.constructor"); }
private static void generateMethod( ClassFileWriter cfw, String genName, String methodName, Class<?>[] parms, Class<?> returnType, boolean convertResult) { StringBuilder sb = new StringBuilder(); int paramsEnd = appendMethodSignature(parms, returnType, sb); String methodSignature = sb.toString(); cfw.startMethod(methodName, methodSignature, ClassFileWriter.ACC_PUBLIC); // Prepare stack to call method // push factory cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "factory", "Lorg/mozilla/javascript/ContextFactory;"); // push self cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "self", "Lorg/mozilla/javascript/Scriptable;"); // push function cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "delegee", "Lorg/mozilla/javascript/Scriptable;"); cfw.addPush(methodName); cfw.addInvoke( ByteCode.INVOKESTATIC, "org/mozilla/javascript/JavaAdapter", "getFunction", "(Lorg/mozilla/javascript/Scriptable;" + "Ljava/lang/String;" + ")Lorg/mozilla/javascript/Function;"); // push arguments generatePushWrappedArgs(cfw, parms, parms.length); // push bits to indicate which parameters should be wrapped if (parms.length > 64) { // If it will be an issue, then passing a static boolean array // can be an option, but for now using simple bitmask throw Context.reportRuntimeError0( "JavaAdapter can not subclass methods with more then" + " 64 arguments."); } long convertionMask = 0; for (int i = 0; i != parms.length; ++i) { if (!parms[i].isPrimitive()) { convertionMask |= (1 << i); } } cfw.addPush(convertionMask); // go through utility method, which creates a Context to run the // method in. cfw.addInvoke( ByteCode.INVOKESTATIC, "org/mozilla/javascript/JavaAdapter", "callMethod", "(Lorg/mozilla/javascript/ContextFactory;" + "Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Function;" + "[Ljava/lang/Object;" + "J" + ")Ljava/lang/Object;"); generateReturnResult(cfw, returnType, convertResult); cfw.stopMethod((short) paramsEnd); }
private static String decode(String str, boolean fullUri) { char[] buf = null; int bufTop = 0; for (int k = 0, length = str.length(); k != length; ) { char C = str.charAt(k); if (C != '%') { if (buf != null) { buf[bufTop++] = C; } ++k; } else { if (buf == null) { // decode always compress so result can not be bigger then // str.length() buf = new char[length]; str.getChars(0, k, buf, 0); bufTop = k; } int start = k; if (k + 3 > length) throw Context.reportRuntimeError0("msg.bad.uri"); int B = unHex(str.charAt(k + 1), str.charAt(k + 2)); if (B < 0) throw Context.reportRuntimeError0("msg.bad.uri"); k += 3; if ((B & 0x80) == 0) { C = (char) B; } else { // Decode UTF-8 sequence into ucs4Char and encode it into // UTF-16 int utf8Tail, ucs4Char, minUcs4Char; if ((B & 0xC0) == 0x80) { // First UTF-8 should be ouside 0x80..0xBF throw Context.reportRuntimeError0("msg.bad.uri"); } else if ((B & 0x20) == 0) { utf8Tail = 1; ucs4Char = B & 0x1F; minUcs4Char = 0x80; } else if ((B & 0x10) == 0) { utf8Tail = 2; ucs4Char = B & 0x0F; minUcs4Char = 0x800; } else if ((B & 0x08) == 0) { utf8Tail = 3; ucs4Char = B & 0x07; minUcs4Char = 0x10000; } else if ((B & 0x04) == 0) { utf8Tail = 4; ucs4Char = B & 0x03; minUcs4Char = 0x200000; } else if ((B & 0x02) == 0) { utf8Tail = 5; ucs4Char = B & 0x01; minUcs4Char = 0x4000000; } else { // First UTF-8 can not be 0xFF or 0xFE throw Context.reportRuntimeError0("msg.bad.uri"); } if (k + 3 * utf8Tail > length) throw Context.reportRuntimeError0("msg.bad.uri"); for (int j = 0; j != utf8Tail; j++) { if (str.charAt(k) != '%') throw Context.reportRuntimeError0("msg.bad.uri"); B = unHex(str.charAt(k + 1), str.charAt(k + 2)); if (B < 0 || (B & 0xC0) != 0x80) throw Context.reportRuntimeError0("msg.bad.uri"); ucs4Char = (ucs4Char << 6) | (B & 0x3F); k += 3; } // Check for overlongs and other should-not-present codes if (ucs4Char < minUcs4Char || ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) { ucs4Char = 0xFFFD; } if (ucs4Char >= 0x10000) { ucs4Char -= 0x10000; if (ucs4Char > 0xFFFFF) throw Context.reportRuntimeError0("msg.bad.uri"); char H = (char) ((ucs4Char >>> 10) + 0xD800); C = (char) ((ucs4Char & 0x3FF) + 0xDC00); buf[bufTop++] = H; } else { C = (char) ucs4Char; } } if (fullUri && URI_DECODE_RESERVED.indexOf(C) >= 0) { for (int x = start; x != k; x++) { buf[bufTop++] = str.charAt(x); } } else { buf[bufTop++] = C; } } } return (buf == null) ? str : new String(buf, 0, bufTop); }
/** * The global method escape, as per ECMA-262 15.1.2.4. * * <p>Includes code for the 'mask' argument supported by the C escape method, which used to be * part of the browser imbedding. Blame for the strange constant names should be directed there. */ private Object js_escape(Object[] args) { final int URL_XALPHAS = 1, URL_XPALPHAS = 2, URL_PATH = 4; String s = ScriptRuntime.toString(args, 0); int mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH; if (args.length > 1) { // the 'mask' argument. Non-ECMA. double d = ScriptRuntime.toNumber(args[1]); if (d != d || ((mask = (int) d) != d) || 0 != (mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))) { throw Context.reportRuntimeError0("msg.bad.esc.mask"); } } StringBuffer sb = null; for (int k = 0, L = s.length(); k != L; ++k) { int c = s.charAt(k); if (mask != 0 && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '@' || c == '*' || c == '_' || c == '-' || c == '.' || (0 != (mask & URL_PATH) && (c == '/' || c == '+')))) { if (sb != null) { sb.append((char) c); } } else { if (sb == null) { sb = new StringBuffer(L + 3); sb.append(s); sb.setLength(k); } int hexSize; if (c < 256) { if (c == ' ' && mask == URL_XPALPHAS) { sb.append('+'); continue; } sb.append('%'); hexSize = 2; } else { sb.append('%'); sb.append('u'); hexSize = 4; } // append hexadecimal form of c left-padded with 0 for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) { int digit = 0xf & (c >> shift); int hc = (digit < 10) ? '0' + digit : 'A' - 10 + digit; sb.append((char) hc); } } } return (sb == null) ? s : sb.toString(); }