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     */
019    
020    package javax.activation;
021    
022    import java.util.Collections;
023    import java.util.Enumeration;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.Map;
027    
028    
029    /**
030     * @version $Rev: 467553 $ $Date: 2006-10-25 06:01:51 +0200 (Mi, 25. Okt 2006) $
031     */
032    public class MimeTypeParameterList {
033    
034        private final Map params = new HashMap();
035    
036        public MimeTypeParameterList() {
037        }
038    
039        public MimeTypeParameterList(String parameterList) throws MimeTypeParseException {
040            parse(parameterList);
041        }
042    
043        protected void parse(String parameterList) throws MimeTypeParseException {
044            if (parameterList == null) {
045                throw new MimeTypeParseException("parameterList is null");
046            }
047    
048            RFC2045Parser parser = new RFC2045Parser(parameterList);
049            while (parser.hasMoreParams()) {
050                String attribute = parser.expectAttribute();
051                parser.expectEquals();
052                String value = parser.expectValue();
053                params.put(attribute.toLowerCase(), value);
054            }
055        }
056    
057        public int size() {
058            return params.size();
059        }
060    
061        public boolean isEmpty() {
062            return params.isEmpty();
063        }
064    
065        public String get(String name) {
066            return (String) params.get(name.toLowerCase());
067        }
068    
069        public void set(String name, String value) {
070            params.put(name.toLowerCase(), value);
071        }
072    
073        public void remove(String name) {
074            params.remove(name.toLowerCase());
075        }
076    
077        public Enumeration getNames() {
078            return Collections.enumeration(params.keySet());
079        }
080    
081        /**
082         * String representation of this parameter list.
083         *
084         * @return
085         */
086        public String toString() {
087            StringBuffer buf = new StringBuffer(params.size() << 4);
088            for (Iterator i = params.entrySet().iterator(); i.hasNext();) {
089                Map.Entry entry = (Map.Entry) i.next();
090                buf.append("; ").append(entry.getKey()).append('=');
091                quote(buf, (String) entry.getValue());
092            }
093            return buf.toString();
094        }
095    
096        private void quote(StringBuffer buf, String value) {
097            int length = value.length();
098            boolean quote = false;
099            for (int i = 0; i < length; i++) {
100                if (MimeType.isSpecial(value.charAt(i))) {
101                    quote = true;
102                    break;
103                }
104            }
105            if (quote) {
106                buf.append('"');
107                for (int i = 0; i < length; i++) {
108                    char c = value.charAt(i);
109                    if (c == '\\' || c == '"') {
110                        buf.append('\\');
111                    }
112                    buf.append(c);
113                }
114                buf.append('"');
115            } else {
116                buf.append(value);
117            }
118        }
119    
120        private static class RFC2045Parser {
121            private final String text;
122            private int index = 0;
123    
124            private RFC2045Parser(String text) {
125                this.text = text;
126            }
127    
128            /**
129             * Look the next ";" to start a parameter (skipping whitespace)
130             *
131             * @return
132             */
133            private boolean hasMoreParams() throws MimeTypeParseException {
134                char c;
135                do {
136                    if (index == text.length()) {
137                        return false;
138                    }
139                    c = text.charAt(index++);
140                } while (Character.isWhitespace(c));
141                if (c != ';') {
142                    throw new MimeTypeParseException("Expected \";\" at " + (index - 1) + " in " + text);
143                }
144                return true;
145            }
146    
147            private String expectAttribute() throws MimeTypeParseException {
148                char c;
149                do {
150                    if (index == text.length()) {
151                        throw new MimeTypeParseException("Expected attribute at " + (index - 1) + " in " + text);
152                    }
153                    c = text.charAt(index++);
154                } while (Character.isWhitespace(c));
155                int start = index - 1;
156                while (index != text.length() && !MimeType.isSpecial(text.charAt(index))) {
157                    index += 1;
158                }
159                return text.substring(start, index);
160            }
161    
162            private void expectEquals() throws MimeTypeParseException {
163                char c;
164                do {
165                    if (index == text.length()) {
166                        throw new MimeTypeParseException("Expected \"=\" at " + (index - 1) + " in " + text);
167                    }
168                    c = text.charAt(index++);
169                } while (Character.isWhitespace(c));
170                if (c != '=') {
171                    throw new MimeTypeParseException("Expected \"=\" at " + (index - 1) + " in " + text);
172                }
173            }
174    
175            private String expectValue() throws MimeTypeParseException {
176                char c;
177                do {
178                    if (index == text.length()) {
179                        throw new MimeTypeParseException("Expected value at " + (index - 1) + " in " + text);
180                    }
181                    c = text.charAt(index++);
182                } while (Character.isWhitespace(c));
183                if (c == '"') {
184                    // quoted-string
185                    StringBuffer buf = new StringBuffer();
186                    while (true) {
187                        if (index == text.length()) {
188                            throw new MimeTypeParseException("Expected closing quote at " + (index - 1) + " in " + text);
189                        }
190                        c = text.charAt(index++);
191                        if (c == '"') {
192                            break;
193                        }
194                        if (c == '\\') {
195                            if (index == text.length()) {
196                                throw new MimeTypeParseException("Expected escaped char at " + (index - 1) + " in " + text);
197                            }
198                            c = text.charAt(index++);
199                        }
200                        buf.append(c);
201                    }
202                    return buf.toString();
203                } else {
204                    // token
205                    int start = index - 1;
206                    while (index != text.length() && !MimeType.isSpecial(text.charAt(index))) {
207                        index += 1;
208                    }
209                    return text.substring(start, index);
210                }
211            }
212        }
213    }