    001/*
    002    Licensed to the Apache Software Foundation (ASF) under one
    003    or more contributor license agreements.  See the NOTICE file
    004    distributed with this work for additional information
    005    regarding copyright ownership.  The ASF licenses this file
    006    to you under the Apache License, Version 2.0 (the
    007    "License"); you may not use this file except in compliance
    008    with the License.  You may obtain a copy of the License at
    009
    010       http://www.apache.org/licenses/LICENSE-2.0
    011
    012    Unless required by applicable law or agreed to in writing,
    013    software distributed under the License is distributed on an
    014    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015    KIND, either express or implied.  See the License for the
    016    specific language governing permissions and limitations
    017    under the License.
    018 */
    019package org.apache.wiki.util;
    020
    021import java.util.Iterator;
    022import java.util.Map;
    023import java.util.Properties;
    024import java.util.TreeMap;
    025
    026/**
    027 * some useful methods for properties
    028 *
    029 * @version 1.0
    030 */
    031public final class PropertiesUtils {
    032
    033    private static final String OTHER_WHITESPACE = "\t\r\n\014";
    034    private static final char[] HEXDIGIT = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    035
    036    /** Private constructor to prevent instantiation. */
    037    private PropertiesUtils()
    038    {}
    039
    040    /**
    041     * <p>
    042     * like Properties.store, but stores the properties in sorted order
    043     * </p>
    044     *
    045     * @param properties the properties object
    046     * @return String the properties, nicely formatted
    047     */
    048    public static String toSortedString(final Properties properties )
    049    {
    050        @SuppressWarnings( { "unchecked", "rawtypes" } ) final TreeMap< String, String > treemap = new TreeMap( properties );
    051        final StringBuilder string = new StringBuilder();
    052        final Iterator< Map.Entry< String, String > > iterator = treemap.entrySet().iterator();
    053        while( iterator.hasNext() )
    054        {
    055            final Map.Entry< String, String > entry = iterator.next();
    056            final String key = entry.getKey();
    057            final String value = entry.getValue() == null ? "null" : entry.getValue();
    058            string.append(toLine(key, value)).append('\n');
    059        }
    060        return string.toString();
    061    }
    062
    063    /**
    064     * Generates a property file line from a supplied key and value.
    065     * @param key the property's key
    066     * @param value the property's value
    067     * @return the converted string
    068     */
    069    public static String toLine(final String key, final String value )
    070    {
    071        return saveConvert( key, true ) + '=' + saveConvert( value, false );
    072    }
    073
    074    /**
    075     * Encodes a property file string from a supplied key/value line.
    076     * @param string the string to encode
    077     * @param encodeWhiteSpace <code>true</code> if whitespace should be encoded also
    078     * @return the converted string
    079     */
    080    public static String saveConvert(final String string, final boolean encodeWhiteSpace )
    081    {
    082        final int i = string.length();
    083        final StringBuilder stringbuffer = new StringBuilder( i * 2 );
    084        for( int i3 = 0; i3 < i; i3++ )
    085        {
    086            final char c = string.charAt( i3 );
    087            switch( c )
    088            {
    089                case ' ':
    090                    if( i3 == 0 || encodeWhiteSpace )
    091                    {
    092                        stringbuffer.append( '\\' );
    093                    }
    094                    stringbuffer.append( ' ' );
    095                    break;
    096                case '\\':
    097                    stringbuffer.append( '\\' );
    098                    stringbuffer.append( '\\' );
    099                    break;
    100                case '\t':
    101                    stringbuffer.append( '\\' );
    102                    stringbuffer.append( 't' );
    103                    break;
    104                case '\n':
    105                    stringbuffer.append( '\\' );
    106                    stringbuffer.append( 'n' );
    107                    break;
    108                case '\r':
    109                    stringbuffer.append( '\\' );
    110                    stringbuffer.append( 'r' );
    111                    break;
    112                case '\014':
    113                    stringbuffer.append( '\\' );
    114                    stringbuffer.append( 'f' );
    115                    break;
    116                default:
    117                    if( c < 32 || c > 126 )
    118                    {
    119                        stringbuffer.append( '\\' );
    120                        stringbuffer.append( 'u' );
    121                        stringbuffer.append( toHex( c >> 12 & 0xf ) );
    122                        stringbuffer.append( toHex( c >> 8 & 0xf ) );
    123                        stringbuffer.append( toHex( c >> 4 & 0xf ) );
    124                        stringbuffer.append( toHex( c & 0xf ) );
    125                    }
    126                    else
    127                    {
    128                        if( OTHER_WHITESPACE.indexOf( c ) != -1 )
    129                        {
    130                            stringbuffer.append( '\\' );
    131                        }
    132                        stringbuffer.append( c );
    133                    }
    134            }
    135        }
    136        return stringbuffer.toString();
    137    }
    138
    139    private static char toHex(final int i )
    140    {
    141        return HEXDIGIT[i & 0xf];
    142    }
    143}