FileDocCategorySizeDatePackage
LocaleHelpers.javaAPI DocphoneME MR2 API (J2ME)9950Wed May 02 18:00:46 BST 2007com.sun.j2me.global

LocaleHelpers.java

/*
 *   
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */

package com.sun.j2me.global;

/**
 *  This class provides general helper methods related with locale manipulation.
 */
public class LocaleHelpers {

    /**
     * Checks whether given locale is valid or not according to
     * JSR 238 specification, i.e. is in form of
     * <language>-<country>-<variant>.
     * Restrictions apply to length and
     * validity of characters of language part, country part and separators.
     * No checking of variant is performed.
     *
     * @param locale  locale code
     * @return <code>true</code> if locale is valid, 
     *         <code>false</code> otherwise
     */
    public static boolean isValidLocale(String locale) {
        if (locale == null) {
            // Null locale is acceptable according to MIDP 2.0.
            return true;
        }

        int len = locale.length();
	if (len == 0) {
	    return true;
	}
        if (len < 2) {
            // Language part, if present, must be 2 characters long.
            return false;
        }

        char ch = locale.charAt(0);
        if (ch < 'a' || ch > 'z') {
            return false;
        }
        ch = locale.charAt(1);
        if (ch < 'a' || ch > 'z') {
            return false;
        }

        if (len > 2) {
            if (len < 5 || len == 6) {
                // Country part, if present, must be 2 characters long.
                return false;
            }

            ch = locale.charAt(2);
            if (ch != '-' && ch != '_') {
                return false;
            }
            ch = locale.charAt(3);
            if (ch < 'A' || ch > 'Z') {
                return false;
            }
            ch = locale.charAt(4);
            if (ch < 'A' || ch > 'Z') {
                return false;
            }

            if (len > 6) {
                ch = locale.charAt(5);
                if (ch != '-' && ch != '_') {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Replaces characters (expected dashes or underscores) on appropriate
     * positions of locale code by dashes. The resulting locale name is likely
     * to conform with MIDP 2.0 specification.
     *
     * @param locale  locale code
     * @return corrected locale code, or <code>null</code> in case of invalid
     *      format of given locale
     */
    public static String normalizeLocale(String locale) {
        if (locale == null) {
            return null;
        }

        int len = locale.length();
        if (len > 3) {
            locale = locale.substring(0, 2) + '-' + locale.substring(3);
            if (len > 6) {
                locale = locale.substring(0, 5) + '-' + locale.substring(6);
            }
        }

        return locale;
    }

    /**
     * Returns parent for the given locale. Parent locale is obtained by removing
     * the last component of locale code, which is in form:
     * <language>-<country>-<variant>. Parent locale for
     * <language> is empty string.
     *
     * @param locale  the locale to obtain parent of.
     * @return parent locale or <code>null</code> if locale doesn't have
     *      parent (if locale is already <code>null</code> or empty string.
     */
    public static String getParentLocale(String locale) {

        if (locale == null) {
            return null;
        }
        int len = locale.length();
        if (len == 0) {
            return null;
        }

        if (len > 6) {
            return locale.substring(0, 5);
        }
        if (len > 3) {
            return locale.substring(0, 2);
        }
        return "";
    }

    /**
     * Get an index of the given locale in array of locales returned from any
     * of <code>getSupportedLocales</code> methods (e.g.
     * {@link javax.microedition.global.ResourceManager#getSupportedLocales}).
     *
     * @param  locale   the locale to search for
     * @param  locales  array of locales to search in
     * @return locale index in the given array, or <code>-1</code> if the
     *      array doesn't contain the specified locale
     */
    public static int indexInSupportedLocales(String locale, 
                                            String[] locales) {

        if (locale == null || locales == null || locales.length == 0) {
            return -1;
        }

        for (int i = 0; i < locales.length; i++) {
            if (locale.equals(locales[i])) {
                return i;
            }
        }

        return -1;
    }

    private static String extractElement(String input) {
        String trimmed = input.trim();
        int length = trimmed.length();
        
        if ((length >= 2) && (trimmed.charAt(0) == '"') && 
                (trimmed.charAt(length - 1) == '"')) {
            return trimmed.substring(1, length - 1);
        }
        
        return trimmed;
    }

    /**
     * Splits the given string into parts according to the given separator. It
     * stops parsing the string after the first <code>limit</code> parts are
     * extracted. If <code>limit</code> equals <code>-1</code> all parts are
     * extracted.
     *
     * @param input the input string
     * @param separator the separator
     * @param limit the maximum number of parts or <code>-1</code> if no maximum
     *      is given
     * @return the extracted parts as an array of strings
     */ 
    public static String[] splitString(String input, String separator, 
            int limit) {
        int index = input.indexOf(separator);
        int count = 1;
        
        // get the count of elements
        while (index >= 0) {
            ++count;
            index = input.indexOf(separator, index + 1);
        }
        
        if ((limit != -1) && (count > limit)) {
            count = limit;
        }
        
        // create array for elements
        String[] elements = new String[count];
        splitString(elements, input, separator, limit);
        
        return elements;
    }
    
    /**
     * Splits the given string into parts according to the given separator. It
     * stops parsing the string after the first <code>limit</code> parts are
     * extracted. If <code>limit</code> equals <code>-1</code> all parts are
     * extracted.
     *
     * @param elements an array of strings where to put the results to
     * @param input the input string
     * @param separator the separator
     * @param limit the maximum number of parts or <code>-1</code> if no maximum
     *      is given
     * @return the number of extracted parts
     */ 
    public static int splitString(String[] elements, String input, 
            String separator, int limit) {
        int lastIndex = -1;
        int index = input.indexOf(separator);
        int count = 0;

        if ((limit == -1) || (limit > elements.length)) {
            limit = elements.length;
        }
        
        if (limit == 0) {
            return 0;
        }
        
        while (index >= 0) {
            elements[count++] = extractElement(input.substring(lastIndex + 1,
                    index));
            if (count == limit) {
                return count;
            }
            lastIndex = index;
            index = input.indexOf(separator, lastIndex + 1);
        }

        elements[count++] = extractElement(input.substring(lastIndex + 1,
                input.length()));
        
        return count;
    }

    /**
     * Creates an array of <code>short</code> values from a given
     * <code>byte</code> array. Every two sequential one-byte values are
     * packed into one <code>short</code> value. <p>
     * Caution: initial array must have even length.
     *
     * @param source  original array of bytes
     * @return new array of shorts
     */
    public static short[] byteArrayToShortArray(byte[] source) {
        short[] output = new short[source.length >> 1];
        for (int i = 0, j = 0; i < source.length; i += 2, ++j) {
            output[j] = (short)(((source[i] & 0xff) << 8) | 
                    source[i + 1] & 0xff);
        }
        return output;
    }
    
    /**
     * Creates an array of <code>int</code> values from a given
     * <code>byte</code> array. Every four sequential one-byte values are
     * packed into one <code>int</code> value. <p>
     * Caution: initial array's length must be a multiple of 4.
     *
     * @param source  original array of bytes
     * @return new array of ints
     */
    public static int[] byteArrayToIntArray(byte[] source) {
        int[] output = new int[source.length >> 2];
        for (int i = 0, j = 0; i < source.length; i += 4, ++j) {
            output[j] = ((source[i] & 0xff) << 24) | 
                    ((source[i + 1] & 0xff) << 16) | 
                    ((source[i + 2] & 0xff) << 8) | 
                    source[i + 3] & 0xff;
        }
        return output;
    }
}