1 /*
   2  * Copyright (c) 2017, 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.xerces.internal.dom;
  22 
  23 import java.util.ArrayList;
  24 import java.util.List;
  25 import java.util.StringTokenizer;
  26 import org.w3c.dom.DOMImplementation;
  27 import org.w3c.dom.DOMImplementationList;
  28 import org.w3c.dom.DOMImplementationSource;
  29 
  30 /**
  31  * Supply one the right implementation, based upon requested features. Each
  32  * implemented <code>DOMImplementationSource</code> object is listed in the
  33  * binding-specific list of available sources so that its
  34  * <code>DOMImplementation</code> objects are made available.
  35  *
  36  * <p>See also the
  37  * <a href='http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMImplementationSource'>
  38  * Document Object Model (DOM) Level 3 Core Specification</a>.
  39  *
  40  * @xerces.internal
  41  *
  42  * @LastModified: Oct 2017
  43  */
  44 public class DOMImplementationSourceImpl
  45     implements DOMImplementationSource {
  46 
  47     /**
  48      * A method to request a DOM implementation.
  49      * @param features A string that specifies which features are required.
  50      *   This is a space separated list in which each feature is specified
  51      *   by its name optionally followed by a space and a version number.
  52      *   This is something like: "XML 1.0 Traversal Events 2.0"
  53      * @return An implementation that has the desired features, or
  54      *   <code>null</code> if this source has none.
  55      */
  56     public DOMImplementation getDOMImplementation(String features) {
  57         // first check whether the CoreDOMImplementation would do
  58         DOMImplementation impl =
  59             CoreDOMImplementationImpl.getDOMImplementation();
  60         if (testImpl(impl, features)) {
  61             return impl;
  62         }
  63         // if not try the DOMImplementation
  64         impl = DOMImplementationImpl.getDOMImplementation();
  65         if (testImpl(impl, features)) {
  66             return impl;
  67         }
  68 
  69         return null;
  70     }
  71 
  72     /**
  73      * A method to request a list of DOM implementations that support the
  74      * specified features and versions, as specified in .
  75      * @param features A string that specifies which features and versions
  76      *   are required. This is a space separated list in which each feature
  77      *   is specified by its name optionally followed by a space and a
  78      *   version number. This is something like: "XML 3.0 Traversal +Events
  79      *   2.0"
  80      * @return A list of DOM implementations that support the desired
  81      *   features.
  82      */
  83     public DOMImplementationList getDOMImplementationList(String features) {
  84         // first check whether the CoreDOMImplementation would do
  85         DOMImplementation impl = CoreDOMImplementationImpl.getDOMImplementation();
  86         final List<DOMImplementation> implementations = new ArrayList<>();
  87         if (testImpl(impl, features)) {
  88             implementations.add(impl);
  89         }
  90         impl = DOMImplementationImpl.getDOMImplementation();
  91         if (testImpl(impl, features)) {
  92             implementations.add(impl);
  93         }
  94 
  95         return new DOMImplementationListImpl(implementations);
  96     }
  97 
  98     boolean testImpl(DOMImplementation impl, String features) {
  99 
 100         StringTokenizer st = new StringTokenizer(features);
 101         String feature = null;
 102         String version = null;
 103 
 104         if (st.hasMoreTokens()) {
 105            feature = st.nextToken();
 106         }
 107         while (feature != null) {
 108            boolean isVersion = false;
 109            if (st.hasMoreTokens()) {
 110                char c;
 111                version = st.nextToken();
 112                c = version.charAt(0);
 113                switch (c) {
 114                case '0': case '1': case '2': case '3': case '4':
 115                case '5': case '6': case '7': case '8': case '9':
 116                    isVersion = true;
 117                }
 118            } else {
 119                version = null;
 120            }
 121            if (isVersion) {
 122                if (!impl.hasFeature(feature, version)) {
 123                    return false;
 124                }
 125                if (st.hasMoreTokens()) {
 126                    feature = st.nextToken();
 127                } else {
 128                    feature = null;
 129                }
 130            } else {
 131                if (!impl.hasFeature(feature, null)) {
 132                    return false;
 133                }
 134                feature = version;
 135            }
 136         }
 137         return true;
 138     }
 139 }