All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gargoylesoftware.htmlunit.javascript.IEConditionalCompilationScriptPreProcessor Maven / Gradle / Ivy

Go to download

Vaadin is a web application framework for Rich Internet Applications (RIA). Vaadin enables easy development and maintenance of fast and secure rich web applications with a stunning look and feel and a wide browser support. It features a server-side architecture with the majority of the logic running on the server. Ajax technology is used at the browser-side to ensure a rich and interactive user experience.

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright (c) 2002-2011 Gargoyle Software Inc.
 *
 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gargoylesoftware.htmlunit.javascript;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.ArrayUtils;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.ScriptPreProcessor;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

/**
 * A basic implementation for IE Conditional Compilation.
 *
 * 

Currently provides (basic) supports for @cc_on, @if, * @el_if, @else, @end and @set, * as well as for conditional compilation variables: * "@_win16", "@_mac", "@_alpha", "@_mc680x0", "@_PowerPC", "@_debug", "@_fast", * "@_win32", "@_x86", "@_jscript", "@_jscript_version" and "@_jscript_build" * * @version $Revision: 6335 $ * @author Ahmed Ashour * @author Marc Guillemot * @author Ronald Brill * * @see Microsoft Docs */ public class IEConditionalCompilationScriptPreProcessor implements ScriptPreProcessor { private static final Pattern CC_VARIABLE_PATTERN = Pattern.compile("@\\w+|'[^']*'|\"[^\"]*\""); private static final Pattern SET_PATTERN = Pattern.compile("@set\\s+(@\\w+)(\\s*=\\s*[\\d\\.]+)"); private static final Pattern C_VARIABLE_PATTERN = Pattern.compile("(@_\\w+)|'[^']*'|\"[^\"]*\""); private static final Pattern CC_PROCESS_PATTERN = Pattern.compile("/\\*@end"); private static final Pattern IF1_PATTERN = Pattern.compile("@if\\s*\\(([^\\)]+)\\)"); private static final Pattern IF2_PATTERN = Pattern.compile("@elif\\s*\\(([^\\)]+)\\)"); private static final Pattern IF3_PATTERN = Pattern.compile("@else"); private static final Pattern IF4_PATTERN = Pattern.compile("(/\\*)?@end"); private static final String CC_VARIABLE_PREFIX = "htmlunit_cc_variable_"; private enum PARSING_STATUS { NORMAL, IN_MULTI_LINE_COMMENT, IN_SINGLE_LINE_COMMENT, IN_STRING, IN_REG_EXP } private final Set setVariables_ = new HashSet(); /** * {@inheritDoc} */ public String preProcess(final HtmlPage htmlPage, final String sourceCode, final String sourceName, final int lineNumber, final HtmlElement htmlElement) { final int startPos = indexOf(sourceCode, "/*@cc_on", 0); if (startPos == -1) { return sourceCode; } final int endPos = indexOf(sourceCode, "@*/", startPos); if (endPos == -1) { return sourceCode; } final StringBuilder sb = new StringBuilder(); if (startPos > 0) { sb.append(sourceCode.substring(0, startPos)); } final BrowserVersion browserVersion = htmlPage.getWebClient().getBrowserVersion(); final String body = sourceCode.substring(startPos + 8, endPos); sb.append(processConditionalCompilation(body, browserVersion)); if (endPos < sourceCode.length() - 3) { String remaining = sourceCode.substring(endPos + 3); int nextStart = remaining.indexOf("/*@"); int nextEnd = remaining.indexOf("@*/", nextStart + 3); // handle other /*@ @*/ blocks while (nextStart >= 0 && nextEnd > 0) { sb.append(remaining.substring(0, nextStart)); final String nextBody = remaining.substring(nextStart + 3, nextEnd); sb.append(processConditionalCompilation(nextBody, browserVersion)); remaining = remaining.substring(nextEnd + 3); nextStart = remaining.indexOf("/*@"); nextEnd = remaining.indexOf("@*/", nextStart + 3); } sb.append(remaining); } return sb.toString(); } private String processConditionalCompilation(final String precompilationBody, final BrowserVersion browserVersion) { String body = precompilationBody; if (body.startsWith("cc_on")) { body = body.substring(5); } body = "@" + body; //TODO: StringScriptPreProcessor.indexOf() should be used (in order to ignore string literals) body = processIfs(body); if (body.startsWith("@")) { body = body.substring(1); } body = CC_PROCESS_PATTERN.matcher(body).replaceAll(""); body = replaceCompilationVariables(body, browserVersion); body = processSet(body); body = replaceCustomCompilationVariables(body); return body; } private String replaceCustomCompilationVariables(final String body) { final Matcher m = CC_VARIABLE_PATTERN.matcher(body); final StringBuffer sb = new StringBuffer(); while (m.find()) { final String match = m.group(); if (match.startsWith("@")) { m.appendReplacement(sb, replaceOneCustomCompilationVariable(match)); } else { m.appendReplacement(sb, match); } } m.appendTail(sb); return sb.toString(); } private String replaceOneCustomCompilationVariable(final String variable) { if (setVariables_.contains(variable)) { return CC_VARIABLE_PREFIX + variable.substring(1); } return "NaN"; } private String processSet(final String body) { final Matcher m = SET_PATTERN.matcher(body); final StringBuffer sb = new StringBuffer(); while (m.find()) { setVariables_.add(m.group(1)); m.appendReplacement(sb, CC_VARIABLE_PREFIX + m.group(1).substring(1) + m.group(2) + ";"); } m.appendTail(sb); return sb.toString(); } private static String processIfs(String code) { //TODO: StringScriptPreProcessor.indexOf() should be used (in order to ignore string literals) code = IF1_PATTERN.matcher(code).replaceAll("if ($1) {"); code = IF2_PATTERN.matcher(code).replaceAll("} else if ($1) {"); code = IF3_PATTERN.matcher(code).replaceAll("} else {"); code = IF4_PATTERN.matcher(code).replaceAll("}"); return code; } String replaceCompilationVariables(final String source, final BrowserVersion browserVersion) { final Matcher m = C_VARIABLE_PATTERN.matcher(source); final StringBuffer sb = new StringBuffer(); while (m.find()) { final String match = m.group(); if (match.startsWith("@")) { m.appendReplacement(sb, replaceOneVariable(match, browserVersion)); } else { m.appendReplacement(sb, match); } } m.appendTail(sb); return sb.toString(); } /** * Replace a single conditional compilation variable * @param variable something like "@_win32" * @return the value */ private static String replaceOneVariable(final String variable, final BrowserVersion browserVersion) { final String[] varNaN = {"@_win16", "@_mac", "@_alpha", "@_mc680x0", "@_PowerPC", "@_debug", "@_fast"}; final String[] varTrue = {"@_win32", "@_x86", "@_jscript"}; if (ArrayUtils.contains(varTrue, variable)) { return "true"; } else if ("@_jscript_version".equals(variable)) { if (browserVersion.getBrowserVersionNumeric() <= 6) { return "5.6"; } else if (browserVersion.getBrowserVersionNumeric() == 7) { return "5.7"; } return "5.8"; } else if ("@_jscript_build".equals(variable)) { if (browserVersion.getBrowserVersionNumeric() <= 6) { return "6626"; } if (browserVersion.getBrowserVersionNumeric() == 7) { return "5730"; } return "18702"; } else if (ArrayUtils.contains(varNaN, variable)) { return "NaN"; } return variable; } /** * Returns the index within the JavaScript code of the first occurrence of the specified substring. * This method searches inside multi-lines comments, but ignores the string literals and single line comments. * @param sourceCode JavaScript source * @param str any string * @param fromIndex the index from which to start the search * @return the index */ private static int indexOf(final String sourceCode, final String str, final int fromIndex) { PARSING_STATUS parsingStatus = PARSING_STATUS.NORMAL; char stringChar = 0; for (int i = 0; i < sourceCode.length(); i++) { if ((parsingStatus == PARSING_STATUS.NORMAL || parsingStatus == PARSING_STATUS.IN_MULTI_LINE_COMMENT) && i >= fromIndex && i + str.length() <= sourceCode.length() && sourceCode.substring(i, i + str.length()).equals(str)) { return i; } final char ch = sourceCode.charAt(i); switch (ch) { case '/': if (parsingStatus == PARSING_STATUS.NORMAL && i + 1 < sourceCode.length()) { final char nextCh = sourceCode.charAt(i + 1); if (nextCh == '/') { parsingStatus = PARSING_STATUS.IN_SINGLE_LINE_COMMENT; } else if (nextCh == '*') { parsingStatus = PARSING_STATUS.IN_MULTI_LINE_COMMENT; } else { stringChar = ch; parsingStatus = PARSING_STATUS.IN_REG_EXP; } } else if (parsingStatus == PARSING_STATUS.IN_REG_EXP && ch == stringChar) { stringChar = 0; parsingStatus = PARSING_STATUS.NORMAL; } break; case '*': if (parsingStatus == PARSING_STATUS.IN_MULTI_LINE_COMMENT && i + 1 < sourceCode.length()) { final char nextCh = sourceCode.charAt(i + 1); if (nextCh == '/') { parsingStatus = PARSING_STATUS.NORMAL; } } break; case '\n': if (parsingStatus == PARSING_STATUS.IN_SINGLE_LINE_COMMENT) { parsingStatus = PARSING_STATUS.NORMAL; } break; case '\'': case '"': if (parsingStatus == PARSING_STATUS.NORMAL) { stringChar = ch; parsingStatus = PARSING_STATUS.IN_STRING; } else if (parsingStatus == PARSING_STATUS.IN_STRING && ch == stringChar) { stringChar = 0; parsingStatus = PARSING_STATUS.NORMAL; } break; case '\\': if (parsingStatus == PARSING_STATUS.IN_STRING) { if (i + 3 < sourceCode.length() && sourceCode.charAt(i + 1) == 'x') { final char ch1 = Character.toUpperCase(sourceCode.charAt(i + 2)); final char ch2 = Character.toUpperCase(sourceCode.charAt(i + 3)); if ((ch1 >= '0' && ch1 <= '9' || ch1 >= 'A' && ch1 <= 'F') && (ch2 >= '0' && ch2 <= '9' || ch2 >= 'A' && ch2 <= 'F')) { final char character = (char) Integer.parseInt(sourceCode.substring(i + 2, i + 4), 16); if (character >= ' ') { i += 3; continue; } } } else if (i + 1 < sourceCode.length()) { i++; continue; } } default: } } return -1; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy