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.htmltowiki;
020
021import java.util.Iterator;
022import java.util.Map;
023import java.util.Properties;
024import java.util.TreeMap;
025
026/**
027 * some usefull methods for properties
028 *
029 * @version 1.0
030 */
031// FIXME3.0 move to utils package
032public final class PropertiesUtils
033{
034    private static final String OTHER_WHITESPACE = "\t\r\n\014";
035    private static final char[] HEXDIGIT = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
036
037    /** Private constructor to prevent instantiation. */
038    private PropertiesUtils()
039    {}
040
041    /**
042     * <p>
043     * like Properties.store, but stores the properties in sorted order
044     * </p>
045     *
046     * @param properties the properties object
047     * @return String the properties, nicely formatted 
048     */
049    @SuppressWarnings("unchecked")
050    public static String toSortedString( Properties properties )
051    {
052        TreeMap treemap = new TreeMap( properties );
053        String string = "";
054        Iterator iterator = treemap.entrySet().iterator();
055        while( iterator.hasNext() )
056        {
057            Map.Entry entry = (Map.Entry)iterator.next();
058            String key = (String)entry.getKey();
059            String value = entry.getValue() == null ? "null" : entry.getValue().toString();
060            string += toLine( key, value ) + '\n';
061        }
062        return string;
063    }
064
065    /**
066     * Generates a property file line from a supplied key and value.
067     * @param key the property's key
068     * @param value the property's value
069     * @return the converted string
070     */
071    public static String toLine( String key, String value )
072    {
073        return saveConvert( key, true ) + '=' + saveConvert( value, false );
074    }
075
076    /**
077     * Encodes a property file string from a supplied key/value line.
078     * @param string the string to encode
079     * @param encodeWhiteSpace <code>true</code> if whitespace should be encoded also
080     * @return the converted string
081     */
082    public static String saveConvert( String string, boolean encodeWhiteSpace )
083    {
084        int i = string.length();
085        StringBuilder stringbuffer = new StringBuilder( i * 2 );
086        for( int i3 = 0; i3 < i; i3++ )
087        {
088            char c = string.charAt( i3 );
089            switch( c )
090            {
091                case ' ':
092                    if( i3 == 0 || encodeWhiteSpace )
093                    {
094                        stringbuffer.append( '\\' );
095                    }
096                    stringbuffer.append( ' ' );
097                    break;
098                case '\\':
099                    stringbuffer.append( '\\' );
100                    stringbuffer.append( '\\' );
101                    break;
102                case '\t':
103                    stringbuffer.append( '\\' );
104                    stringbuffer.append( 't' );
105                    break;
106                case '\n':
107                    stringbuffer.append( '\\' );
108                    stringbuffer.append( 'n' );
109                    break;
110                case '\r':
111                    stringbuffer.append( '\\' );
112                    stringbuffer.append( 'r' );
113                    break;
114                case '\014':
115                    stringbuffer.append( '\\' );
116                    stringbuffer.append( 'f' );
117                    break;
118                default:
119                    if( c < 32 || c > 126 )
120                    {
121                        stringbuffer.append( '\\' );
122                        stringbuffer.append( 'u' );
123                        stringbuffer.append( toHex( c >> 12 & 0xf ) );
124                        stringbuffer.append( toHex( c >> 8 & 0xf ) );
125                        stringbuffer.append( toHex( c >> 4 & 0xf ) );
126                        stringbuffer.append( toHex( c & 0xf ) );
127                    }
128                    else
129                    {
130                        if( OTHER_WHITESPACE.indexOf( c ) != -1 )
131                        {
132                            stringbuffer.append( '\\' );
133                        }
134                        stringbuffer.append( c );
135                    }
136            }
137        }
138        return stringbuffer.toString();
139    }
140
141    private static char toHex( int i )
142    {
143        return HEXDIGIT[i & 0xf];
144    }
145}