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

com.backblaze.b2.util.B2StringUtil Maven / Gradle / Ivy

Go to download

The core logic for B2 SDK for Java. Does not include any implementations of B2WebApiClient.

There is a newer version: 6.3.0
Show newest version
/*
 * Copyright 2017, Backblaze Inc. All Rights Reserved.
 * License https://www.backblaze.com/using_b2_code.html
 */
package com.backblaze.b2.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * String utilities
 */
public class B2StringUtil {
    public static final String UTF8 = "UTF-8";

    static final char [] LOWER_HEX_DIGITS = new char [] {
            '0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

    /**
     * @param str the string to check
     * @return true if str is null or zero-length.
     */
    static boolean isEmpty(String str) {
        if (str == null) {
            return true;
        }
        str = str.trim();
        return (str.length() == 0);
    }

    /**
     * @param s the string to encode.
     * @return a string with the contents of 's' encoded with percents as is done for URLs.
     */
    public static String percentEncode(String s) {
        try {
            return URLEncoder.encode(s, UTF8).replace("%2F", "/");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UTF8 isn't supported? " + e.getMessage(), e);
        }
    }

    public static String percentDecode(String s) {
        try {
            return URLDecoder.decode(s, UTF8);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UTF8 isn't supported? " + e.getMessage(), e);
        }
    }

    private static boolean isDecimalDigitChar(char c) {
        return ('0' <= c) && (c <= '9');
    }

    /**
     * @param str the string to examine
     * @param startIndex the index of the first character to examine
     * @param endIndex the index just past the last character to examine.  must be >= startIndex.
     * @return true iff there are no non-decimal characters in the specified substring of str.
     */
    @SuppressWarnings("SameParameterValue")
    static boolean allDecimal(String str,
                              int startIndex,
                              int endIndex) {
        B2Preconditions.checkArgument(startIndex <= endIndex);
        for (int i = startIndex; i < endIndex; i++) {
            if (!isDecimalDigitChar(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    private static int decimalCharToInt(char c) {
        if (c < '0' || '9' < c) {
            throw new IllegalArgumentException("Character " + c + " is not a digit");
        }
        return c - '0';
    }

    /**
     *
     * @param s the string to examine
     * @param startIndex the index of the first character to examine
     * @param endIndex the index just past the last character to examine.  must be >= startIndex.
     * @return 0 if beginIndex == endIndex, otherwise the specified substring of 's' as an integer.
     * @throws IllegalArgumentException if the substring doesn't represent an integer.
     */
    public static int decimalSubstringToInt(String s, int startIndex, int endIndex) {
        int result = 0;
        for (int i = startIndex; i < endIndex; i++) {
            result = result * 10 + decimalCharToInt(s.charAt(i));
        }
        return result;
    }

    /**
     * @param str the string to examine
     * @param offset index of the first character to examine.  must be >= 0.
     * @param length the length of the substring to examine.  must be >= 0.
     * @param minInclusive the smallest value allowed
     * @param maxInclusive the largest value allowed
     * @return true iff the specified substring of 'str' is an integer in the specified range.
     */
    public static boolean decimalNumberInRange(String str, int offset, int length,
                                               int minInclusive, int maxInclusive) {
        B2Preconditions.checkArgument(offset >= 0 && length >= 0);
        int value = 0;
        for (int i = offset; i < offset + length; i++) {
            char c = str.charAt(i);
            if (c < '0' || '9' < c) {
                return false;
            }
            value = (value * 10) + (c - '0');
        }
        return (minInclusive <= value) && (value <= maxInclusive);
    }

    public static String join(String delimiter, Object[] objects) {
        final StringBuilder builder = new StringBuilder();
        for (Object o : objects) {
            if (builder.length() > 0) {
                builder.append(delimiter);
            }
            final String s = (o == null) ? null : o.toString();
            builder.append(s);
        }
        return builder.toString();
    }

    /**
     * Returns the UTF-8 representation of a string.
     *
     * We assume that there's always a UTF-8 charset installed, and
     * it's a bother to catch the exception everywhere, so this method
     * catches the exception for you.
     */
    public static byte [] getUtf8Bytes(String str) {
        try {
            return str.getBytes(UTF8);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("No UTF-8 charset");
        }
    }

    /**
     * @param b the array of bytes to convert.
     * @return if b is null or empty, "".  otherwise, returns a string with
     *         two lowercase hex digits for each byte in the string, representing
     *         the value of that byte.
     */
    public static String toHexString(byte[] b) {
        if (b == null || b.length == 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder(b.length * 2);
        for (int i = 0; i < b.length; i++) {
            int unsignedByte = (b[i] & 0xff);
            sb.append(LOWER_HEX_DIGITS[unsignedByte >> 4]);
            sb.append(LOWER_HEX_DIGITS[unsignedByte & 0x0f]);
        }
        return sb.toString();
    }

    /**
     * This returns a new string with the first letter title-cased, and
     * first character after each "_" title-cased, and all underscores removed.
     * For example, "foo" becomes "Foo" and "foo_bar_baz" becomes "FooBarBaz".
     * @param orig an input string with "_"s separating words.
     * @param capitalizeFirstLetter should the first letter be capitalized?
     * @return new, camel-cased version of orig
     */
    public static String underscoresToCamelCase(String orig, boolean capitalizeFirstLetter) {
        final int origLen = orig.length();
        final StringBuilder builder = new StringBuilder(origLen);

        boolean capitalize = capitalizeFirstLetter;
        for (int i=0; i < origLen; i++) {
            char c = orig.charAt(i);
            if (c == '_') {
                capitalize = true;
                continue;
            }
            if (capitalize) {
                c = Character.toTitleCase(c);
                capitalize = false;
            }
            else {
                c = Character.toLowerCase(c);
            }
            builder.append(c);
        }

        return builder.toString();
    }
  
    /**
     * @param all the string whose prefix we're checking
     * @param possiblePrefix the prefix we're asking about being in all.
     * @return true iff both all and possiblePrefix are non-null and
     *                  all starts with possiblePrefix ignoring case.
     */
    public static boolean startsWithIgnoreCase(String all, String possiblePrefix) {
        if (all == null || possiblePrefix == null) {
            return false;  // by specification of this method.
        }
        if (all.length() < possiblePrefix.length()) {
            return false;  // too short to have the prefix
        }

        // we have to actually check the prefix.
        final String prefix = all.substring(0, possiblePrefix.length());
        return prefix.equalsIgnoreCase(possiblePrefix);
    }

    // this exists so it can be called for code coverage purposes in the unit test.
    // it is package-private so that no one else can call it.
    B2StringUtil() {
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy