001: /*
002: * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.es;
030:
031: import com.caucho.es.parser.Parser;
032: import com.caucho.vfs.ReadStream;
033: import com.caucho.vfs.Vfs;
034:
035: import java.io.IOException;
036:
037: /**
038: * JavaScript object
039: */
040: class NativeGlobal extends Native {
041: static final int EVAL = 2;
042: static final int PARSE_INT = 3;
043: static final int PARSE_FLOAT = 4;
044: static final int ESCAPE = 5;
045: static final int UNESCAPE = 6;
046: static final int IS_NAN = 7;
047: static final int IS_FINITE = 8;
048:
049: static final int PRINT = 9;
050: static final int SYSTEM = PRINT + 1;
051:
052: /**
053: * Create a new object based on a prototype
054: */
055: NativeGlobal(String name, int n, int len) {
056: super (name, len);
057:
058: this .n = n;
059: }
060:
061: /**
062: * Creates the native Object object
063: */
064: static void create(Global resin) {
065: put(resin, "eval", EVAL, 1);
066: put(resin, "parseInt", PARSE_INT, 2);
067: put(resin, "parseFloat", PARSE_FLOAT, 1);
068: put(resin, "escape", ESCAPE, 1);
069: put(resin, "unescape", UNESCAPE, 1);
070: put(resin, "isNaN", IS_NAN, 1);
071: put(resin, "isFinite", IS_FINITE, 1);
072:
073: put(resin, "print", PRINT, 1);
074: put(resin, "system", SYSTEM, 1);
075: }
076:
077: private static void put(Global resin, String name, int n, int len) {
078: ESId id = ESId.intern(name);
079:
080: resin.addProperty(id, new NativeGlobal(name, n, len));
081: }
082:
083: public ESBase call(Call eval, int length) throws Throwable {
084: switch (n) {
085: case EVAL:
086: return eval(eval, length);
087:
088: case PARSE_INT:
089: return parseInt(eval, length);
090:
091: case PARSE_FLOAT:
092: if (length < 1)
093: return ESNumber.NaN;
094: else {
095: return ESNumber.create(ESString.parseFloat(eval.getArg(
096: 0).toStr()));
097: }
098:
099: case ESCAPE:
100: return escape(eval, length);
101:
102: case UNESCAPE:
103: return unescape(eval, length);
104:
105: case IS_NAN:
106: if (length < 1)
107: return esUndefined;
108: else
109: return ESBoolean.create(Double.isNaN(eval.getArg(0)
110: .toNum()));
111:
112: case IS_FINITE:
113: if (length < 1)
114: return esUndefined;
115: else {
116: double value = eval.getArg(0).toNum();
117: if (Double.isNaN(value))
118: return ESBoolean.create(false);
119: else if (value == 1.0 / 0.0)
120: return ESBoolean.create(false);
121: else if (value == -1.0 / 0.0)
122: return ESBoolean.create(false);
123: else
124: return ESBoolean.create(true);
125: }
126:
127: case PRINT:
128: System.out.print(eval.getArg(0).toStr().toString());
129: return esNull;
130:
131: case SYSTEM:
132: String arg = eval.getArg(0).toStr().toString();
133: String[] args = new String[3];
134: Process process;
135: try {
136: args[0] = "sh";
137: args[1] = "-c";
138: args[2] = arg;
139: process = Runtime.getRuntime().exec(args);
140: return ESNumber.create(process.waitFor());
141: } catch (Exception e) {
142: throw new ESWrapperException(e);
143: }
144:
145: default:
146: throw new ESException("Unknown object function");
147: }
148: }
149:
150: private ESBase eval(Call eval, int length) throws Throwable {
151: if (length < 1)
152: return esUndefined;
153:
154: ESBase arg = eval.getArg(0);
155: if (!(arg instanceof ESString))
156: return arg;
157:
158: String string = arg.toString();
159:
160: Global resin = Global.getGlobalProto();
161: ESBase context = eval.getFunctionContext();
162: Script script = null;
163: ReadStream is = null;
164: try {
165: Parser parser = new Parser();
166: is = Vfs.openString(string);
167: script = parser.parseEval(is, "eval", 1);
168: } catch (IOException e) {
169: e.printStackTrace();
170: } finally {
171: if (is != null)
172: is.close();
173: }
174:
175: ESCallable jsClass = script.initClass(resin, eval.getGlobal());
176:
177: return jsClass.call(2, eval.caller, 0);
178: }
179:
180: private ESBase parseInt(Call eval, int length) throws Throwable {
181: if (length < 1)
182: return ESNumber.NaN;
183:
184: ESString string = eval.getArg(0).toStr();
185: int len = string.length();
186:
187: int i = 0;
188: for (; i < len && Character.isSpaceChar(string.charAt(i)); i++) {
189: }
190:
191: int sign = 1;
192: if (i < len && string.charAt(i) == '+') {
193: i++;
194: } else if (i < len && string.charAt(i) == '-') {
195: sign = -1;
196: i++;
197: }
198:
199: int radix = 0;
200: if (length > 1) {
201: radix = eval.getArg(1).toInt32();
202: if (radix == 0) {
203: } else if (radix < 2 || radix > 36)
204: return ESNumber.NaN;
205: else if (radix == 16
206: && i + 1 < length
207: && string.charAt(i) == '0'
208: && (string.charAt(i + 1) == 'x' || string
209: .charAt(i + 1) == 'X'))
210: i += 2;
211: }
212:
213: if (radix != 0) {
214: } else if (i >= len)
215: radix = 10;
216: else if (string.charAt(i) != '0')
217: radix = 10;
218: else if (i + 1 < len
219: && (string.charAt(i + 1) == 'x' || string.charAt(i + 1) == 'X')) {
220: radix = 16;
221: i += 2;
222: } else {
223: radix = 8;
224: }
225:
226: long value = 0;
227: boolean hasDigit = false;
228: for (; i < len; i++) {
229: int ch = string.charAt(i);
230:
231: if (radix <= 10 && ('0' <= ch && ch <= '0' + radix - 1)) {
232: value = radix * value + string.charAt(i) - '0';
233: hasDigit = true;
234: } else if (radix > 10 && ('0' <= ch && ch <= '9')) {
235: value = radix * value + string.charAt(i) - '0';
236: hasDigit = true;
237: } else if (radix > 10
238: && ('a' <= ch && ch <= 'a' + radix - 11)) {
239: value = radix * value + string.charAt(i) - 'a' + 10;
240: hasDigit = true;
241: } else if (radix > 10
242: && ('A' <= ch && ch <= 'A' + radix - 11)) {
243: value = radix * value + string.charAt(i) - 'A' + 10;
244: hasDigit = true;
245: } else
246: break;
247: }
248:
249: if (hasDigit)
250: return ESNumber.create((double) sign * value);
251: else
252: return ESNumber.NaN;
253: }
254:
255: static ESBase escape(Call eval, int length) throws Throwable {
256: if (length < 1)
257: return esUndefined;
258:
259: ESString string = eval.getArg(0).toStr();
260: StringBuffer sbuf = new StringBuffer();
261:
262: for (int i = 0; i < string.length(); i++) {
263: int ch = string.charAt(i);
264:
265: if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'
266: || ch >= '0' && ch <= '9' || ch == '@' || ch == '*'
267: || ch == '.' || ch == '_' || ch == '+' || ch == '-'
268: || ch == '/') {
269: sbuf.append((char) ch);
270: } else if (ch < 256) {
271: sbuf.append('%');
272: sbuf.append(Integer.toHexString(ch >> 4));
273: sbuf.append(Integer.toHexString(ch & 0xf));
274: } else {
275: sbuf.append("%u");
276: sbuf.append(Integer.toHexString(ch >> 12));
277: sbuf.append(Integer.toHexString((ch >> 8) & 0xf));
278: sbuf.append(Integer.toHexString((ch >> 4) & 0xf));
279: sbuf.append(Integer.toHexString(ch & 0xf));
280: }
281: }
282:
283: return ESString.create(sbuf.toString());
284: }
285:
286: static ESBase unescape(Call eval, int length) throws Throwable {
287: if (length < 1)
288: return esUndefined;
289:
290: ESString string = eval.getArg(0).toStr();
291: StringBuffer sbuf = new StringBuffer();
292:
293: for (int i = 0; i < string.length(); i++) {
294: int ch = string.charAt(i);
295:
296: if (ch == '%' && i + 2 < string.length()) {
297: int limit = 2;
298: int start = 1;
299:
300: if (string.charAt(i + 1) == 'u') {
301: limit = 4;
302: start = 2;
303: }
304:
305: int newCh = 0;
306: int j = 0;
307: for (; j < limit && i + j + start < string.length(); j++) {
308: if ((ch = string.charAt(i + j + start)) >= '0'
309: && ch <= '9')
310: newCh = 16 * newCh + ch - '0';
311: else if (ch >= 'a' && ch <= 'f')
312: newCh = 16 * newCh + ch - 'a' + 10;
313: else if (ch >= 'A' && ch <= 'F')
314: newCh = 16 * newCh + ch - 'A' + 10;
315: else
316: break;
317: }
318:
319: if (j != limit) {
320: sbuf.append('%');
321: } else {
322: sbuf.append((char) newCh);
323: i += limit + start - 1;
324: }
325: } else
326: sbuf.append((char) ch);
327: }
328:
329: return ESString.create(sbuf.toString());
330: }
331: }
|