001package org.apache.maven.scm.provider.accurev.util;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.HashMap;
023import java.util.Map;
024
025/**
026 * @author ggardner
027 */
028public final class QuotedPropertyParser
029{
030
031    private QuotedPropertyParser()
032    {
033
034    }
035
036    public static Map<String, String> parse( CharSequence seq )
037    {
038        Map<String, String> hashMap = new HashMap<String, String>();
039
040        parse( seq, hashMap );
041        return hashMap;
042    }
043
044    public static void parse( CharSequence string, Map<? super String, ? super String> propertyMap )
045    {
046
047        QuotedParseState state = QuotedParseState.KEY;
048        char quote = '\0';
049        StringBuilder buffer = new StringBuilder();
050        String propertyKey = "";
051
052        int i = 0; // where we are up to in the scan
053        int pos = 0; // where we have consumed into the buffer
054        while ( i < string.length() )
055        {
056            char current = string.charAt( i );
057            switch ( state )
058            {
059                case KEY:
060                    switch ( current )
061                    {
062                        case '"':
063                        case '\'':
064                            quote = current;
065                            state = QuotedParseState.IN_QUOTED_KEY;
066                            if ( i >= pos )
067                            {
068                                buffer.append( string.subSequence( pos, i ) );
069                            }
070                            pos = i + 1;
071                            break;
072                        case '=':
073                            if ( i >= pos )
074                            {
075                                buffer.append( string.subSequence( pos, i ) );
076                            }
077                            propertyKey = buffer.toString();
078                            buffer = new StringBuilder();
079                            state = QuotedParseState.VALUE;
080                            pos = i + 1;
081                            break;
082                        default:
083                    }
084                    break;
085
086                case VALUE:
087                    switch ( current )
088                    {
089                        case '"':
090                        case '\'':
091                            quote = current;
092                            state = QuotedParseState.IN_QUOTED_VALUE;
093                            if ( i >= pos )
094                            {
095                                buffer.append( string.subSequence( pos, i ) );
096                            }
097                            pos = i + 1;
098                            break;
099                        case '&':
100                            if ( i >= pos )
101                            {
102                                buffer.append( string.subSequence( pos, i ) );
103                            }
104                            propertyMap.put( propertyKey, buffer.toString() );
105                            pos = i + 1;
106                            buffer = new StringBuilder();
107                            state = QuotedParseState.KEY;
108                            break;
109                        default:
110                    }
111
112                    break;
113                case IN_QUOTED_KEY:
114                case IN_QUOTED_VALUE:
115                    if ( current == quote )
116                    {
117                        state =
118                            ( state == QuotedParseState.IN_QUOTED_KEY ) ? QuotedParseState.KEY : QuotedParseState.VALUE;
119                        if ( i >= pos )
120                        {
121                            buffer.append( string.subSequence( pos, i ) );
122                        }
123                        pos = i + 1;
124                    }
125                    break;
126                default:
127                    break;
128            }
129
130            i++;
131        }
132
133        if ( state == QuotedParseState.VALUE )
134        {
135            if ( i >= pos )
136            {
137                buffer.append( string.subSequence( pos, i ) );
138            }
139            propertyMap.put( propertyKey, buffer.toString() );
140        }
141    }
142
143    /**
144     * 
145     */
146    // Has to be down here to avoid a QDOX exception
147    public enum QuotedParseState
148    {
149        KEY, IN_QUOTED_KEY, IN_QUOTED_VALUE, VALUE
150    }
151
152}