All Downloads are FREE. Search and download functionalities are using the official Maven repository.

libcore.net.url.UrlUtils Maven / Gradle / Ivy

/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 libcore.net.url;

import java.util.Locale;

public final class UrlUtils {
    private UrlUtils() {
    }

    /**
     * Returns the path will relative path segments like ".." and "." resolved.
     * The returned path will not necessarily start with a "/" character. This
     * handles ".." and "." segments at both the beginning and end of the path.
     *
     * @param discardRelativePrefix true to remove leading ".." segments from
     *     the path. This is appropriate for paths that are known to be
     *     absolute.
     */
    public static String canonicalizePath(String path, boolean discardRelativePrefix) {
        // the first character of the current path segment
        int segmentStart = 0;

        // the number of segments seen thus far that can be erased by sequences of '..'.
        int deletableSegments = 0;

        for (int i = 0; i <= path.length(); ) {
            int nextSegmentStart;
            if (i == path.length()) {
                nextSegmentStart = i;
            } else if (path.charAt(i) == '/') {
                nextSegmentStart = i + 1;
            } else {
                i++;
                continue;
            }

            /*
             * We've encountered either the end of a segment or the end of the
             * complete path. If the final segment was "." or "..", remove the
             * appropriate segments of the path.
             */
            if (i == segmentStart + 1 && path.regionMatches(segmentStart, ".", 0, 1)) {
                // Given "abc/def/./ghi", remove "./" to get "abc/def/ghi".
                path = path.substring(0, segmentStart) + path.substring(nextSegmentStart);
                i = segmentStart;
            } else if (i == segmentStart + 2 && path.regionMatches(segmentStart, "..", 0, 2)) {
                if (deletableSegments > 0 || discardRelativePrefix) {
                    // Given "abc/def/../ghi", remove "def/../" to get "abc/ghi".
                    deletableSegments--;
                    int prevSegmentStart = path.lastIndexOf('/', segmentStart - 2) + 1;
                    path = path.substring(0, prevSegmentStart) + path.substring(nextSegmentStart);
                    i = segmentStart = prevSegmentStart;
                } else {
                    // There's no segment to delete; this ".." segment must be retained.
                    i++;
                    segmentStart = i;
                }
            } else {
                if (i > 0) {
                    deletableSegments++;
                }
                i++;
                segmentStart = i;
            }
        }
        return path;
    }

    /**
     * Returns a path that can be safely concatenated with {@code authority}. If
     * the authority is null or empty, this can be any path. Otherwise the paths
     * run together like {@code http://android.comindex.html}.
     */
    public static String authoritySafePath(String authority, String path) {
        if (authority != null && !authority.isEmpty() && !path.isEmpty() && !path.startsWith("/")) {
            return "/" + path;
        }
        return path;
    }

    /**
     * Returns the scheme prefix like "http" from the URL spec, or null if the
     * spec doesn't start with a scheme. Scheme prefixes match this pattern:
     * {@code alpha ( alpha | digit | '+' | '-' | '.' )* ':'}
     */
    public static String getSchemePrefix(String spec) {
        int colon = spec.indexOf(':');

        if (colon < 1) {
            return null;
        }

        for (int i = 0; i < colon; i++) {
            char c = spec.charAt(i);
            if (!isValidSchemeChar(i, c)) {
                return null;
            }
        }

        return spec.substring(0, colon).toLowerCase(Locale.US);
    }

    public static boolean isValidSchemeChar(int index, char c) {
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            return true;
        }
        if (index > 0 && ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')) {
            return true;
        }
        return false;
    }

    /**
     * Returns the index of the first char of {@code chars} in {@code string}
     * bounded between {@code start} and {@code end}. This returns {@code end}
     * if none of the characters exist in the requested range.
     */
    public static int findFirstOf(String string, String chars, int start, int end) {
        for (int i = start; i < end; i++) {
            char c = string.charAt(i);
            if (chars.indexOf(c) != -1) {
                return i;
            }
        }
        return end;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy