/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.es; import com.caucho.es.parser.Parser; import com.caucho.vfs.ReadStream; import com.caucho.vfs.Vfs; import java.io.IOException; /** * JavaScript object */ class NativeGlobal extends Native { static final int EVAL = 2; static final int PARSE_INT = 3; static final int PARSE_FLOAT = 4; static final int ESCAPE = 5; static final int UNESCAPE = 6; static final int IS_NAN = 7; static final int IS_FINITE = 8; static final int PRINT = 9; static final int SYSTEM = PRINT + 1; /** * Create a new object based on a prototype */ NativeGlobal(String name, int n, int len) { super(name, len); this.n = n; } /** * Creates the native Object object */ static void create(Global resin) { put(resin, "eval", EVAL, 1); put(resin, "parseInt", PARSE_INT, 2); put(resin, "parseFloat", PARSE_FLOAT, 1); put(resin, "escape", ESCAPE, 1); put(resin, "unescape", UNESCAPE, 1); put(resin, "isNaN", IS_NAN, 1); put(resin, "isFinite", IS_FINITE, 1); put(resin, "print", PRINT, 1); put(resin, "system", SYSTEM, 1); } private static void put(Global resin, String name, int n, int len) { ESId id = ESId.intern(name); resin.addProperty(id, new NativeGlobal(name, n, len)); } public ESBase call(Call eval, int length) throws Throwable { switch (n) { case EVAL: return eval(eval, length); case PARSE_INT: return parseInt(eval, length); case PARSE_FLOAT: if (length < 1) return ESNumber.NaN; else { return ESNumber.create(ESString.parseFloat(eval.getArg(0).toStr())); } case ESCAPE: return escape(eval, length); case UNESCAPE: return unescape(eval, length); case IS_NAN: if (length < 1) return esUndefined; else return ESBoolean.create(Double.isNaN(eval.getArg(0).toNum())); case IS_FINITE: if (length < 1) return esUndefined; else { double value = eval.getArg(0).toNum(); if (Double.isNaN(value)) return ESBoolean.create(false); else if (value == 1.0/0.0) return ESBoolean.create(false); else if (value == -1.0/0.0) return ESBoolean.create(false); else return ESBoolean.create(true); } case PRINT: System.out.print(eval.getArg(0).toStr().toString()); return esNull; case SYSTEM: String arg = eval.getArg(0).toStr().toString(); String []args = new String[3]; Process process; try { args[0] = "sh"; args[1] = "-c"; args[2] = arg; process = Runtime.getRuntime().exec(args); return ESNumber.create(process.waitFor()); } catch (Exception e) { throw new ESWrapperException(e); } default: throw new ESException("Unknown object function"); } } private ESBase eval(Call eval, int length) throws Throwable { if (length < 1) return esUndefined; ESBase arg = eval.getArg(0); if (! (arg instanceof ESString)) return arg; String string = arg.toString(); Global resin = Global.getGlobalProto(); ESBase context = eval.getFunctionContext(); Script script = null; ReadStream is = null; try { Parser parser = new Parser(); is = Vfs.openString(string); script = parser.parseEval(is, "eval", 1); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) is.close(); } ESCallable jsClass = script.initClass(resin, eval.getGlobal()); return jsClass.call(2, eval.caller, 0); } private ESBase parseInt(Call eval, int length) throws Throwable { if (length < 1) return ESNumber.NaN; ESString string = eval.getArg(0).toStr(); int len = string.length(); int i = 0; for (; i < len && Character.isSpaceChar(string.charAt(i)); i++) { } int sign = 1; if (i < len && string.charAt(i) == '+') { i++; } else if (i < len && string.charAt(i) == '-') { sign = -1; i++; } int radix = 0; if (length > 1) { radix = eval.getArg(1).toInt32(); if (radix == 0) { } else if (radix < 2 || radix > 36) return ESNumber.NaN; else if (radix == 16 && i + 1 < length && string.charAt(i) == '0' && (string.charAt(i + 1) == 'x' || string.charAt(i + 1) == 'X')) i += 2; } if (radix != 0) { } else if (i >= len) radix = 10; else if (string.charAt(i) != '0') radix = 10; else if (i + 1 < len && (string.charAt(i + 1) == 'x' || string.charAt(i + 1) == 'X')) { radix = 16; i += 2; } else { radix = 8; } long value = 0; boolean hasDigit = false; for (; i < len; i++) { int ch = string.charAt(i); if (radix <= 10 && ('0' <= ch && ch <= '0' + radix - 1)) { value = radix * value + string.charAt(i) - '0'; hasDigit = true; } else if (radix > 10 && ('0' <= ch && ch <= '9')) { value = radix * value + string.charAt(i) - '0'; hasDigit = true; } else if (radix > 10 && ('a' <= ch && ch <= 'a' + radix - 11)) { value = radix * value + string.charAt(i) - 'a' + 10; hasDigit = true; } else if (radix > 10 && ('A' <= ch && ch <= 'A' + radix - 11)) { value = radix * value + string.charAt(i) - 'A' + 10; hasDigit = true; } else break; } if (hasDigit) return ESNumber.create((double) sign * value); else return ESNumber.NaN; } static ESBase escape(Call eval, int length) throws Throwable { if (length < 1) return esUndefined; ESString string = eval.getArg(0).toStr(); StringBuffer sbuf = new StringBuffer(); for (int i = 0; i < string.length(); i++) { int ch = string.charAt(i); if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '@' || ch == '*' || ch == '.' || ch == '_' || ch == '+' || ch == '-' || ch == '/') { sbuf.append((char) ch); } else if (ch < 256) { sbuf.append('%'); sbuf.append(Integer.toHexString(ch >> 4)); sbuf.append(Integer.toHexString(ch & 0xf)); } else { sbuf.append("%u"); sbuf.append(Integer.toHexString(ch >> 12)); sbuf.append(Integer.toHexString((ch >> 8) & 0xf)); sbuf.append(Integer.toHexString((ch >> 4) & 0xf)); sbuf.append(Integer.toHexString(ch & 0xf)); } } return ESString.create(sbuf.toString()); } static ESBase unescape(Call eval, int length) throws Throwable { if (length < 1) return esUndefined; ESString string = eval.getArg(0).toStr(); StringBuffer sbuf = new StringBuffer(); for (int i = 0; i < string.length(); i++) { int ch = string.charAt(i); if (ch == '%' && i + 2 < string.length()) { int limit = 2; int start = 1; if (string.charAt(i + 1) == 'u') { limit = 4; start = 2; } int newCh = 0; int j = 0; for (; j < limit && i + j + start < string.length(); j++) { if ((ch = string.charAt(i + j + start)) >= '0' && ch <= '9') newCh = 16 * newCh + ch - '0'; else if (ch >= 'a' && ch <= 'f') newCh = 16 * newCh + ch - 'a' + 10; else if (ch >= 'A' && ch <= 'F') newCh = 16 * newCh + ch - 'A' + 10; else break; } if (j != limit) { sbuf.append('%'); } else { sbuf.append((char) newCh); i += limit + start - 1; } } else sbuf.append((char) ch); } return ESString.create(sbuf.toString()); } }