Package org.apache.commons.vfs.provider

Source Code of org.apache.commons.vfs.provider.UriParser

/*
* Copyright 2002-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.vfs.provider;

import org.apache.commons.vfs.FileName;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileType;
import org.apache.commons.vfs.VFS;

/**
* Utilities for dealing with URIs. See RFC 2396 for details.
*
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
* @version $Revision: 1.4 $ $Date: 2005-10-13 21:11:33 +0200 (Do, 13 Okt
*          2005) $
*/
public final class UriParser
{
  /**
   * The normalised separator to use.
   */
  private static final char SEPARATOR_CHAR = FileName.SEPARATOR_CHAR;

  /**
   * The set of valid separators. These are all converted to the normalised
   * one. Does <i>not</i> contain the normalised separator
   */
  // public static final char[] separators = {'\\'};
  public static final char TRANS_SEPARATOR = '\\';

  private UriParser()
  {
  }

  /**
   * Extracts the first element of a path.
   */
  public static String extractFirstElement(final StringBuffer name)
  {
    final int len = name.length();
    if (len < 1)
    {
      return null;
    }
    int startPos = 0;
    if (name.charAt(0) == SEPARATOR_CHAR)
    {
      startPos = 1;
    }
    for (int pos = startPos; pos < len; pos++)
    {
      if (name.charAt(pos) == SEPARATOR_CHAR)
      {
        // Found a separator
        final String elem = name.substring(startPos, pos);
        name.delete(startPos, pos + 1);
        return elem;
      }
    }

    // No separator
    final String elem = name.substring(startPos);
    name.setLength(0);
    return elem;
  }

  /**
   * Normalises a path. Does the following:
   * <ul>
   * <li>Removes empty path elements.
   * <li>Handles '.' and '..' elements.
   * <li>Removes trailing separator.
   * </ul>
   *
   * Its assumed that the separators are already fixed.
   *
   *  @see #fixSeparators
   */
  public static FileType normalisePath(final StringBuffer path)
      throws FileSystemException
  {
    FileType fileType = FileType.FOLDER;
    if (path.length() == 0)
    {
      return fileType;
    }

    if (path.charAt(path.length() - 1) != '/')
    {
      fileType = FileType.FILE;
    }

    // Adjust separators
    // fixSeparators(path);

    // Determine the start of the first element
    int startFirstElem = 0;
    if (path.charAt(0) == SEPARATOR_CHAR)
    {
      if (path.length() == 1)
      {
        return fileType;
      }
      startFirstElem = 1;
    }

    // Iterate over each element
    int startElem = startFirstElem;
    int maxlen = path.length();
    while (startElem < maxlen)
    {
      // Find the end of the element
      int endElem = startElem;
      for (; endElem < maxlen && path.charAt(endElem) != SEPARATOR_CHAR; endElem++)
      {
      }

      final int elemLen = endElem - startElem;
      if (elemLen == 0)
      {
        // An empty element - axe it
        path.delete(endElem, endElem + 1);
        maxlen = path.length();
        continue;
      }
      if (elemLen == 1 && path.charAt(startElem) == '.')
      {
        // A '.' element - axe it
        path.delete(startElem, endElem + 1);
        maxlen = path.length();
        continue;
      }
      if (elemLen == 2 && path.charAt(startElem) == '.'
          && path.charAt(startElem + 1) == '.')
      {
        // A '..' element - remove the previous element
        if (startElem == startFirstElem)
        {
          // Previous element is missing
          throw new FileSystemException(
              "vfs.provider/invalid-relative-path.error");
        }

        // Find start of previous element
        int pos = startElem - 2;
        for (; pos >= 0 && path.charAt(pos) != SEPARATOR_CHAR; pos--)
        {
        }
        startElem = pos + 1;

        path.delete(startElem, endElem + 1);
        maxlen = path.length();
        continue;
      }

      // A regular element
      startElem = endElem + 1;
    }

    // Remove trailing separator
    if (!VFS.isUriStyle())
    {
      if (maxlen > 0 && path.charAt(maxlen - 1) == SEPARATOR_CHAR
          && maxlen > 1)
      {
        path.delete(maxlen - 1, maxlen);
      }
    }

    return fileType;
  }

  /**
   * Normalises the separators in a name.
   */
  public static boolean fixSeparators(final StringBuffer name)
  {
    boolean changed = false;
    final int maxlen = name.length();
    for (int i = 0; i < maxlen; i++)
    {
      final char ch = name.charAt(i);
      if (ch == TRANS_SEPARATOR)
      {
        name.setCharAt(i, SEPARATOR_CHAR);
        changed = true;
      }
    }
    return changed;
  }

  /**
   * Extracts the scheme from a URI.
   *
   * @param uri
   *            The URI.
   * @return The scheme name. Returns null if there is no scheme.
   */
  public static String extractScheme(final String uri)
  {
    return extractScheme(uri, null);
  }

  /**
   * Extracts the scheme from a URI. Removes the scheme and ':' delimiter from
   * the front of the URI.
   *
   * @param uri
   *            The URI.
   * @param buffer
   *            Returns the remainder of the URI.
   * @return The scheme name. Returns null if there is no scheme.
   */
  public static String extractScheme(final String uri,
      final StringBuffer buffer)
  {
    if (buffer != null)
    {
      buffer.setLength(0);
      buffer.append(uri);
    }

    final int maxPos = uri.length();
    for (int pos = 0; pos < maxPos; pos++)
    {
      final char ch = uri.charAt(pos);

      if (ch == ':')
      {
        // Found the end of the scheme
        final String scheme = uri.substring(0, pos);
        if (buffer != null)
        {
          buffer.delete(0, pos + 1);
        }
        return scheme;
      }

      if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
      {
        // A scheme character
        continue;
      }
      if (pos > 0
          && ((ch >= '0' && ch <= '9') || ch == '+' || ch == '-' || ch == '.'))
      {
        // A scheme character (these are not allowed as the first
        // character of the scheme, but can be used as subsequent
        // characters.
        continue;
      }

      // Not a scheme character
      break;
    }

    // No scheme in URI
    return null;
  }

