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                    }
083                    break;
084
085                case VALUE:
086                    switch ( current )
087                    {
088                        case '"':
089                        case '\'':
090                            quote = current;
091                            state = QuotedParseState.IN_QUOTED_VALUE;
092                            if ( i >= pos )
093                            {
094                                buffer.append( string.subSequence( pos, i ) );
095                            }
096                            pos = i + 1;
097                            break;
098                        case '&':
099                            if ( i >= pos )
100                            {
101                                buffer.append( string.subSequence( pos, i ) );
102                            }
103                            propertyMap.put( propertyKey, buffer.toString() );
104                            pos = i + 1;
105                            buffer = new StringBuilder();
106                            state = QuotedParseState.KEY;
107                            break;
108                        default:
109                    }
110
111                    break;
112                case IN_QUOTED_KEY:
113                case IN_QUOTED_VALUE:
114                    if ( current == quote )
115                    {
116                        state =
117                            ( state == QuotedParseState.IN_QUOTED_KEY ) ? QuotedParseState.KEY : QuotedParseState.VALUE;
118                        if ( i >= pos )
119                        {
120                            buffer.append( string.subSequence( pos, i ) );
121                        }
122                        pos = i + 1;
123                    }
124                    break;
125                default:
126                    break;
127            }
128
129            i++;
130        }
131
132        if ( state == QuotedParseState.VALUE )
133        {
134            if ( i >= pos )
135            {
136                buffer.append( string.subSequence( pos, i ) );
137            }
138            propertyMap.put( propertyKey, buffer.toString() );
139        }
140    }
141
142    // Has to be down here to avoid a QDOX exception
143    public static enum QuotedParseState
144    {
145        KEY, IN_QUOTED_KEY, IN_QUOTED_VALUE, VALUE
146    }
147
148}