javacommons/fileutils/javasrc/com/nokia/mj/impl/fileutils/FileURL.java
changeset 21 2a9601315dfc
child 50 023eef975703
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/fileutils/javasrc/com/nokia/mj/impl/fileutils/FileURL.java	Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,386 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package com.nokia.mj.impl.fileutils;
+
+/**
+ * FileURL manages URL/Path handling. It is responsible to manage paths which
+ * have path separators specific to the platform. It will also manage
+ * differences between URL and Absolute path and make it transparent to use
+ * from.
+ */
+final class FileURL
+{
+    private static String FILE_PREFIX = "file://";
+
+    private static String FILE_VALID_START_1 = "file:///";
+
+    private static String FILE_VALID_START_2 = "file://localhost/";
+
+    public static final String S60_FILE_SEPARATOR = "\\";
+
+    public static final String LINUX_FILE_SEPARATOR = "/";
+
+    private boolean iIsS60Path;
+
+    // Contains the unescaped path.
+    private String iUnescapedPath;
+
+    // Contains the absolute path to the current target.
+    private String iTargetPath;
+
+    // Contains the name of the target.
+    private String iTargetName;
+
+    private String iSeparatorUsed;
+
+    /**
+     * Constructor for FileURL.
+     *
+     * @param aName
+     *            Can contain either an Absolute path name or a File URL.
+     *            <p>
+     *            Path separator in Absolute path can be either "/" or platform
+     *            specific path separator. This is specified in file.separator
+     *            system property.
+     *            <p>
+     *            In case of file URL being passed as parameter, it must follow
+     *            the format of a fully-qualified, absolute path file name as
+     *            described by the file URL format in IETF RFCs 1738 & 2396.
+     */
+    public FileURL(String aName)
+    {
+        iIsS60Path = false;
+        String initialPath  = aName;
+        String path = "";
+
+        if (aName.trim().length() <= 0)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        if (aName.startsWith(FILE_PREFIX))
+        {
+            validateUrlStart(aName);
+
+            // aName is a url of the form file://<host>/<path>
+            // We need just the absolute path. So we extract it.
+            path = initialPath.substring(initialPath.indexOf('/', FILE_PREFIX
+                                         .length()) + 1);
+
+            // A file URL should have only "/" as file separator.
+            if (initialPath.indexOf(S60_FILE_SEPARATOR) != -1)
+            {
+                throw new IllegalArgumentException();
+            }
+        }
+        else
+        {
+            path = aName;
+        }
+
+        int endIndex = 0;
+        String tempName = path;
+        while (tempName.indexOf("//")!=-1)
+        {
+            endIndex = path.indexOf("//");
+            tempName = path.substring(0, endIndex);
+            if (endIndex < path.length())
+            {
+                tempName += path.substring(endIndex+1);
+            }
+        };
+        path = tempName;
+
+        // Check the sanity of path specified
+        checkPathValidity(path);
+        iUnescapedPath = path;
+
+        iIsS60Path = (iUnescapedPath.indexOf("\\") != -1);
+        int index = 0;
+
+        if (iIsS60Path)
+        {
+            iSeparatorUsed = "\\";
+            index = iUnescapedPath.lastIndexOf('\\',
+                                               iUnescapedPath.length() - 2);
+        }
+        else
+        {
+            iSeparatorUsed = "/";
+            index = iUnescapedPath
+                    .lastIndexOf('/', iUnescapedPath.length() - 2);
+        }
+
+        iTargetName = iUnescapedPath.substring(index + 1);
+        iTargetPath = iUnescapedPath.substring(0, index + 1);
+    }
+
+    /**
+     * checks to see if URL begins with valid urls starts.<br/> It can either
+     * be file:/// or file://localhost/.
+     *
+     * @param url
+     *            contains url passed to the constructor
+     */
+    private void validateUrlStart(String url)
+    {
+        if (url.startsWith(FILE_VALID_START_1)
+                || url.startsWith(FILE_VALID_START_2))
+        {
+            return;
+        }
+        throw new IllegalArgumentException();
+    }
+
+    /**
+     * Getter method to retrieve path to the parent directory of the current
+     * target.
+     *
+     * @return string containing absloute path to the target's parent.
+     */
+    public String getPath()
+    {
+        return iTargetPath;
+    }
+
+    /**
+     * Getter method to retrieve name of the target.
+     *
+     * @return string containing the name of the target currently pointed to.
+     *         This is derived from the url.
+     */
+    public String getName()
+    {
+        return iTargetName;
+    }
+
+    /**
+     * Getter method to retrieve the full path of the target. It will contain
+     * path to the target and the target too as a complete url.
+     *
+     * @return the full path of the target
+     */
+    public String getFullPath()
+    {
+        return iTargetPath + iTargetName;
+    }
+
+    protected String getSeparatorUsed()
+    {
+        return iSeparatorUsed;
+    }
+
+    /**
+     * Getter method to retrieve the file URL that can be passed as a parameter
+     * to FileConnection url. It will conform to File URL format in IETF RFCs
+     * 1738 & 2396.
+     *
+     * @return fully qualified File URL
+     */
+    public String getUrl()
+    {
+        // Get URL must return escaped url.
+        String aUrl = FILE_VALID_START_1 + iTargetPath + iTargetName;
+        String value = "";
+
+        for (int i = 0; i < aUrl.length(); i++)
+        {
+            char ch = aUrl.charAt(i);
+
+            // Also replace "\\" with "/"
+            if (ch == '\\')
+            {
+                value += "/";
+                continue;
+            }
+
+            boolean isLetter = (ch >= 'a' && ch <= 'z')
+                               || (ch >= 'A' && ch <= 'Z');
+            boolean isDigit = (ch >= '0' && ch <= '9');
+            if (isLetter || isDigit)
+            {
+                value += ch;
+            }
+            else
+            {
+                value += stringToHex("" + ch);
+            }
+
+        }
+
+        return value;
+    }
+
+    /**
+     * Checks to see if the path passed is valid. Simple sanity checks for the
+     * path to point to a valid target.
+     *
+     * @param name
+     *            contains an absolute path to a target.
+     */
+    private static final void checkPathValidity(String name)
+    {
+        // Only in S60 file system, we have the concept of drives.
+        // So, ":" should only appear in File systems that have
+        // file.separator as '\\'
+
+        String separator = System.getProperty("file.separator");
+
+        // If platform is S60 like.
+        if (separator.equals(S60_FILE_SEPARATOR))
+        {
+            makeS60SpecificChecks(name);
+        }
+        else
+        {
+            makeLinuxSpecificChecks(name);
+        }
+
+        if ((name.indexOf('*') != -1) || (name.indexOf('?') != -1)
+                || (name.indexOf('<') != -1) || (name.indexOf('>') != -1)
+                || (name.indexOf("//") != -1) || name.endsWith("/."))
+        {
+            throw new IllegalArgumentException(name);
+        }
+    }
+
+    /**
+     * Makes checks that are specific to S60 like File System. This should be
+     * called only in case file.separator is "\\"
+     *
+     * @param name
+     *            contians the path that needs to be checked for sanity.
+     */
+    private static final void makeS60SpecificChecks(String name)
+    {
+        // First index of colon
+        int firstIndexOfColon = name.indexOf(':');
+        int indexOfColon = name.indexOf(':', firstIndexOfColon + 1);
+
+        if (indexOfColon != -1)
+        {
+            throw new IllegalArgumentException(name);
+        }
+
+        // In S60 like file system, it is possible to have "/" as the file
+        // separator as file url accepts it. But then, once there is "\\" as
+        // file separator, the entire url should follow the same convention.
+
+        if (name.indexOf(S60_FILE_SEPARATOR) != -1)
+        {
+            if (name.indexOf(LINUX_FILE_SEPARATOR) != -1)
+            {
+                // We must be having only one kind of separator
+                throw new IllegalArgumentException(name);
+            }
+
+            if (firstIndexOfColon > name.indexOf(S60_FILE_SEPARATOR))
+            {
+                throw new IllegalArgumentException(name);
+            }
+        }
+        else
+        {
+            if ((firstIndexOfColon > name.indexOf(LINUX_FILE_SEPARATOR)))
+            {
+                throw new IllegalArgumentException(name);
+            }
+        }
+    }
+
+    /**
+     * Makes checks that are specific to Linux like File System. This should be
+     * called only in case file.separator is "/"
+     *
+     * @param name
+     *            contians the path that needs to be checked for sanity.
+     */
+    private static final void makeLinuxSpecificChecks(String name)
+    {
+        if (name.indexOf(':') != -1)
+        {
+            throw new IllegalArgumentException(name);
+        }
+
+        if (name.indexOf(S60_FILE_SEPARATOR) != -1)
+        {
+            throw new IllegalArgumentException(name);
+        }
+    }
+
+    /**
+     * encodes a unicode string to a string of 4-digit hex numbers <br />
+     * Note: this method is slower than stringToHex(String,StringBuffer)
+     *
+     * @param java
+     *            normal java string
+     * @return string of 4-digit hex numbers
+     */
+    public static final String stringToHex(String str)
+    {
+        if (str == null)
+            return "";
+        int length = str.length();
+        StringBuffer result = new StringBuffer(length * 4);
+        stringToHex(str, result);
+        return result.toString();
+    }
+
+    /**
+     * encodes a unicode string to a string of 4-digit hex numbers.
+     *
+     * @param str
+     *            normal java string
+     * @param out
+     *            string of 4-digit hex numbers
+     */
+    public static final void stringToHex(String str, StringBuffer out)
+    {
+        // To improve performance, implement a table-lookup instead of if/then cases.
+
+        if (str == null)
+            return;
+        int length = str.length();
+        for (int pos = 0; pos < length; pos++)
+        {
+            char cur_char = str.charAt(pos);
+            int this_char = (int) cur_char;
+            if (this_char < 127 && cur_char != ' ')
+            {
+                out.append((char) this_char);
+                continue;
+            }
+            for (int digit = 0; digit < 4; digit++)
+            {
+                int this_digit = this_char & 0xf000;
+                this_char = this_char << 4;
+                this_digit = (this_digit >> 12);
+
+                // We get 4 digits, so on 2nd we insert a % sign and then value
+                if (digit == 2)
+                    out.append('%');
+                if (digit < 2)
+                    continue;
+                if (this_digit >= 10)
+                    out.append((char)(this_digit + 87));
+                else
+                    out.append((char)(this_digit + 48));
+            }
+        }
+    }
+}