diff options
author | Adam Domurad <adomurad@redhat.com> | 2012-12-04 10:43:59 -0500 |
---|---|---|
committer | Adam Domurad <adomurad@redhat.com> | 2012-12-04 10:43:59 -0500 |
commit | 1f595aba1e38b1a0113f45492288e22d3fa90799 (patch) | |
tree | 422a8d29652e3084915801fdc960c1c3099ae2a4 | |
parent | 7aff0a246448bef22d89859b07fef92c128e14e5 (diff) |
Remove redundant HTML-tag scanner from ITW. Do not reconstruct tags.
-rw-r--r-- | ChangeLog | 35 | ||||
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/NetxPanel.java | 57 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/PluginBridge.java | 64 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/PluginParameterException.java | 43 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/PluginParameters.java | 238 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/resources/Messages.properties | 1 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties | 1 | ||||
-rw-r--r-- | plugin/icedteanp/IcedTeaNPPlugin.cc | 221 | ||||
-rw-r--r-- | plugin/icedteanp/IcedTeaNPPlugin.h | 4 | ||||
-rw-r--r-- | plugin/icedteanp/java/sun/applet/PluginAppletViewer.java | 534 | ||||
-rw-r--r-- | plugin/icedteanp/java/sun/applet/PluginParameterParser.java | 90 | ||||
-rw-r--r-- | tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc | 2 | ||||
-rw-r--r-- | tests/cpp-unit-tests/PluginParametersTest.cc | 93 | ||||
-rw-r--r-- | tests/netx/unit/net/sourceforge/jnlp/PluginBridgeTest.java | 53 | ||||
-rw-r--r-- | tests/netx/unit/net/sourceforge/jnlp/PluginParametersTest.java | 114 | ||||
-rw-r--r-- | tests/netx/unit/sun/applet/PluginParameterParserTest.java | 73 |
17 files changed, 842 insertions, 785 deletions
@@ -1,3 +1,38 @@ +2012-12-04 Adam Domurad <adomurad@redhat.com> + + Remove the applet/embed/object tag parser from ITW. Send the applet + parameters directly from the C++. + * Makefile.am: Allow unit-testing for classes in plugin.jar. + * netx/net/sourceforge/jnlp/NetxPanel.java: Use PluginParameters for + attribute lookup + * netx/net/sourceforge/jnlp/PluginBridge.java: Use PluginParameters + for attribute lookup + * netx/net/sourceforge/jnlp/resources/Messages.properties: Add message + for missing code/object attributes. + * netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties: Same. + * plugin/icedteanp/IcedTeaNPPlugin.cc: Send escaped parameter + name/values instead of applet tag. Remove some dead code. + * plugin/icedteanp/IcedTeaNPPlugin.h: Rename applet_tag -> + parameters_string. + * plugin/icedteanp/java/sun/applet/PluginAppletViewer.java: Extract + parsing code into its own class. + * tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc: Use CHECK_EQUALS + instead of CHECK. + * tests/netx/unit/net/sourceforge/jnlp/PluginBridgeTest.java: Update + unit tests due to constructor changes. + * netx/net/sourceforge/jnlp/PluginParameterException.java: New, thrown + when code/object attributes are missing. + * netx/net/sourceforge/jnlp/PluginParameters.java: New, Hashtable + wrapper that handles plugin attribute/parameter lookups. + * plugin/icedteanp/java/sun/applet/PluginParameterParser.java: New, + creates PluginParameters from escaped name/values. + * tests/cpp-unit-tests/PluginParametersTest.cc: New, C++ Unit tests for + plugin parameter related functions + * tests/netx/unit/net/sourceforge/jnlp/PluginParametersTest.java: New, + unit tests for PluginParameters class. + * tests/netx/unit/sun/applet/PluginParameterParserTest.java: New, unit + tests for PluginParameterParser class. + 2012-11-03 Jiri Vanek <jvanek@redhat.com> Fixed logging bottleneck diff --git a/Makefile.am b/Makefile.am index d66f278..3a2a1b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -969,7 +969,7 @@ stamps/netx-unit-tests-compile.stamp: stamps/netx.stamp \ mkdir -p $(NETX_UNIT_TEST_DIR) && \ $(BOOT_DIR)/bin/javac $(IT_JAVACFLAGS) \ -d $(NETX_UNIT_TEST_DIR) \ - -classpath $(JUNIT_JAR):$(NETX_DIR)/lib/classes.jar:$(TEST_EXTENSIONS_DIR) \ + -classpath $(JUNIT_JAR):$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/plugin.jar:$(NETX_DIR)/lib/classes.jar:$(TEST_EXTENSIONS_DIR) \ @netx-unit-tests-source-files.txt && \ mkdir -p stamps && \ touch $@ @@ -999,7 +999,7 @@ stamps/run-netx-unit-tests.stamp: stamps/netx-unit-tests-compile.stamp $(JUNIT_R done ; \ cd $(NETX_UNIT_TEST_DIR) ; \ class_names=`cat $(UNIT_CLASS_NAMES)` ; \ - CLASSPATH=$(NETX_DIR)/lib/classes.jar:$(JUNIT_JAR):$(JUNIT_RUNNER_JAR):$(TEST_EXTENSIONS_DIR):. \ + CLASSPATH=$(NETX_DIR)/lib/classes.jar:$(DESTDIR)$(datadir)/$(PACKAGE_NAME)/plugin.jar:$(JUNIT_JAR):$(JUNIT_RUNNER_JAR):$(TEST_EXTENSIONS_DIR):. \ $(BOOT_DIR)/bin/java -Xbootclasspath:$(RUNTIME) CommandLine $$class_names if WITH_XSLTPROC $(XSLTPROC) --stringparam logs logs_unit.html $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/jreport.xsl $(NETX_UNIT_TEST_DIR)/tests-output.xml > $(TESTS_DIR)/index_unit.html diff --git a/netx/net/sourceforge/jnlp/NetxPanel.java b/netx/net/sourceforge/jnlp/NetxPanel.java index ce20d5c..1afa416 100644 --- a/netx/net/sourceforge/jnlp/NetxPanel.java +++ b/netx/net/sourceforge/jnlp/NetxPanel.java @@ -27,7 +27,6 @@ import net.sourceforge.jnlp.runtime.JNLPRuntime; import java.net.URL; import java.util.HashMap; -import java.util.Hashtable; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -45,12 +44,12 @@ import sun.awt.SunToolkit; * @author Francis Kung <fkung@redhat.com> */ public class NetxPanel extends AppletViewerPanel implements SplashController { + private final PluginParameters parameters; private PluginBridge bridge = null; private boolean exitOnFailure = true; private AppletInstance appInst = null; private SplashController splashController; private boolean appletAlive; - private final String uKey; // We use this so that we can create exactly one thread group // for all panels with the same uKey. @@ -68,51 +67,24 @@ public class NetxPanel extends AppletViewerPanel implements SplashController { private static final ConcurrentMap<String, Boolean> appContextCreated = new ConcurrentHashMap<String, Boolean>(); - public NetxPanel(URL documentURL, Hashtable<String, String> atts) { - super(documentURL, atts); + public NetxPanel(URL documentURL, PluginParameters params) { + super(documentURL, params.getUnderlyingHashtable()); - /* According to http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/applet-compatibility.html, - * classloaders are shared iff these properties match: - * codebase, cache_archive, java_archive, archive - * - * To achieve this, we create the uniquekey based on those 4 values, - * always in the same order. The initial "<NAME>=" parts ensure a - * bad tag cannot trick the loader into getting shared with another. - */ - - // Firefox sometimes skips the codebase if it is default -- ".", - // so set it that way if absent - String codebaseAttr = atts.get("codebase") != null ? - atts.get("codebase") : "."; - - String cache_archiveAttr = atts.get("cache_archive") != null ? - atts.get("cache_archive") : ""; - - String java_archiveAttr = atts.get("java_archive") != null ? - atts.get("java_archive") : ""; + this.parameters = params; - String archiveAttr = atts.get("archive") != null ? - atts.get("archive") : ""; - - this.uKey = "codebase=" + codebaseAttr + - "cache_archive=" + cache_archiveAttr + - "java_archive=" + java_archiveAttr + - "archive=" + archiveAttr; - - // when this was being done (incorrectly) in Launcher, the call was - // new AppThreadGroup(mainGroup, file.getTitle()); + String uniqueKey = params.getUniqueKey(); synchronized(TGMapMutex) { - if (!uKeyToTG.containsKey(this.uKey)) { + if (!uKeyToTG.containsKey(uniqueKey)) { ThreadGroup tg = new ThreadGroup(Launcher.mainGroup, this.documentURL.toString()); - uKeyToTG.put(this.uKey, tg); + uKeyToTG.put(uniqueKey, tg); } } } // overloaded constructor, called when initialized via plugin - public NetxPanel(URL documentURL, Hashtable<String, String> atts, + public NetxPanel(URL documentURL, PluginParameters params, boolean exitOnFailure) { - this(documentURL, atts); + this(documentURL, params); this.exitOnFailure = exitOnFailure; this.appletAlive = true; } @@ -129,6 +101,7 @@ public class NetxPanel extends AppletViewerPanel implements SplashController { //Overriding to use Netx classloader. You might need to relax visibility //in sun.applet.AppletPanel for runLoader(). + @Override protected void runLoader() { try { @@ -138,7 +111,7 @@ public class NetxPanel extends AppletViewerPanel implements SplashController { getCode(), getWidth(), getHeight(), - atts, uKey); + parameters); doInit = true; dispatchAppletEvent(APPLET_LOADING, null); @@ -188,6 +161,7 @@ public class NetxPanel extends AppletViewerPanel implements SplashController { * the applet */ // Reminder: Relax visibility in sun.applet.AppletPanel + @Override protected synchronized void createAppletThread() { // initialize JNLPRuntime in the main threadgroup synchronized (JNLPRuntime.initMutex) { @@ -208,8 +182,7 @@ public class NetxPanel extends AppletViewerPanel implements SplashController { } public void updateSizeInAtts(int height, int width) { - this.atts.put("height", Integer.toString(height)); - this.atts.put("width", Integer.toString(width)); + parameters.updateSize(width, height); } public ClassLoader getAppletClassLoader() { @@ -222,7 +195,7 @@ public class NetxPanel extends AppletViewerPanel implements SplashController { public ThreadGroup getThreadGroup() { synchronized(TGMapMutex) { - return uKeyToTG.get(uKey); + return uKeyToTG.get(parameters.getUniqueKey()); } } @@ -232,7 +205,7 @@ public class NetxPanel extends AppletViewerPanel implements SplashController { } // only create a new context if one hasn't already been created for the // applets with this unique key. - if (null == appContextCreated.putIfAbsent(uKey, Boolean.TRUE)) { + if (null == appContextCreated.putIfAbsent(parameters.getUniqueKey(), Boolean.TRUE)) { SunToolkit.createNewAppContext(); } } diff --git a/netx/net/sourceforge/jnlp/PluginBridge.java b/netx/net/sourceforge/jnlp/PluginBridge.java index 37b72e6..1e34c49 100644 --- a/netx/net/sourceforge/jnlp/PluginBridge.java +++ b/netx/net/sourceforge/jnlp/PluginBridge.java @@ -45,26 +45,23 @@ import net.sourceforge.jnlp.runtime.JNLPRuntime; */ public class PluginBridge extends JNLPFile { - private String name; + private PluginParameters params; private Set<String> jars = new HashSet<String>(); //Folders can be added to the code-base through the archive tag private List<String> codeBaseFolders = new ArrayList<String>(); private String[] cacheJars = new String[0]; private String[] cacheExJars = new String[0]; - private Map<String, String> atts; private boolean usePack; private boolean useVersion; - private boolean codeBaseLookup; private boolean useJNLPHref; /** * Creates a new PluginBridge using a default JNLPCreator. */ public PluginBridge(URL codebase, URL documentBase, String jar, String main, - int width, int height, Map<String, String> atts, - String uKey) + int width, int height, PluginParameters params) throws Exception { - this(codebase, documentBase, jar, main, width, height, atts, uKey, new JNLPCreator()); + this(codebase, documentBase, jar, main, width, height, params, new JNLPCreator()); } /** @@ -86,25 +83,24 @@ public class PluginBridge extends JNLPFile { } public PluginBridge(URL codebase, URL documentBase, String archive, String main, - int width, int height, Map<String, String> atts, - String uKey, JNLPCreator jnlpCreator) + int width, int height, PluginParameters params, JNLPCreator jnlpCreator) throws Exception { specVersion = new Version("1.0"); fileVersion = new Version("1.1"); this.codeBase = codebase; this.sourceLocation = documentBase; - this.atts = atts; + this.params = params; - if (atts.containsKey("jnlp_href")) { + if (params.getJNLPHref() != null) { useJNLPHref = true; try { // Use codeBase as the context for the URL. If jnlp_href's // value is a complete URL, it will replace codeBase's context. - URL jnlp = new URL(codeBase, atts.get("jnlp_href")); + URL jnlp = new URL(codeBase, params.getJNLPHref()); JNLPFile jnlpFile = null; - if (atts.containsKey("jnlp_embedded")) { - InputStream jnlpInputStream = new ByteArrayInputStream(decodeBase64String(atts.get("jnlp_embedded"))); + if (params.getJNLPEmbedded() != null) { + InputStream jnlpInputStream = new ByteArrayInputStream(decodeBase64String(params.getJNLPEmbedded())); jnlpFile = new JNLPFile(jnlpInputStream, codeBase, false); } else { jnlpFile = jnlpCreator.create(jnlp, null, false, JNLPRuntime.getDefaultUpdatePolicy(), codeBase); @@ -118,7 +114,7 @@ public class PluginBridge extends JNLPFile { // Change the parameter name to lowercase to follow conventions. for (Map.Entry<String, String> entry : jnlpParams.entrySet()) { - this.atts.put(entry.getKey().toLowerCase(), entry.getValue()); + this.params.put(entry.getKey().toLowerCase(), entry.getValue()); } JARDesc[] jarDescs = jnlpFile.getResources().getJARs(); for (JARDesc jarDesc : jarDescs) { @@ -128,7 +124,7 @@ public class PluginBridge extends JNLPFile { } catch (MalformedURLException e) { // Don't fail because we cannot get the jnlp file. Parameters are optional not required. // it is the site developer who should ensure that file exist. - System.err.println("Unable to get JNLP file at: " + atts.get("jnlp_href") + System.err.println("Unable to get JNLP file at: " + params.getJNLPHref() + " with context of URL as: " + codeBase.toExternalForm()); } } else { @@ -138,14 +134,14 @@ public class PluginBridge extends JNLPFile { } // also, see if cache_archive is specified - String cacheArchive = atts.get("cache_archive"); - if (cacheArchive != null && cacheArchive.length() > 0) { + String cacheArchive = params.getCacheArchive(); + if (!cacheArchive.isEmpty()) { String[] versions = new String[0]; // are there accompanying versions? - String cacheVersion = atts.get("cache_version"); - if (cacheVersion != null) { + String cacheVersion = params.getCacheVersion(); + if (!cacheVersion.isEmpty()) { versions = cacheVersion.split(","); } @@ -162,8 +158,8 @@ public class PluginBridge extends JNLPFile { } } - String cacheArchiveEx = atts.get("cache_archive_ex"); - if (cacheArchiveEx != null && cacheArchiveEx.length() > 0) { + String cacheArchiveEx = params.getCacheArchiveEx(); + if (!cacheArchiveEx.isEmpty()) { cacheExJars = cacheArchiveEx.split(","); } @@ -178,19 +174,13 @@ public class PluginBridge extends JNLPFile { } } - name = atts.get("name"); - if (name == null) - name = "Applet"; - else - name = name + " applet"; - if (main.endsWith(".class")) main = main.substring(0, main.length() - 6); // the class name should be of the form foo.bar.Baz not foo/bar/Baz String mainClass = main.replace('/', '.'); - launchType = new AppletDesc(name, mainClass, documentBase, width, - height, atts); + launchType = new AppletDesc(params.getAppletTitle(), mainClass, documentBase, width, + height, params.getUnmodifiableMap()); if (main.endsWith(".class")) //single class file only security = new SecurityDesc(this, SecurityDesc.SANDBOX_PERMISSIONS, @@ -198,11 +188,11 @@ public class PluginBridge extends JNLPFile { else security = null; - this.uniqueKey = uKey; + this.uniqueKey = params.getUniqueKey(); usePack = false; useVersion = false; - String jargs = atts.get("java_arguments"); - if (jargs != null) { + String jargs = params.getJavaArguments(); + if (!jargs.isEmpty()) { for (String s : jargs.split(" ")) { String[] parts = s.trim().split("="); if (parts.length == 2 && Boolean.valueOf(parts[1])) { @@ -214,12 +204,10 @@ public class PluginBridge extends JNLPFile { } } } - String cbl = atts.get("codebase_lookup"); - codeBaseLookup = cbl == null || (Boolean.valueOf(cbl)); } public boolean codeBaseLookup() { - return codeBaseLookup; + return params.useCodebaseLookup(); } public boolean useJNLPHref() { @@ -235,7 +223,7 @@ public class PluginBridge extends JNLPFile { } public String getTitle() { - return name; + return params.getAppletTitle(); } public ResourcesDesc getResources(final Locale locale, final String os, @@ -258,9 +246,7 @@ public class PluginBridge extends JNLPFile { } boolean cacheable = true; - - String cacheOption = atts.get("cache_option"); - if (cacheOption != null && cacheOption.equalsIgnoreCase("no")) + if (params.getCacheOption().equalsIgnoreCase("no")) cacheable = false; for (String cacheJar : cacheJars) { diff --git a/netx/net/sourceforge/jnlp/PluginParameterException.java b/netx/net/sourceforge/jnlp/PluginParameterException.java new file mode 100644 index 0000000..b1e1e9d --- /dev/null +++ b/netx/net/sourceforge/jnlp/PluginParameterException.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2012 Red Hat + +This file is part of IcedTea. + +IcedTea 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, or (at your option) +any later version. + +IcedTea 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. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package net.sourceforge.jnlp; + +public class PluginParameterException extends RuntimeException { + public PluginParameterException(String detail) { + super(detail); + } +} diff --git a/netx/net/sourceforge/jnlp/PluginParameters.java b/netx/net/sourceforge/jnlp/PluginParameters.java new file mode 100644 index 0000000..6f0152e --- /dev/null +++ b/netx/net/sourceforge/jnlp/PluginParameters.java @@ -0,0 +1,238 @@ +/* PluginAppletAttributes -- Provides parsing for applet attributes + Copyright (C) 2012 Red Hat + +This file is part of IcedTea. + +IcedTea 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, or (at your option) +any later version. + +IcedTea 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. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package net.sourceforge.jnlp; + +import java.util.Collections; +import java.util.Hashtable; +import java.util.Map; + +import static net.sourceforge.jnlp.runtime.Translator.R; + +/** + * Represents plugin applet parameters, backed by a Hashtable. + */ + +public class PluginParameters { + private final Hashtable<String, String> parameters; + + public PluginParameters(Map<String, String> params) { + this.parameters = createParameterTable(params); + + if (this.parameters.get("code") == null + && this.parameters.get("object") == null) { + throw new PluginParameterException(R("BNoCodeOrObjectApplet")); + } + } + + // Note, lower-case key expected + public String get(String key) { + return this.parameters.get(key); + } + + public void put(String key, String value) { + parameters.put(key.toLowerCase(), value); + } + + public Map<String, String> getUnmodifiableMap() { + return Collections.unmodifiableMap(parameters); + } + + /** + * Used for compatibility with Hashtable-expecting classes. + * + * @return the underlying hashtable. + */ + Hashtable<String, String> getUnderlyingHashtable() { + return parameters; + } + + public String getDefaulted(String key, String defaultStr) { + String value = get(key); + return (value != null) ? value : defaultStr; + } + + public String getAppletTitle() { + String name = get("name"); + if (name == null) { + return "Applet"; + } else { + return name + " applet"; + } + } + + public String getCodebase() { + return getDefaulted("codebase", "."); + } + + public boolean useCodebaseLookup() { + return Boolean.valueOf(getDefaulted("codebase_lookup", "true")); + } + + public String getArchive() { + return getDefaulted("archive", ""); + } + + public String getJavaArchive() { + return getDefaulted("java_archive", ""); + } + + public String getJavaArguments() { + return getDefaulted("java_arguments", ""); + } + + public String getCacheArchive() { + return getDefaulted("cache_archive", ""); + } + + public String getCacheArchiveEx() { + return getDefaulted("cache_archive_ex", ""); + } + + public String getCacheOption() { + return getDefaulted("cache_option", ""); + } + + public String getCacheVersion() { + return getDefaulted("cache_version", ""); + } + + public String getCode() { + return getDefaulted("code", ""); + } + + public String getJNLPHref() { + return get("jnlp_href"); + } + + public String getJNLPEmbedded() { + return get("jnlp_embedded"); + } + + public String getJarFiles() { + return getDefaulted("archive", ""); + } + + public int getWidth() { + String widthStr = getDefaulted("width", "0"); + return Integer.valueOf(widthStr); + } + + public int getHeight() { + String heightStr = getDefaulted("height", "0"); + return Integer.valueOf(heightStr); + } + + public void updateSize(int width, int height) { + parameters.put("width", Integer.toString(width)); + parameters.put("height", Integer.toString(height)); + } + + public String getUniqueKey() { + /* According to http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/applet-compatibility.html, + * classloaders are shared iff these properties match: + * codebase, cache_archive, java_archive, archive + * + * To achieve this, we create the uniquekey based on those 4 values, + * always in the same order. The initial "<NAME>=" parts ensure a + * bad tag cannot trick the loader into getting shared with another. + */ + return "codebase=" + getCodebase() + "cache_archive=" + getCacheArchive() + + "java_archive=" + getJavaArchive() + "archive=" + getArchive(); + } + + /** + * Replace an attribute with its 'java_'-prefixed version. + * Note that java_* aliases override older names: + * http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-nav + */ + static void ensureJavaPrefixTakesPrecedence(Map<String, String> params, + String attribute) { + String javaPrefixAttribute = params.get("java_" + attribute); + if (javaPrefixAttribute != null) { + params.put(attribute, javaPrefixAttribute); + } + } + + /** + * Creates the underlying hash table with the proper overrides. Ensure all + * keys are lowercase consistently. + * + * @param params + * the properties, before parameter aliasing rules. + * @return the resulting parameter table + */ + static Hashtable<String, String> createParameterTable( + Map<String, String> rawParams) { + Hashtable<String, String> params = new Hashtable<String, String>(); + + for (Map.Entry<String, String> entry : rawParams.entrySet()) { + String key = entry.getKey().toLowerCase(); + String value = entry.getValue(); + params.put(key, value); + } + + String codeTag = params.get("code"); + String classID = params.get("classid"); + + // If there is a classid and no code tag present, transform it to code tag + if (codeTag == null && classID != null && !classID.startsWith("clsid:")) { + codeTag = classID; + params.put("code", codeTag); + } + + // remove java: from code tag + if (codeTag != null && codeTag.startsWith("java:")) { + codeTag = codeTag.substring("java:".length()); + params.put("code", codeTag); + } + + // java_* aliases override older names: + // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-nav + ensureJavaPrefixTakesPrecedence(params, "code"); + ensureJavaPrefixTakesPrecedence(params, "codebase"); + ensureJavaPrefixTakesPrecedence(params, "archive"); + ensureJavaPrefixTakesPrecedence(params, "object"); + ensureJavaPrefixTakesPrecedence(params, "type"); + + return params; + } + + public String toString() { + return parameters.toString(); + } +}
\ No newline at end of file diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties index e74cf36..ed34397 100644 --- a/netx/net/sourceforge/jnlp/resources/Messages.properties +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties @@ -141,6 +141,7 @@ BFileLoc=JNLP file location BBadProp=Incorrect property format {0} (should be key=value)
BBadParam=Incorrect parameter format {0} (should be name=value)
BNoDir=Directory {0} does not exist.
+BNoCodeOrObjectApplet=Applet tag must specify a 'code' or 'object' attribute.
RNoResource=Missing Resource: {0}
RShutdown=This exception to prevent shutdown of JVM, but the process has been terminated.
RExitTaken=Exit class already set and caller is not exit class.
diff --git a/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties b/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties index 3fcbfbb..9663e19 100644 --- a/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties +++ b/netx/net/sourceforge/jnlp/resources/Messages_cs_CZ.properties @@ -139,6 +139,7 @@ BFileLoc=Um\u00edst\u011bn\u00ed souboru JNLP BBadProp=Neplatn\u00fd form\u00e1t vlastnosti {0} (platn\u00fd form\u00e1t: kl\u00ed\u010d=hodnota) BBadParam=Neplatn\u00fd form\u00e1t parametru {0} (platn\u00fd form\u00e1t: n\u00e1zev=hodnota) BNoDir=Adres\u00e1\u0159 {0} neexistuje. +BNoCodeOrObjectApplet=Zna\u010dka applet mus\u00ed m\u00edt defnov\u00e1n k\u00f3d nebo objekt - atributy 'code' nebo 'object' chyb\u00ed. RNoResource=Chyb\u011bj\u00edc\u00ed zdroj: {0} RShutdown=Tato v\u00fdjimka zabra\u0148uje ukon\u010den\u00ed prost\u0159ed\u00ed JVM, av\u0161ak proces byl ukon\u010den. RExitTaken=T\u0159\u00edda exit class m\u016f\u017ee b\u00fdt nastavena pouze jednou a pouze ta pak m\u016f\u017ee ukon\u010dit prost\u0159ed\u00ed JVM. diff --git a/plugin/icedteanp/IcedTeaNPPlugin.cc b/plugin/icedteanp/IcedTeaNPPlugin.cc index 302e791..19a04a2 100644 --- a/plugin/icedteanp/IcedTeaNPPlugin.cc +++ b/plugin/icedteanp/IcedTeaNPPlugin.cc @@ -229,8 +229,7 @@ static gboolean plugin_out_pipe_callback (GIOChannel* source, GIOCondition condition, gpointer plugin_data); static NPError plugin_start_appletviewer (ITNPPluginData* data); -static gchar* plugin_create_applet_tag (int16_t argc, char* argn[], - char* argv[]); +std::string plugin_parameters_string (int argc, char* argn[], char* argv[]); static void plugin_stop_appletviewer (); // Uninitialize ITNPPluginData structure static void plugin_data_destroy (NPP instance); @@ -347,7 +346,6 @@ ITNP_New (NPMIMEType pluginType, NPP instance, uint16_t mode, gchar* documentbase = NULL; gchar* read_message = NULL; - gchar* applet_tag = NULL; gchar* cookie_info = NULL; NPObject* npPluginObj = NULL; @@ -395,11 +393,10 @@ ITNP_New (NPMIMEType pluginType, NPP instance, uint16_t mode, documentbase = plugin_get_documentbase (instance); if (documentbase && argc != 0) { - // Send applet tag message to appletviewer. - applet_tag = plugin_create_applet_tag (argc, argn, argv); + // Send parameters to appletviewer. + std::string params_string = plugin_parameters_string(argc, argn, argv); - data->applet_tag = (gchar*) malloc(strlen(applet_tag)*sizeof(gchar) + strlen(documentbase)*sizeof(gchar) + 32); - g_sprintf(data->applet_tag, "tag %s %s", documentbase, applet_tag); + data->parameters_string = g_strdup_printf("tag %s %s", documentbase, params_string.c_str()); data->is_applet_instance = true; } @@ -424,33 +421,7 @@ ITNP_New (NPMIMEType pluginType, NPP instance, uint16_t mode, instance->pdata = data; - goto cleanup_done; - - cleanup_appletviewer_mutex: - g_mutex_free (data->appletviewer_mutex); - data->appletviewer_mutex = NULL; - - // cleanup_instance_string: - g_free (data->instance_id); - data->instance_id = NULL; - - // cleanup applet tag: - g_free (data->applet_tag); - data->applet_tag = NULL; - - // cleanup_data: - // Eliminate back-pointer to plugin instance. - data->owner = NULL; - (*browser_functions.memfree) (data); - data = NULL; - - // Initialization failed so return a NULL pointer for the browser - // data. - instance->pdata = NULL; - cleanup_done: - g_free (applet_tag); - applet_tag = NULL; g_free (read_message); read_message = NULL; g_free (documentbase); @@ -834,7 +805,7 @@ ITNP_SetWindow (NPP instance, NPWindow* window) // Now we have everything. Send this data to the Java side plugin_send_initialization_message( data->instance_id, (gulong) data->window_handle, - data->window_width, data->window_height, data->applet_tag); + data->window_width, data->window_height, data->parameters_string); g_mutex_unlock (data->appletviewer_mutex); @@ -1694,159 +1665,67 @@ plugin_start_appletviewer (ITNPPluginData* data) return error; } + /* - * Replaces certain characters (\r, \n, etc) with HTML escape equivalents. - * - * Return string is allocated on the heap. Caller assumes responsibility - * for freeing the memory via free() + * Escape characters for passing to Java. + * "\n" for new line, "\\" for "\", "\:" for ";" */ -static char* -encode_string(char* to_encode) -{ - - // Do nothing for an empty string - if (to_encode == '\0') - return to_encode; - - // worst case scenario -> all characters are newlines or - // returns, each of which translates to 5 substitutions - char* encoded = (char*) calloc(((strlen(to_encode)*5)+1), sizeof(char)); +std::string +escape_parameter_string(const char* to_encode) { + std::string encoded; - strcpy(encoded, ""); + if (to_encode == NULL) + { + return encoded; + } - for (int i=0; i < strlen(to_encode); i++) + size_t length = strlen(to_encode); + for (int i = 0; i < length; i++) { - if (to_encode[i] == '\r') - encoded = strcat(encoded, " "); - else if (to_encode[i] == '\n') - encoded = strcat(encoded, " "); - else if (to_encode[i] == '>') - encoded = strcat(encoded, ">"); - else if (to_encode[i] == '<') - encoded = strcat(encoded, "<"); - else if (to_encode[i] == '&') - encoded = strcat(encoded, "&"); - else if (to_encode[i] == '"') - encoded = strcat(encoded, """); + if (to_encode[i] == '\n') + encoded += "\\n"; + else if (to_encode[i] == '\\') + encoded += "\\\\"; + else if (to_encode[i] == ';') + encoded += "\\:"; else - { - char* orig_char = (char*) calloc(2, sizeof(char)); - orig_char[0] = to_encode[i]; - orig_char[1] = '\0'; - - strcat(encoded, orig_char); - - free(orig_char); - orig_char = NULL; - } + encoded += to_encode[i]; } return encoded; } -// Build up the applet tag string that we'll send to the applet -// viewer. -static gchar* -plugin_create_applet_tag (int16_t argc, char* argn[], char* argv[]) +/* + * Build a string containing an encoded list of parameters to send to the applet viewer. + * The parameters are separated as 'key1;value1;key2;value2;'. As well, they are + * separated and escaped as: + * "\n" for new line, "\\" for "\", "\:" for ";" + */ +std::string +plugin_parameters_string (int argc, char* argn[], char* argv[]) { - PLUGIN_DEBUG ("plugin_create_applet_tag\n"); - - gchar* applet_tag = g_strdup ("<EMBED "); - gchar* parameters = g_strdup (""); + PLUGIN_DEBUG ("plugin_parameters_string\n"); - for (int16_t i = 0; i < argc; i++) - { - gchar* argn_escaped = encode_string(argn[i]); - gchar* argv_escaped = encode_string(argv[i]); + std::string parameters; - if (!g_ascii_strcasecmp (argn_escaped, "code")) - { - gchar* code = g_strdup_printf ("CODE=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, code, NULL); - g_free (code); - code = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "java_code")) - { - gchar* java_code = g_strdup_printf ("JAVA_CODE=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, java_code, NULL); - g_free (java_code); - java_code = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "codebase")) - { - gchar* codebase = g_strdup_printf ("CODEBASE=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, codebase, NULL); - g_free (codebase); - codebase = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "java_codebase")) - { - gchar* java_codebase = g_strdup_printf ("JAVA_CODEBASE=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, java_codebase, NULL); - g_free (java_codebase); - java_codebase = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "classid")) - { - gchar* classid = g_strdup_printf ("CLASSID=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, classid, NULL); - g_free (classid); - classid = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "archive")) - { - gchar* archive = g_strdup_printf ("ARCHIVE=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, archive, NULL); - g_free (archive); - archive = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "java_archive")) - { - gchar* java_archive = g_strdup_printf ("JAVA_ARCHIVE=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, java_archive, NULL); - g_free (java_archive); - java_archive = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "width")) - { - gchar* width = g_strdup_printf ("width=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, width, NULL); - g_free (width); - width = NULL; - } - else if (!g_ascii_strcasecmp (argn_escaped, "height")) + for (int i = 0; i < argc; i++) + { + if (argv[i] != NULL) { - gchar* height = g_strdup_printf ("height=\"%s\" ", argv_escaped); - applet_tag = g_strconcat (applet_tag, height, NULL); - g_free (height); - height = NULL; - } - else - { - - if (argv_escaped != '\0') - { - parameters = g_strconcat (parameters, "<PARAM NAME=\"", argn_escaped, - "\" VALUE=\"", argv_escaped, "\">", NULL); - } - } - - free(argn_escaped); - free(argv_escaped); + std::string name_escaped = escape_parameter_string(argn[i]); + std::string value_escaped = escape_parameter_string(argv[i]); - argn_escaped = NULL; - argv_escaped = NULL; + //Encode parameters and send as 'key1;value1;key2;value2;' etc + parameters += name_escaped; + parameters += ';'; + parameters += value_escaped; + parameters += ';'; } + } - applet_tag = g_strconcat (applet_tag, ">", parameters, "</EMBED>", NULL); - - g_free (parameters); - parameters = NULL; - - PLUGIN_DEBUG ("plugin_create_applet_tag return\n"); + PLUGIN_DEBUG ("plugin_parameters_string return\n"); - return applet_tag; + return parameters; } // plugin_send_message_to_appletviewer must be called while holding @@ -2057,8 +1936,8 @@ plugin_data_destroy (NPP instance) tofree->instance_id = NULL; // cleanup applet tag - g_free (tofree->applet_tag); - tofree->applet_tag = NULL; + g_free (tofree->parameters_string); + tofree->parameters_string = NULL; g_free(tofree->source); tofree->source = NULL; @@ -2537,7 +2416,7 @@ get_scriptable_object(NPP instance) // a 0 handle if (!data->window_handle) { - plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->applet_tag); + plugin_send_initialization_message(data->instance_id, 0, 0, 0, data->parameters_string); } java_result = java_request.getAppletObjectInstance(id_str); diff --git a/plugin/icedteanp/IcedTeaNPPlugin.h b/plugin/icedteanp/IcedTeaNPPlugin.h index 187aede..d009e70 100644 --- a/plugin/icedteanp/IcedTeaNPPlugin.h +++ b/plugin/icedteanp/IcedTeaNPPlugin.h @@ -66,8 +66,8 @@ struct ITNPPluginData { // A unique identifier for this plugin window. gchar* instance_id; - // The applet tag sent to Java side - gchar* applet_tag; + // The parameter list string sent to Java side + gchar* parameters_string; // Mutex to protect appletviewer_alive. GMutex* appletviewer_mutex; // Back-pointer to the plugin instance to which this data belongs. diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java index f9d9422..611ed56 100644 --- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java +++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java @@ -70,7 +70,6 @@ import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.Insets; -import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; @@ -87,6 +86,7 @@ import java.lang.reflect.InvocationTargetException; import java.net.SocketPermission; import java.net.URI; import java.net.URL; +import java.net.URLConnection; import java.security.AccessController; import java.security.AllPermission; import java.security.PrivilegedAction; @@ -107,6 +107,7 @@ import java.util.concurrent.locks.ReentrantLock; import javax.swing.SwingUtilities; import net.sourceforge.jnlp.NetxPanel; +import net.sourceforge.jnlp.PluginParameters; import net.sourceforge.jnlp.runtime.JNLPClassLoader; import sun.awt.AppContext; import sun.awt.SunToolkit; @@ -129,14 +130,14 @@ class PluginAppletPanelFactory { public AppletPanel createPanel(PluginStreamHandler streamhandler, final int identifier, - final long handle, int x, int y, + final long handle, final URL doc, - final Hashtable<String, String> atts) { + final PluginParameters params) { final NetxPanel panel = AccessController.doPrivileged(new PrivilegedAction<NetxPanel>() { public NetxPanel run() { - NetxPanel panel = new NetxPanel(doc, atts, false); + NetxPanel panel = new NetxPanel(doc, params, false); NetxPanel.debug("Using NetX panel"); - PluginDebug.debug(atts.toString()); + PluginDebug.debug(params.toString()); return panel; } }); @@ -146,14 +147,13 @@ class PluginAppletPanelFactory { // isn't the case, the awt eventqueue thread's context classloader // won't be set to a JNLPClassLoader, and when an applet class needs // to be loaded from the awt eventqueue, it won't be found. - final int width = Integer.parseInt(atts.get("width")); - final int height = Integer.parseInt(atts.get("height")); Thread panelInit = new Thread(panel.getThreadGroup(), new Runnable() { @Override public void run() { panel.createNewAppContext(); // create the frame. - PluginDebug.debug("X and Y are: " + width + " " + height); - panel.setAppletViewerFrame(PluginAppletViewer.framePanel(identifier,handle, width, height, panel)); + PluginDebug.debug("X and Y are: " + params.getWidth() + " " + params.getHeight()); + panel.setAppletViewerFrame(PluginAppletViewer.framePanel(identifier, handle, + params.getWidth(), params.getHeight(), panel)); panel.init(); // Start the applet @@ -194,7 +194,7 @@ class PluginAppletPanelFactory { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { - panel.getParent().setSize(width, height); + panel.getParent().setSize(params.getWidth(), params.getHeight()); } }); } catch (InvocationTargetException ite) { @@ -599,18 +599,28 @@ public class PluginAppletViewer extends XEmbeddedFrame int spaceLocation = message.indexOf(' ', "tag".length() + 1); String documentBase = UrlUtil.decode(message.substring("tag".length() + 1, spaceLocation)); - String tag = message.substring(spaceLocation + 1); + String paramString = message.substring(spaceLocation + 1); PluginDebug.debug("Handle = ", handle, "\n", "Width = ", width, "\n", "Height = ", height, "\n", "DocumentBase = ", documentBase, "\n", - "Tag = ", tag); + "Params = ", paramString); - PluginAppletViewer.parse - (identifier, handle, width, height, - new StringReader(tag), - new URL(documentBase)); + PluginAppletPanelFactory factory = new PluginAppletPanelFactory(); + AppletMessageHandler amh = new AppletMessageHandler("appletviewer"); + URL url = new URL(documentBase); + URLConnection conn = url.openConnection(); + /* The original URL may have been redirected - this + * sets it to whatever URL/codebase we ended up getting + */ + url = conn.getURL(); + + PluginParameters params = new PluginParameterParser().parse(width, height, paramString); + + // Let user know we are starting up + streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start")); + factory.createPanel(streamhandler, identifier, handle, url, params); long maxTimeToSleep = APPLET_TIMEOUT; appletsLock.lock(); @@ -1546,24 +1556,6 @@ public class PluginAppletViewer extends XEmbeddedFrame } /** - * Decodes the string (converts html escapes into proper characters) - * - * @param toDecode The string to decode - * @return The decoded string - */ - public static String decodeString(String toDecode) { - - toDecode = toDecode.replace(">", ">"); - toDecode = toDecode.replace("<", "<"); - toDecode = toDecode.replace("&", "&"); - toDecode = toDecode.replace(" ", "\n"); - toDecode = toDecode.replace(" ", "\r"); - toDecode = toDecode.replace(""", "\""); - - return toDecode; - } - - /** * System parameters. */ static Hashtable<String, String> systemParam = new Hashtable<String, String>(); @@ -1580,76 +1572,14 @@ public class PluginAppletViewer extends XEmbeddedFrame } /** - * Print the HTML tag. - */ - public static void printTag(PrintStream out, Hashtable<String, String> atts) { - out.print("<applet"); - - String v = atts.get("codebase"); - if (v != null) { - out.print(" codebase=\"" + v + "\""); - } - - v = atts.get("code"); - if (v == null) { - v = "applet.class"; - } - out.print(" code=\"" + v + "\""); - v = atts.get("width"); - if (v == null) { - v = "150"; - } - out.print(" width=" + v); - - v = atts.get("height"); - if (v == null) { - v = "100"; - } - out.print(" height=" + v); - - v = atts.get("name"); - if (v != null) { - out.print(" name=\"" + v + "\""); - } - out.println(">"); - - // A very slow sorting algorithm - int len = atts.size(); - String params[] = new String[len]; - len = 0; - for (Enumeration<String> e = atts.keys(); e.hasMoreElements();) { - String param = e.nextElement(); - int i = 0; - for (; i < len; i++) { - if (params[i].compareTo(param) >= 0) { - break; - } - } - System.arraycopy(params, i, params, i + 1, len - i); - params[i] = param; - len++; - } - - for (int i = 0; i < len; i++) { - String param = params[i]; - if (systemParam.get(param) == null) { - out.println("<param name=" + param + - " value=\"" + atts.get(param) + "\">"); - } - } - out.println("</applet>"); - } - - /** * Make sure the atrributes are uptodate. */ public void updateAtts() { Dimension d = panel.getSize(); Insets in = panel.getInsets(); - panel.atts.put("width", - Integer.valueOf(d.width - (in.left + in.right)).toString()); - panel.atts.put("height", - Integer.valueOf(d.height - (in.top + in.bottom)).toString()); + int width = d.width - (in.left + in.right); + int height = d.height - (in.top + in.bottom); + panel.updateSizeInAtts(height, width); } /** @@ -1796,412 +1726,6 @@ public class PluginAppletViewer extends XEmbeddedFrame return appletPanels.size(); } - /** - * Scan spaces. - */ - public static void skipSpace(int[] c, Reader in) throws IOException { - while ((c[0] >= 0) && - ((c[0] == ' ') || (c[0] == '\t') || (c[0] == '\n') || (c[0] == '\r'))) { - c[0] = in.read(); - } - } - - /** - * Scan identifier - */ - public static String scanIdentifier(int[] c, Reader in) throws IOException { - StringBuilder buf = new StringBuilder(); - - if (c[0] == '!') { - // Technically, we should be scanning for '!--' but we are reading - // from a stream, and there is no way to peek ahead. That said, - // a ! at this point can only mean comment here afaik, so we - // should be okay - skipComment(c, in); - return ""; - } - - while (true) { - if (((c[0] >= 'a') && (c[0] <= 'z')) || - ((c[0] >= 'A') && (c[0] <= 'Z')) || - ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_')) { - buf.append((char) c[0]); - c[0] = in.read(); - } else { - return buf.toString(); - } - } - } - - public static void skipComment(int[] c, Reader in) throws IOException { - StringBuilder buf = new StringBuilder(); - boolean commentHeaderPassed = false; - c[0] = in.read(); - buf.append((char) c[0]); - - while (true) { - if (c[0] == '-' && (c[0] = in.read()) == '-') { - buf.append((char) c[0]); - if (commentHeaderPassed) { - // -- encountered ... is > next? - if ((c[0] = in.read()) == '>') { - buf.append((char) c[0]); - - PluginDebug.debug("Comment skipped: ", buf.toString()); - - // comment skipped. - return; - } - } else { - // first -- is part of <!-- ... , just mark that we have passed it - commentHeaderPassed = true; - } - - } else if (commentHeaderPassed == false) { - buf.append((char) c[0]); - PluginDebug.debug("Warning: Attempted to skip comment, but this tag does not appear to be a comment: ", buf.toString()); - return; - } - - c[0] = in.read(); - buf.append((char) c[0]); - } - } - - /** - * Scan tag - */ - public static Hashtable<String, String> scanTag(int[] c, Reader in) throws IOException { - Hashtable<String, String> atts = new Hashtable<String, String>(); - skipSpace(c, in); - while (c[0] >= 0 && c[0] != '>') { - String att = decodeString(scanIdentifier(c, in)); - String val = ""; - skipSpace(c, in); - if (c[0] == '=') { - int quote = -1; - c[0] = in.read(); - skipSpace(c, in); - if ((c[0] == '\'') || (c[0] == '\"')) { - quote = c[0]; - c[0] = in.read(); - } - StringBuilder buf = new StringBuilder(); - while ((c[0] > 0) && - (((quote < 0) && (c[0] != ' ') && (c[0] != '\t') && - (c[0] != '\n') && (c[0] != '\r') && (c[0] != '>')) - || ((quote >= 0) && (c[0] != quote)))) { - buf.append((char) c[0]); - c[0] = in.read(); - } - if (c[0] == quote) { - c[0] = in.read(); - } - skipSpace(c, in); - val = decodeString(buf.toString()); - } - - PluginDebug.debug("PUT ", att, " = '", val, "'"); - atts.put(att.toLowerCase(java.util.Locale.ENGLISH), val); - - while (true) { - if ((c[0] == '>') || (c[0] < 0) || - ((c[0] >= 'a') && (c[0] <= 'z')) || - ((c[0] >= 'A') && (c[0] <= 'Z')) || - ((c[0] >= '0') && (c[0] <= '9')) || (c[0] == '_')) - break; - c[0] = in.read(); - } - //skipSpace(in); - } - return atts; - } - - // private static final == inline - private static final boolean isInt(Object o) { - boolean isInt = false; - try { - Integer.parseInt((String) o); - isInt = true; - } catch (Exception e) { - // don't care - } - - return isInt; - } - - /* values used for placement of AppletViewer's frames */ - private static int x = 0; - private static int y = 0; - private static final int XDELTA = 30; - private static final int YDELTA = XDELTA; - - static String encoding = null; - - /** - * Scan an html file for <applet> tags - */ - public static void parse(int identifier, long handle, String width, String height, Reader in, URL url, String enc) - throws IOException { - encoding = enc; - parse(identifier, handle, width, height, in, url, System.out, new PluginAppletPanelFactory()); - } - - public static void parse(int identifier, long handle, String width, String height, Reader in, URL url) - throws PrivilegedActionException { - - final int fIdentifier = identifier; - final long fHandle = handle; - final String fWidth = width; - final String fHeight = height; - final Reader fIn = in; - final URL fUrl = url; - AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { - public Void run() throws IOException { - parse(fIdentifier, fHandle, fWidth, fHeight, fIn, fUrl, - System.out, new PluginAppletPanelFactory()); - return null; - } - }); - } - - @SuppressWarnings("unused") - public static void parse(int identifier, long handle, String width, - String height, Reader in, URL url, - PrintStream statusMsgStream, - PluginAppletPanelFactory factory) - throws IOException { - boolean isObjectTag = false; - boolean objectTagAlreadyParsed = false; - - // The current character - // FIXME: This is an evil hack to force pass-by-reference.. the - // parsing code needs to be rewritten from scratch to prevent such - //a need - int[] c = new int[1]; - - // warning messages - String requiresNameWarning = amh.getMessage("parse.warning.requiresname"); - String paramOutsideWarning = amh.getMessage("parse.warning.paramoutside"); - String appletRequiresCodeWarning = amh.getMessage("parse.warning.applet.requirescode"); - String appletRequiresHeightWarning = amh.getMessage("parse.warning.applet.requiresheight"); - String appletRequiresWidthWarning = amh.getMessage("parse.warning.applet.requireswidth"); - String objectRequiresCodeWarning = amh.getMessage("parse.warning.object.requirescode"); - String objectRequiresHeightWarning = amh.getMessage("parse.warning.object.requiresheight"); - String objectRequiresWidthWarning = amh.getMessage("parse.warning.object.requireswidth"); - String embedRequiresCodeWarning = amh.getMessage("parse.warning.embed.requirescode"); - String embedRequiresHeightWarning = amh.getMessage("parse.warning.embed.requiresheight"); - String embedRequiresWidthWarning = amh.getMessage("parse.warning.embed.requireswidth"); - String appNotLongerSupportedWarning = amh.getMessage("parse.warning.appnotLongersupported"); - - java.net.URLConnection conn = url.openConnection(); - /* The original URL may have been redirected - this - * sets it to whatever URL/codebase we ended up getting - */ - url = conn.getURL(); - - int ydisp = 1; - Hashtable<String, String> atts = null; - - while (true) { - c[0] = in.read(); - if (c[0] == -1) - break; - - if (c[0] == '<') { - c[0] = in.read(); - if (c[0] == '/') { - c[0] = in.read(); - String nm = scanIdentifier(c, in); - if (nm.equalsIgnoreCase("applet") || - nm.equalsIgnoreCase("object") || - nm.equalsIgnoreCase("embed")) { - - // We can't test for a code tag until </OBJECT> - // because it is a parameter, not an attribute. - if (isObjectTag) { - if (atts.get("code") == null && atts.get("object") == null) { - statusMsgStream.println(objectRequiresCodeWarning); - atts = null; - } - } - - if (atts != null) { - // XXX 5/18 In general this code just simply - // shouldn't be part of parsing. It's presence - // causes things to be a little too much of a - // hack. - - // Let user know we are starting up - streamhandler.write("instance " + identifier + " status " + amh.getMessage("status.start")); - factory.createPanel(streamhandler, identifier, handle, x, y, url, atts); - - x += XDELTA; - y += YDELTA; - // make sure we don't go too far! - Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); - if ((x > d.width - 300) || (y > d.height - 300)) { - x = 0; - y = 2 * ydisp * YDELTA; - ydisp++; - } - } - atts = null; - isObjectTag = false; - } - } else { - String nm = scanIdentifier(c, in); - if (nm.equalsIgnoreCase("param")) { - Hashtable<String, String> t = scanTag(c, in); - String att = t.get("name"); - - if (att == null) { - statusMsgStream.println(requiresNameWarning); - } else { - String val = t.get("value"); - if (val == null) { - statusMsgStream.println(requiresNameWarning); - } else { - PluginDebug.debug("PUT ", att, " = ", val); - atts.put(att.toLowerCase(), val); - } - } - } else if (nm.equalsIgnoreCase("applet")) { - atts = scanTag(c, in); - - // If there is a classid and no code tag present, transform it to code tag - if (atts.get("code") == null && atts.get("classid") != null - && !(atts.get("classid")).startsWith("clsid:")) { - atts.put("code", atts.get("classid")); - } - - // remove java: from code tag - if (atts.get("code") != null && (atts.get("code")).startsWith("java:")) { - atts.put("code", (atts.get("code")).substring(5)); - } - - if (atts.get("code") == null && atts.get("object") == null) { - statusMsgStream.println(appletRequiresCodeWarning); - atts = null; - } - - if (atts.get("width") == null || !isInt(atts.get("width"))) { - atts.put("width", width); - } - - if (atts.get("height") == null || !isInt(atts.get("height"))) { - atts.put("height", height); - } - } else if (nm.equalsIgnoreCase("object")) { - isObjectTag = true; - - // Once code is set, additional nested objects are ignored - if (!objectTagAlreadyParsed) { - objectTagAlreadyParsed = true; - atts = scanTag(c, in); - } - - // If there is a classid and no code tag present, transform it to code tag - if (atts.get("code") == null && atts.get("classid") != null - && !(atts.get("classid")).startsWith("clsid:")) { - atts.put("code", atts.get("classid")); - } - - // remove java: from code tag - if (atts.get("code") != null && (atts.get("code")).startsWith("java:")) { - atts.put("code", (atts.get("code")).substring(5)); - } - - // java_* aliases override older names: - // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-ie - if (atts.get("java_code") != null) { - atts.put("code", (atts.get("java_code"))); - } - - if (atts.containsKey("code")) { - objectTagAlreadyParsed = true; - } - - if (atts.get("java_codebase") != null) { - atts.put("codebase", (atts.get("java_codebase"))); - } - - if (atts.get("java_archive") != null) { - atts.put("archive", (atts.get("java_archive"))); - } - - if (atts.get("java_object") != null) { - atts.put("object", (atts.get("java_object"))); - } - - if (atts.get("java_type") != null) { - atts.put("type", (atts.get("java_type"))); - } - - if (atts.get("width") == null || !isInt(atts.get("width"))) { - atts.put("width", width); - } - - if (atts.get("height") == null || !isInt(atts.get("height"))) { - atts.put("height", height); - } - } else if (nm.equalsIgnoreCase("embed")) { - atts = scanTag(c, in); - - // If there is a classid and no code tag present, transform it to code tag - if (atts.get("code") == null && atts.get("classid") != null - && !(atts.get("classid")).startsWith("clsid:")) { - atts.put("code", atts.get("classid")); - } - - // remove java: from code tag - if (atts.get("code") != null && (atts.get("code")).startsWith("java:")) { - atts.put("code", (atts.get("code")).substring(5)); - } - - // java_* aliases override older names: - // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-nav - if (atts.get("java_code") != null) { - atts.put("code", (atts.get("java_code"))); - } - - if (atts.get("java_codebase") != null) { - atts.put("codebase", (atts.get("java_codebase"))); - } - - if (atts.get("java_archive") != null) { - atts.put("archive", (atts.get("java_archive"))); - } - - if (atts.get("java_object") != null) { - atts.put("object", (atts.get("java_object"))); - } - - if (atts.get("java_type") != null) { - atts.put("type", (atts.get("java_type"))); - } - - if (atts.get("code") == null && atts.get("object") == null) { - statusMsgStream.println(embedRequiresCodeWarning); - atts = null; - } - - if (atts.get("width") == null || !isInt(atts.get("width"))) { - atts.put("width", width); - } - - if (atts.get("height") == null || !isInt(atts.get("height"))) { - atts.put("height", height); - } - - } - } - } - } - in.close(); - } - - private static AppletMessageHandler amh = new AppletMessageHandler("appletviewer"); private static void checkConnect(URL url) { SecurityManager security = System.getSecurityManager(); diff --git a/plugin/icedteanp/java/sun/applet/PluginParameterParser.java b/plugin/icedteanp/java/sun/applet/PluginParameterParser.java new file mode 100644 index 0000000..9ce578f --- /dev/null +++ b/plugin/icedteanp/java/sun/applet/PluginParameterParser.java @@ -0,0 +1,90 @@ +package sun.applet; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import net.sourceforge.jnlp.PluginParameters; + +class PluginParameterParser { + static private final char DELIMITER_ESCAPE = ':'; + static private final String KEY_VALUE_DELIMITER = ";"; + + /** + * Unescape characters passed from C++. + * Specifically, "\n" -> new line, "\\" -> "\", "\:" -> ";" + * + * @param str The string to unescape + * @return The unescaped string + */ + static String unescapeString(String str) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < str.length(); i++) { + char chr = str.charAt(i); + if (chr != '\\') { + sb.append(chr); + } else { + i++; // Skip ahead one + chr = str.charAt(i); + if (chr == 'n') { + sb.append('\n'); + } else if (chr == '\\') { + sb.append('\\'); + } else if (chr == DELIMITER_ESCAPE) { + sb.append(KEY_VALUE_DELIMITER); + } + } + } + return sb.toString(); + } + + /** + * Parse semi-colon delimited key-value pairs. + * @param keyvalString the escaped, semicolon-delimited, string + * @return a map of the keys to the values + */ + static Map<String, String> parseEscapedKeyValuePairs(String keyvalString) { + // Split on ';', ensuring empty strings at end are kept + String[] strs = keyvalString.split(KEY_VALUE_DELIMITER, -1 /* Keep empty strings */); + System.out.println("Split array: " + Arrays.toString(strs)); + + Map<String, String> attributes = new HashMap<String, String>(); + + /* Note that we will typically have one empty string at end */ + for (int i = 0; i < strs.length - 1; i += 2) { + String key = unescapeString(strs[i]).toLowerCase(); + String value = unescapeString(strs[i + 1]); + attributes.put(key, value); + } + + return attributes; + } + + static boolean isInt(String s) { + return s.matches("^-?\\d+$"); + } + + /** + * Parsers parameters given a string containing + * parameters in quotes. + * + * @param width default applet width + * @param height default applet height + * @param parameterString the parameters + * @return the attributes in a hash table + */ + public PluginParameters parse(String width, + String height, String parameterString) { + Map<String, String> params = parseEscapedKeyValuePairs(parameterString); + + if (params.get("width") == null || !isInt(params.get("width"))) { + params.put("width", width); + } + + if (params.get("height") == null || !isInt(params.get("height"))) { + params.put("height", height); + } + + return new PluginParameters(params); + } +} diff --git a/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc b/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc index 9d77564..1ad1698 100644 --- a/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc +++ b/tests/cpp-unit-tests/IcedTeaPluginUtilsTest.cc @@ -48,7 +48,7 @@ TEST(NPVariantAsString) { STRINGZ_TO_NPVARIANT("test", var); std::string cppstr = IcedTeaPluginUtilities::NPVariantAsString(var); - CHECK(cppstr == "test"); + CHECK_EQUAL("test", cppstr); } diff --git a/tests/cpp-unit-tests/PluginParametersTest.cc b/tests/cpp-unit-tests/PluginParametersTest.cc new file mode 100644 index 0000000..e0136e4 --- /dev/null +++ b/tests/cpp-unit-tests/PluginParametersTest.cc @@ -0,0 +1,93 @@ +/* Copyright (C) 2012 Red Hat + + This file is part of IcedTea. + + IcedTea 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, or (at your option) + any later version. + + IcedTea 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. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + +/****************************************************************************** + * Unit tests for functions related to sending applet parameters * + * (key value pairs). * + ******************************************************************************/ + +#include <UnitTest++.h> + +#include "IcedTeaNPPlugin.h" + + +/* Not normally exposed */ +std::string escape_parameter_string(const char* to_encode); + +TEST(escape_parameter_string) { + CHECK_EQUAL("\\n", escape_parameter_string("\n")); + CHECK_EQUAL("\\\\", escape_parameter_string("\\")); + CHECK_EQUAL("\\:", escape_parameter_string(";")); + + CHECK_EQUAL(std::string("test") + "\\n" + "\\\\" + "\\:", + escape_parameter_string("test\n\\;")); +} + +/* Not normally exposed */ +std::string plugin_parameters_string(int argc, char* argn[], char* argv[]); + +TEST(plugin_parameters_string) { + + /* test empty */{ + const char* argn[] = { "" }; + const char* argv[] = { "" }; + CHECK_EQUAL("", + plugin_parameters_string(0, (char**)argn, (char**)argv)); + } + + /* test simple key & value */{ + const char* argn[] = { "key" }; + const char* argv[] = { "value" }; + CHECK_EQUAL("key;value;", + plugin_parameters_string(1, (char**)argn, (char**)argv)); + } + + /* test key & value characters that require escaping */{ + const char* argn[] = { "key\\" }; + const char* argv[] = { "value;" }; + CHECK_EQUAL("key\\\\;value\\:;", + plugin_parameters_string(1, (char**)argn, (char**)argv)); + } + + /* multiple key & value pairs that require escaping*/{ + const char* argn[] = { "key1\\", "key2\\" }; + const char* argv[] = { "value1;", "value2;" }; + CHECK_EQUAL("key1\\\\;value1\\:;key2\\\\;value2\\:;", + plugin_parameters_string(2, (char**)argn, (char**)argv)); + } +} + + diff --git a/tests/netx/unit/net/sourceforge/jnlp/PluginBridgeTest.java b/tests/netx/unit/net/sourceforge/jnlp/PluginBridgeTest.java index e9069f2..9015acf 100644 --- a/tests/netx/unit/net/sourceforge/jnlp/PluginBridgeTest.java +++ b/tests/netx/unit/net/sourceforge/jnlp/PluginBridgeTest.java @@ -29,6 +29,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import java.util.Hashtable; import java.util.List; import junit.framework.Assert; @@ -64,14 +65,20 @@ public class PluginBridgeTest { } } + static private PluginParameters createValidParamObject() { + Map<String, String> params = new HashMap<String, String>(); + params.put("code", ""); // Avoids an exception being thrown + return new PluginParameters(params); + } + @Test public void testAbsoluteJNLPHref() throws MalformedURLException, Exception { URL codeBase = new URL("http://undesired.absolute.codebase.com"); String absoluteLocation = "http://absolute.href.com/test.jnlp"; - Hashtable<String, String> atts = new Hashtable<String, String>(); - atts.put("jnlp_href", absoluteLocation); + PluginParameters params = createValidParamObject(); + params.put("jnlp_href", absoluteLocation); MockJNLPCreator mockCreator = new MockJNLPCreator(); - PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, atts, "", mockCreator); + PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, params, mockCreator); assertEquals(absoluteLocation, mockCreator.getJNLPHref().toExternalForm()); } @@ -79,12 +86,12 @@ public class PluginBridgeTest { public void testRelativeJNLPHref() throws MalformedURLException, Exception { URL codeBase = new URL("http://desired.absolute.codebase.com/"); String relativeLocation = "sub/dir/test.jnlp"; - Hashtable<String, String> atts = new Hashtable<String, String>(); - atts.put("jnlp_href", relativeLocation); + PluginParameters params = createValidParamObject(); + params.put("jnlp_href", relativeLocation); MockJNLPCreator mockCreator = new MockJNLPCreator(); - PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, atts, "", mockCreator); + PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, params, mockCreator); assertEquals(codeBase.toExternalForm() + relativeLocation, - mockCreator.getJNLPHref().toExternalForm()); + mockCreator.getJNLPHref().toExternalForm()); } @Test @@ -92,12 +99,12 @@ public class PluginBridgeTest { String desiredDomain = "http://desired.absolute.codebase.com"; URL codeBase = new URL(desiredDomain + "/undesired/sub/dir"); String relativeLocation = "/app/test/test.jnlp"; - Hashtable<String, String> atts = new Hashtable<String, String>(); - atts.put("jnlp_href", relativeLocation); + PluginParameters params = createValidParamObject(); + params.put("jnlp_href", relativeLocation); MockJNLPCreator mockCreator = new MockJNLPCreator(); - PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, atts, "", mockCreator); + PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, params, mockCreator); assertEquals(desiredDomain + relativeLocation, - mockCreator.getJNLPHref().toExternalForm()); + mockCreator.getJNLPHref().toExternalForm()); } @Test @@ -166,12 +173,12 @@ public class PluginBridgeTest { "ICAgICAgLz4NCiAgICAgICAgICAgIDwvam5scD4="; MockJNLPCreator mockCreator = new MockJNLPCreator(); - Hashtable<String, String> atts = new Hashtable<String, String>(); - atts.put("jnlp_href", relativeLocation); - atts.put("jnlp_embedded", jnlpFileEncoded); + PluginParameters params = createValidParamObject(); + params.put("jnlp_href", relativeLocation); + params.put("jnlp_embedded", jnlpFileEncoded); String jnlpCodebase = "http://www.redhat.com"; - PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, atts, "", mockCreator); + PluginBridge pb = new PluginBridge(codeBase, null, "", "", 0, 0, params, mockCreator); JARDesc[] jars = pb.getResources().getJARs(); //Check if there are two jars cached @@ -239,11 +246,11 @@ public class PluginBridgeTest { "ICAgICAgICAgICAgPC9qbmxwPg=="; MockJNLPCreator mockCreator = new MockJNLPCreator(); - Hashtable<String, String> atts = new Hashtable<String, String>(); - atts.put("jnlp_href", relativeLocation); - atts.put("jnlp_embedded", jnlpFileEncoded); + PluginParameters params = createValidParamObject(); + params.put("jnlp_href", relativeLocation); + params.put("jnlp_embedded", jnlpFileEncoded); - PluginBridge pb = new PluginBridge(overwrittenCodebase, null, "", "", 0, 0, atts, "", mockCreator); + PluginBridge pb = new PluginBridge(overwrittenCodebase, null, "", "", 0, 0, params, mockCreator); JARDesc[] jars = pb.getResources().getJARs(); //Check if there are two jars cached @@ -268,12 +275,12 @@ public class PluginBridgeTest { String jnlpFileEncoded = "thisContextIsInvalid"; MockJNLPCreator mockCreator = new MockJNLPCreator(); - Hashtable<String, String> atts = new Hashtable<String, String>(); - atts.put("jnlp_href", relativeLocation); - atts.put("jnlp_embedded", jnlpFileEncoded); + PluginParameters params = createValidParamObject(); + params.put("jnlp_href", relativeLocation); + params.put("jnlp_embedded", jnlpFileEncoded); try { - new PluginBridge(overwrittenCodebase, null, "", "", 0, 0, atts, "", mockCreator); + new PluginBridge(overwrittenCodebase, null, "", "", 0, 0, params, mockCreator); } catch (Exception e) { return; } diff --git a/tests/netx/unit/net/sourceforge/jnlp/PluginParametersTest.java b/tests/netx/unit/net/sourceforge/jnlp/PluginParametersTest.java new file mode 100644 index 0000000..0e05b53 --- /dev/null +++ b/tests/netx/unit/net/sourceforge/jnlp/PluginParametersTest.java @@ -0,0 +1,114 @@ +package net.sourceforge.jnlp; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.junit.Test; + +public class PluginParametersTest { + + @Test + public void testAttributeParseJavaPrefix() { + // java_* aliases override older names: + // http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/using_tags.html#in-nav + + Map<String, String> rawParams; + Hashtable<String, String> params; + + rawParams = new HashMap<String, String>(); + rawParams.put("code", "codeValue"); + rawParams.put("java_code", "java_codeValue"); + params = PluginParameters.createParameterTable(rawParams); + + assertEquals("java_codeValue", params.get("code")); + + rawParams = new HashMap<String, String>(); + rawParams.put("codebase", "codebaseValue"); + rawParams.put("java_codebase", "java_codebaseValue"); + params = PluginParameters.createParameterTable(rawParams); + + assertEquals("java_codebaseValue", params.get("codebase")); + + rawParams = new HashMap<String, String>(); + rawParams.put("archive", "archiveValue"); + rawParams.put("java_archive", "java_archiveValue"); + params = PluginParameters.createParameterTable(rawParams); + + assertEquals("java_archiveValue", params.get("archive")); + + rawParams = new HashMap<String, String>(); + rawParams.put("object", "objectValue"); + rawParams.put("java_object", "java_objectValue"); + params = PluginParameters.createParameterTable(rawParams); + + assertEquals("java_objectValue", params.get("object")); + + rawParams = new HashMap<String, String>(); + rawParams.put("type", "typeValue"); + rawParams.put("java_type", "java_typeValue"); + params = PluginParameters.createParameterTable(rawParams); + + assertEquals("java_typeValue", params.get("type")); + } + + @Test + public void testEnsureJavaPrefixTakesPrecedence() { + Map<String, String> params; + params = new HashMap<String, String>(); + params.put("test", "testValue"); + params.put("java_test", "java_testValue"); + PluginParameters.ensureJavaPrefixTakesPrecedence(params, "test"); + assertEquals("java_testValue", params.get("test")); + + params = new HashMap<String, String>(); + params.put("test", "testValue"); + PluginParameters.ensureJavaPrefixTakesPrecedence(params, "test"); + assertEquals("testValue", params.get("test")); + + params = new HashMap<String, String>(); + params.put("java_test", "java_testValue"); + PluginParameters.ensureJavaPrefixTakesPrecedence(params, "test"); + assertEquals("java_testValue", params.get("test")); + } + + @Test + public void testAttributeParseCodeAttribute() { + Map<String, String> rawParams; + Hashtable<String, String> params; + + // Simple test of object tag being set + rawParams = new HashMap<String, String>(); + rawParams.put("object", "objectValue"); + params = PluginParameters.createParameterTable(rawParams); + assertEquals("objectValue", params.get("object")); + + // Classid tag gets used as code tag + rawParams = new HashMap<String, String>(); + rawParams.put("classid", "classidValue"); + params = PluginParameters.createParameterTable(rawParams); + assertEquals("classidValue", params.get("code")); + + // Java: gets stripped from code tag + rawParams = new HashMap<String, String>(); + rawParams.put("code", "java:codeValue"); + params = PluginParameters.createParameterTable(rawParams); + assertEquals("codeValue", params.get("code")); + + // Classid tag gets used as code tag, and java: is stripped + rawParams = new HashMap<String, String>(); + rawParams.put("classid", "java:classidValue"); + params = PluginParameters.createParameterTable(rawParams); + assertEquals("classidValue", params.get("code")); + + // Classid tag gets used as code tag, and clsid: is stripped + rawParams = new HashMap<String, String>(); + rawParams.put("classid", "clsid:classidValue"); + params = PluginParameters.createParameterTable(rawParams); + assertEquals(null, params.get("code")); + + } + +} diff --git a/tests/netx/unit/sun/applet/PluginParameterParserTest.java b/tests/netx/unit/sun/applet/PluginParameterParserTest.java new file mode 100644 index 0000000..162d603 --- /dev/null +++ b/tests/netx/unit/sun/applet/PluginParameterParserTest.java @@ -0,0 +1,73 @@ +package sun.applet; + +import static org.junit.Assert.*; + +import java.util.Map; + +import net.sourceforge.jnlp.PluginParameters; + +import org.junit.Test; + +public class PluginParameterParserTest { + + @Test + public void testIsInt() { + assertFalse(PluginParameterParser.isInt("1.0")); + assertFalse(PluginParameterParser.isInt("abc")); + assertTrue(PluginParameterParser.isInt("1")); + } + + @Test + public void testUnescapeString() { + assertEquals("", PluginParameterParser.unescapeString("")); + assertEquals("\n", PluginParameterParser.unescapeString("\n")); + assertEquals("\\", PluginParameterParser.unescapeString("\\\\")); + assertEquals(";", PluginParameterParser.unescapeString("\\:")); + + assertEquals("test\n\\;", + PluginParameterParser.unescapeString("test" + "\\n" + "\\\\" + "\\:")); + + assertEquals("start\n;end\\;", + PluginParameterParser.unescapeString("start\\n\\:end\\\\;")); + } + + @Test + public void testParseEscapedKeyValuePairs() { + Map<String, String> params; + + params = PluginParameterParser.parseEscapedKeyValuePairs("key1;value1;KEY2\\:;value2\\\\;"); + assertEquals(params.size(), 2); + assertEquals(params.get("key1"), "value1"); + assertEquals(params.get("key2;"), "value2\\"); // ensure key is lowercased + + params = PluginParameterParser.parseEscapedKeyValuePairs(""); + assertEquals(params.size(), 0); + + params = PluginParameterParser.parseEscapedKeyValuePairs("key;;"); + assertEquals(params.size(), 1); + assertEquals(params.get("key"), ""); + + params = PluginParameterParser.parseEscapedKeyValuePairs(";value;"); + assertEquals(params.size(), 1); + assertEquals(params.get(""), "value"); + } + + @Test + public void testAttributeParseWidthHeightAttributes() { + final String width = "1", height = "1"; + final String codeKeyVal = "code;codeValue;"; + + PluginParameterParser parser = new PluginParameterParser(); + PluginParameters params; + + params = parser.parse(width, height, codeKeyVal); + assertEquals("1", params.get("width")); + assertEquals("1", params.get("height")); + + //Test that width height are defaulted to in case of not-a-number attributes: + params = parser.parse(width, height, codeKeyVal + " width;NAN;height;NAN;"); + assertEquals("1", params.get("width")); + assertEquals("1", params.get("height")); + } + +} |