Package org.apache.shindig.gadgets.parse.caja

Source Code of org.apache.shindig.gadgets.parse.caja.CajaCssUtils

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.shindig.gadgets.parse.caja;

import com.google.caja.parser.AncestorChain;
import com.google.caja.parser.Visitor;
import com.google.caja.parser.css.CssTree;
import com.google.common.collect.Lists;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Utility functions for traversing Caja's CSS DOM
*/
public final class CajaCssUtils {
  private CajaCssUtils() {}
 
  /**
   * Get the immediate children of the passed node with the specified node type
   */
  public static <T extends CssTree> List<T> children(CssTree node, Class<T> nodeType) {
    List<T> result = Lists.newArrayList();
    for (CssTree child : node.children()) {
      if (nodeType.isAssignableFrom(child.getClass())) {
        result.add(nodeType.cast(child));
      }
    }
    return result;
  }

  /**
   * Get all descendants of the passed node with the specified node type
   */
  public static <T extends CssTree> List<T> descendants(CssTree node, final Class<T> nodeType) {
    final List<T> descendants = Lists.newArrayList();
    node.acceptPreOrder(new Visitor() {
      public boolean visit(AncestorChain<?> ancestorChain) {
        if (nodeType.isAssignableFrom(ancestorChain.node.getClass())) {
          descendants.add(nodeType.cast(ancestorChain.node));
        }
        return true;
      }
    }, null);
    return descendants;
  }

  /**
   * Changes problematic ip6 uris in StyleSheet per indexes before DOM object is serialized.
   * Indexes follow pattern "ipv6i0f", "ipv6i1f", ..., "ipv6iNf".
   *
   * @param styleSheet StyleSheet object representing a CSS DOM to extract ip6 explicit uris
   * @param ip6Uris List of Strings where ip6 uris will be stored
   */
  public static void saveIp6Uris(CssTree.StyleSheet styleSheet, List<String> ip6Uris) {
    if (styleSheet == null || ip6Uris == null) {
        // This case should not happen
        return;
    }
    List<CssTree.UriLiteral> uris = descendants(styleSheet, CssTree.UriLiteral.class);
    for (CssTree.UriLiteral uri : uris) {
        String sUri = uri.getValue();
        String ip6 = extractIp6(sUri);
        if (ip6 != null) {
            int count = ip6Uris.indexOf(ip6);
            if (count == -1) {
                ip6Uris.add(ip6);
                count = ip6Uris.size() - 1;
            }
            String index = "ipv6i" + count + "f";
            uri.setValue(sUri.replace(ip6, index));
        }
    }
  }

  /**
   * Restores original ip6 uris in serialized StyleSheet DOM.
   * Searches patterns "ipv6i0f", "ipv6i1f", ..., "ipv6iNf" and changes them by original ip6 uris.
   *
   * @param styleSheet String representation of StyleSheet object serialized
   * @param ip6Uris List of String with ip6 uris to restore
   * @return String representation of StyleSheet updated with ip6 uris
   */
  public static String restoreIp6Uris(String styleSheet, List<String> ip6Uris) {
    if (ip6Uris == null || ip6Uris.size() == 0) {
        return styleSheet;
    }

    int length = styleSheet.length();
    int i = 0;
    int startToken = -1;
    int finishToken = -1;
    boolean finish = false;
    StringBuilder output = new StringBuilder();

    while (!finish) {
        boolean found = false;
        Character ch = styleSheet.charAt(i);
        // Checks if there is a pattern under present position
        if (ch.equals('i') &&
            ((i+1) < length) && styleSheet.charAt(i+1) == 'p' &&
            ((i+2) < length) && styleSheet.charAt(i+2) == 'v' &&
            ((i+3) < length) && styleSheet.charAt(i+3) == '6' &&
            ((i+4) < length) && styleSheet.charAt(i+4) == 'i') {
            // Search end of token
            boolean numbers = true;
            startToken = i;
            finishToken = i + 5;
            while (numbers) {
                if (finishToken < length &&
                    styleSheet.charAt(finishToken) >= '0' &&
                    styleSheet.charAt(finishToken) <= '9') {
                    finishToken++;
                } else {
                    numbers = false;
                }
            }
            if (finishToken < length &&
                styleSheet.charAt(finishToken) == 'f') {
                String token = styleSheet.substring(startToken, finishToken);
                int index = -1;
                try {
                    index = new Integer(token.substring(5, token.length()));
                } catch (Exception e) {
                    // Not a number
                }
                if (index > -1 && index < ip6Uris.size() ) {
                    output.append(ip6Uris.get(index));
                    found = true;
                    i = finishToken;
                }
            }
        }
        if (!found) {
            output.append(ch);
        }
        i++;
        if (i >= length) {
            finish = true;
        }
    }

    return output.toString();
  }

  /**
   * Validates sUri has a explicit ip6 authority.
   *
   * @param sUri String with normalized uri in the form http:// or https://
   * @return null if not explicit ip6 or host if explicit ip6 found
   */
  public static String extractIp6(String sUri) {
    if (sUri == null ||
        sUri.length() < 7 ||
        !sUri.startsWith("http")) {
        return null;
    }
    int beginFrom;
    if (sUri.charAt(4) == ':') {
        // http://
        beginFrom = 7;
    } else if (sUri.charAt(4) == 's') {
        // https://
        beginFrom = 8;
    } else {
        return null;
    }
    int firstSlash = sUri.indexOf('/', beginFrom);
    if (firstSlash == -1) firstSlash = sUri.length();
    String authority = sUri.substring(beginFrom, firstSlash);
    int lastColon = authority.lastIndexOf(':');
    if (lastColon == -1) {
        return null;
    } else {
        int openBracket = authority.lastIndexOf('[');
        if (openBracket == -1) {
            String untilColon = authority.substring(0, lastColon);
            boolean moreColons = untilColon.lastIndexOf(':') > -1;
            if (moreColons) {
                return authority;
            } else {
                return null;
            }
        } else {
            int closeBracket = authority.lastIndexOf(']');
            return authority.substring(openBracket, closeBracket + 1);
        }
    }
  }
}
TOP

Related Classes of org.apache.shindig.gadgets.parse.caja.CajaCssUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.