  /**
   * Removes %nn encodings from a string.
   */
  public static String decode(final String encodedStr)
      throws FileSystemException
  {
    if (encodedStr == null)
    {
      return null;
    }
    final StringBuffer buffer = new StringBuffer(encodedStr);
    decode(buffer, 0, buffer.length());
    return buffer.toString();
  }

  /**
   * Removes %nn encodings from a string.
   */
  public static void decode(final StringBuffer buffer, final int offset,
      final int length) throws FileSystemException
  {
    int index = offset;
    int count = length;
    for (; count > 0; count--, index++)
    {
      final char ch = buffer.charAt(index);
      if (ch != '%')
      {
        continue;
      }
      if (count < 3)
      {
        throw new FileSystemException(
            "vfs.provider/invalid-escape-sequence.error", buffer
                .substring(index, index + count));
      }

      // Decode
      int dig1 = Character.digit(buffer.charAt(index + 1), 16);
      int dig2 = Character.digit(buffer.charAt(index + 2), 16);
      if (dig1 == -1 || dig2 == -1)
      {
        throw new FileSystemException(
            "vfs.provider/invalid-escape-sequence.error", buffer
                .substring(index, index + 3));
      }
      char value = (char) (dig1 << 4 | dig2);

      // Replace
      buffer.setCharAt(index, value);
      buffer.delete(index + 1, index + 3);
      count -= 2;
    }
  }

  /**
   * Encodes and appends a string to a StringBuffer.
   */
  public static void appendEncoded(final StringBuffer buffer,
      final String unencodedValue, final char[] reserved)
  {
    final int offset = buffer.length();
    buffer.append(unencodedValue);
    encode(buffer, offset, unencodedValue.length(), reserved);
  }

  /**
   * Encodes a set of reserved characters in a StringBuffer, using the URI %nn
   * encoding. Always encodes % characters.
   */
  public static void encode(final StringBuffer buffer, final int offset,
      final int length, final char[] reserved)
  {
    int index = offset;
    int count = length;
    for (; count > 0; index++, count--)
    {
      final char ch = buffer.charAt(index);
      boolean match = (ch == '%');
      if (reserved != null)
      {
        for (int i = 0; !match && i < reserved.length; i++)
        {
          if (ch == reserved[i])
          {
            match = true;
          }
        }
      }
      if (match)
      {
        // Encode
        char[] digits =
        { Character.forDigit(((ch >> 4) & 0xF), 16),
            Character.forDigit((ch & 0xF), 16) };
        buffer.setCharAt(index, '%');
        buffer.insert(index + 1, digits);
        index += 2;
      }
    }
  }

  /**
   * Removes %nn encodings from a string.
   */
  public static String encode(final String decodedStr)
  {
    return encode(decodedStr, null);
  }

  public static String encode(final String decodedStr, final char[] reserved)
  {
    if (decodedStr == null)
    {
      return null;
    }
    final StringBuffer buffer = new StringBuffer(decodedStr);
    encode(buffer, 0, buffer.length(), reserved);
    return buffer.toString();
  }

  public static String[] encode(String[] strings)
  {
    if (strings == null)
    {
      return null;
    }
    for (int i = 0; i < strings.length; i++)
    {
      strings[i] = encode(strings[i]);
    }
    return strings;
  }

  public static void checkUriEncoding(String uri) throws FileSystemException
  {
    decode(uri);
  }

  public static void canonicalizePath(StringBuffer buffer, int offset,
      int length, FileNameParser fileNameParser)
      throws FileSystemException
  {
    int index = offset;
    int count = length;
    for (; count > 0; count--, index++)
    {
      final char ch = buffer.charAt(index);
      if (ch == '%')
      {
        if (count < 3)
        {
          throw new FileSystemException(
              "vfs.provider/invalid-escape-sequence.error",
              buffer.substring(index, index + count));
        }

        // Decode
        int dig1 = Character.digit(buffer.charAt(index + 1), 16);
        int dig2 = Character.digit(buffer.charAt(index + 2), 16);
        if (dig1 == -1 || dig2 == -1)
        {
          throw new FileSystemException(
              "vfs.provider/invalid-escape-sequence.error",
              buffer.substring(index, index + 3));
        }
        char value = (char) (dig1 << 4 | dig2);

        boolean match = (value == '%')
            || (fileNameParser != null && fileNameParser
                .encodeCharacter(value));

        if (match)
        {
          // this is a reserved character, not allowed to decode
          index += 2;
          count -= 2;
          continue;
        }

        // Replace
        buffer.setCharAt(index, value);
        buffer.delete(index + 1, index + 3);
        count -= 2;
      }
      else if (fileNameParser.encodeCharacter(ch))
      {
        // Encode
        char[] digits =
        { Character.forDigit(((ch >> 4) & 0xF), 16),
            Character.forDigit((ch & 0xF), 16) };
        buffer.setCharAt(index, '%');
        buffer.insert(index + 1, digits);
        index += 2;
      }
    }
  }

  public static String extractQueryString(StringBuffer name)
  {
    for (int pos = 0; pos < name.length(); pos++)
    {
      if (name.charAt(pos) == '?')
      {
        String queryString = name.substring(pos + 1);
        name.delete(pos, name.length());
        return queryString;
      }
    }

    return null;
  }
}
TOP

Related Classes of org.apache.commons.vfs.provider.UriParser

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.