1 /*
   2  * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xml.internal.serializer;
  22 
  23 import java.util.Properties;
  24 import javax.xml.transform.OutputKeys;
  25 import jdk.xml.internal.SecuritySupport;
  26 
  27 /**
  28  * This class is a factory to generate a set of default properties
  29  * of key/value pairs that are used to create a serializer through the
  30  * factory {@link SerializerFactory SerilizerFactory}.
  31  * The properties generated by this factory
  32  * may be modified to non-default values before the SerializerFactory is used to
  33  * create a Serializer.
  34  * <p>
  35  * The given output types supported are "xml", "text", and "html".
  36  * These type strings can be obtained from the
  37  * {@link Method Method} class in this package.
  38  * <p>
  39  * Other constants defined in this class are the non-standard property keys
  40  * that can be used to set non-standard property values on a java.util.Properties object
  41  * that is used to create or configure a serializer. Here are the non-standard keys:
  42  * <ul>
  43  * <li> <b>S_KEY_INDENT_AMOUNT </b> -
  44  * The non-standard property key to use to set the indentation amount.
  45  * The "indent" key needs to have a value of "yes", and this
  46  * properties value is a the number of whitespaces to indent by per
  47  * indentation level.
  48  *
  49  * <li> <b>S_KEY_CONTENT_HANDLER </b> -
  50  * This non-standard property key is used to set the name of the fully qualified
  51  * Java class that implements the ContentHandler interface.
  52  * The output of the serializer will be SAX events sent to this an
  53  * object of this class.
  54  *
  55  * <li> <b>S_KEY_ENTITIES </b> -
  56  * This non-standard property key is used to specify the name of the property file
  57  * that specifies character to entity reference mappings. A line in such a
  58  * file is has the name of the entity and the numeric (base 10) value
  59  * of the corresponding character, like this one: <br> quot=34 <br>
  60  *
  61  * <li> <b>S_USE_URL_ESCAPING </b> -
  62  * This non-standard property key is used to set a value of "yes" if the href values
  63  * for HTML serialization should use %xx escaping.
  64  *
  65  * <li> <b>S_OMIT_META_TAG </b> -
  66  * This non-standard property key is used to set a value of "yes" if the META tag
  67  * should be omitted where it would otherwise be supplied.
  68  * </ul>
  69  *
  70  * @see SerializerFactory
  71  * @see Method
  72  * @see Serializer
  73  * @LastModified: Mar 2019
  74  */
  75 public final class OutputPropertiesFactory
  76 {
  77     /** S_BUILTIN_EXTENSIONS_URL is a mnemonic for the XML Namespace
  78      *(http://xml.apache.org/xalan) predefined to signify Xalan's
  79      * built-in XSLT Extensions. When used in stylesheets, this is often
  80      * bound to the "xalan:" prefix.
  81      */
  82     private static final String
  83       S_BUILTIN_EXTENSIONS_URL = "http://xml.apache.org/xalan";
  84 
  85     /**
  86      * The old built-in extension url. It is still supported for
  87      * backward compatibility.
  88      */
  89     private static final String
  90       S_BUILTIN_OLD_EXTENSIONS_URL = "http://xml.apache.org/xslt";
  91 
  92     //************************************************************
  93     //*  PUBLIC CONSTANTS
  94     //************************************************************
  95     /**
  96      * This is not a public API.
  97      * This is the built-in extensions namespace,
  98      * reexpressed in {namespaceURI} syntax
  99      * suitable for prepending to a localname to produce a "universal
 100      * name".
 101      */
 102     public static final String S_BUILTIN_EXTENSIONS_UNIVERSAL =
 103         "{" + S_BUILTIN_EXTENSIONS_URL + "}";
 104 
 105     // Some special Xalan keys.
 106 
 107     /**
 108      * The non-standard property key to use to set the
 109      * number of whitepaces to indent by, per indentation level,
 110      * if indent="yes".
 111      */
 112     public static final String S_KEY_INDENT_AMOUNT =
 113         S_BUILTIN_EXTENSIONS_UNIVERSAL + "indent-amount";
 114 
 115     /**
 116      * The non-standard property key to use to set the
 117      * number of whitepaces to indent by, per indentation level,
 118      * if indent="yes".
 119      */
 120     public static final String S_KEY_LINE_SEPARATOR =
 121         S_BUILTIN_EXTENSIONS_UNIVERSAL + "line-separator";
 122 
 123     /** This non-standard property key is used to set the name of the fully qualified
 124      * Java class that implements the ContentHandler interface.
 125      * Fully qualified name of class with a default constructor that
 126      *  implements the ContentHandler interface, where the result tree events
 127      *  will be sent to.
 128      */
 129 
 130     public static final String S_KEY_CONTENT_HANDLER =
 131         S_BUILTIN_EXTENSIONS_UNIVERSAL + "content-handler";
 132 
 133     /**
 134      * This non-standard property key is used to specify the name of the property file
 135      * that specifies character to entity reference mappings.
 136      */
 137     public static final String S_KEY_ENTITIES =
 138         S_BUILTIN_EXTENSIONS_UNIVERSAL + "entities";
 139 
 140     /**
 141      * This non-standard property key is used to set a value of "yes" if the href
 142      * values for HTML serialization should use %xx escaping.
 143      */
 144     public static final String S_USE_URL_ESCAPING =
 145         S_BUILTIN_EXTENSIONS_UNIVERSAL + "use-url-escaping";
 146 
 147     /**
 148      * This non-standard property key is used to set a value of "yes" if the META
 149      * tag should be omitted where it would otherwise be supplied.
 150      */
 151     public static final String S_OMIT_META_TAG =
 152         S_BUILTIN_EXTENSIONS_UNIVERSAL + "omit-meta-tag";
 153 
 154     /**
 155      * The old built-in extension namespace, this is not a public API.
 156      */
 157     public static final String S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL =
 158         "{" + S_BUILTIN_OLD_EXTENSIONS_URL + "}";
 159 
 160     /**
 161      * This is not a public API, it is only public because it is used
 162      * by outside of this package,
 163      * it is the length of the old built-in extension namespace.
 164      */
 165     public static final int S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL_LEN =
 166         S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL.length();
 167 
 168     /**
 169      * This non-standard, Oracle-impl only property key is used as if
 170      * OutputKeys.STANDALONE is specified but without writing it out in the declaration;
 171      * It can be used to reverse the change by Xalan patch 1495.
 172      * Since Xalan patch 1495 can cause incompatible behavior, this property is
 173      * added for application to neutralize the effect of Xalan patch 1495
 174      */
 175     /**
 176      * <p>Is Standalone</p>
 177      *
 178      * <ul>
 179      *   <li>
 180      *     <code>yes</code> to indicate the output is intended to be used as standalone
 181      *   </li>
 182      *   <li>
 183      *     <code>no</code> has no effect.
 184      *   </li>
 185      * </ul>
 186      */
 187     public static final String ORACLE_IS_STANDALONE = "http://www.oracle.com/xml/is-standalone";
 188 
 189     //************************************************************
 190     //*  PRIVATE CONSTANTS
 191     //************************************************************
 192 
 193     /*
 194      * XSLT properties do not need namespace qualification.
 195      *
 196      * Xalan-specific output properties can be overridden in the stylesheet
 197      * assigning a xalan namespace.  For example:
 198      * <xsl:stylesheet version="1.0"
 199      *          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 200      *          xmlns:xalan="http://xml.apache.org/xalan">
 201      *  <xsl:output method="html" encoding="UTF-8"
 202      *              xalan:content-handler="MyContentHandler"/>
 203      *  ...
 204      */
 205     private static final String[] PROP_XML = {
 206         "method",
 207         "version",
 208         "encoding",
 209         "indent",
 210         "omit-xml-declaration",
 211         "standalone",
 212         "media-type",
 213         "{http://xml.apache.org/xalan}indent-amount",
 214         "{http://xml.apache.org/xalan}content-handler",
 215         "{http://xml.apache.org/xalan}entities"
 216     };
 217 
 218     private static final String[] PROP_XML_VALUE = {
 219         "xml",
 220         "1.0",
 221         "UTF-8",
 222         "no",
 223         "no",
 224         "no",
 225         "text/xml",
 226         "0",
 227         "com.sun.org.apache.xml.internal.serializer.ToXMLStream",
 228         "com/sun/org/apache/xml/internal/serializer/XMLEntities"
 229     };
 230 
 231     private static final String[] PROP_HTML = {
 232         "method",
 233         "indent",
 234         "media-type",
 235         "version",
 236         "{http://xml.apache.org/xalan}indent-amount",
 237         "{http://xml.apache.org/xalan}content-handler",
 238         "{http://xml.apache.org/xalan}entities",
 239         "{http://xml.apache.org/xalan}use-url-escaping",
 240         "{http://xml.apache.org/xalan}omit-meta-tag"
 241     };
 242 
 243     private static final String[] PROP_HTML_VALUE = {
 244         "html",
 245         "yes",
 246         "text/html",
 247         "4.0",
 248         "4",
 249         "com.sun.org.apache.xml.internal.serializer.ToHTMLStream",
 250         "com/sun/org/apache/xml/internal/serializer/HTMLEntities",
 251         "yes",
 252         "no"
 253     };
 254 
 255     private static final String[] PROP_TEXT = {
 256         "method",
 257         "media-type",
 258         "{http://xml.apache.org/xalan}content-handler"
 259     };
 260 
 261     private static final String[] PROP_TEXT_VALUE = {
 262         "text",
 263         "text/plain",
 264         "com.sun.org.apache.xml.internal.serializer.ToTextStream"
 265     };
 266 
 267     private static final String[] PROP_UNKNOWN = {
 268         "method",
 269         "version",
 270         "encoding",
 271         "indent",
 272         "omit-xml-declaration",
 273         "standalone",
 274         "media-type",
 275         "{http://xml.apache.org/xalan}indent-amount",
 276         "{http://xml.apache.org/xalan}content-handler"
 277     };
 278 
 279     private static final String[] PROP_UNKNOWN_VALUE = {
 280         "xml",
 281         "1.0",
 282         "UTF-8",
 283         "no",
 284         "no",
 285         "no",
 286         "text/xml",
 287         "0",
 288         "com.sun.org.apache.xml.internal.serializer.ToUnknownStream",
 289     };
 290 
 291     //************************************************************
 292     //*  PRIVATE STATIC FIELDS
 293     //************************************************************
 294 
 295     /** The default properties for all other than html and text. */
 296     private static Properties m_xml_properties = null;
 297 
 298     /** The default properties when method="html". */
 299     private static Properties m_html_properties = null;
 300 
 301     /** The default properties when method="text". */
 302     private static Properties m_text_properties = null;
 303 
 304     /** The properties when method="" for the "unknown" wrapper */
 305     private static Properties m_unknown_properties = null;
 306 
 307     /**
 308      * Returns a Properties based on the specified method. The default is xml.
 309      *
 310      * @param   method non-null reference to method name.
 311      *
 312      * @return Properties object that holds the defaults for the given method.
 313      */
 314     static public final Properties getDefaultMethodProperties(String method)
 315     {
 316         Properties defaultProperties = null;
 317 
 318         if (null == m_xml_properties) {
 319             m_xml_properties = initProperties(PROP_XML, PROP_XML_VALUE, null);
 320         }
 321 
 322 
 323         switch (method) {
 324             case Method.XML:
 325                 defaultProperties = m_xml_properties;
 326                 break;
 327             case Method.HTML:
 328                 if (null == m_html_properties) {
 329                     m_html_properties = initProperties(
 330                             PROP_HTML, PROP_HTML_VALUE, m_xml_properties);
 331                 }
 332                 defaultProperties = m_html_properties;
 333                 break;
 334             case Method.TEXT:
 335                 if (null == m_text_properties) {
 336                     m_text_properties = initProperties(
 337                             PROP_TEXT, PROP_TEXT_VALUE, m_xml_properties);
 338 
 339                     if (null == m_text_properties.getProperty(OutputKeys.ENCODING))
 340                     {
 341                         String mimeEncoding = Encodings.getMimeEncoding(null);
 342                         m_text_properties.put(OutputKeys.ENCODING, mimeEncoding);
 343                     }
 344                 }
 345                 defaultProperties = m_text_properties;
 346                 break;
 347             case com.sun.org.apache.xml.internal.serializer.Method.UNKNOWN:
 348                 if (null == m_unknown_properties) {
 349                     m_unknown_properties = initProperties(
 350                             PROP_UNKNOWN, PROP_UNKNOWN_VALUE, m_xml_properties);
 351                 }
 352                 defaultProperties = m_unknown_properties;
 353                 break;
 354             default:
 355                 defaultProperties = m_xml_properties;
 356                 break;
 357         }
 358 
 359         // wrap these cached defaultProperties in a new Property object just so
 360         // that the caller of this method can't modify the default values
 361         return new Properties(defaultProperties);
 362     }
 363 
 364     /**
 365      * Initiates the properties
 366      *
 367      * @param keys an array of keys
 368      * @param values values corresponding to the keys
 369      * @param defaults Default properties, which may be null.
 370      */
 371     static private Properties initProperties(String[] keys, String[] values, Properties defaults)
 372     {
 373         Properties props = new Properties(defaults);
 374 
 375         for (int i = 0; i < keys.length; i++) {
 376             // check System Property. This is kept as is for binary compatibility
 377             String sys = SecuritySupport.getSystemProperty(keys[i]);
 378             props.put(keys[i], (sys == null) ? values[i] : sys);
 379         }
 380 
 381         return props;
 382     }
 383 }