001/* MimeType.java -- A MIME type as defined in RFC2046 and RFC2047.
002   Copyright (C) 2004 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package javax.activation;
039
040import gnu.java.lang.CPStringBuilder;
041
042import java.io.Externalizable;
043import java.io.IOException;
044import java.io.ObjectInput;
045import java.io.ObjectOutput;
046
047/**
048 * A MIME content type, as defined in RFCs 2045 and 2046.
049 *
050 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
051 * @version 1.1
052 */
053public class MimeType
054  implements Externalizable
055{
056
057  static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
058
059  private String primaryType;
060  private String subType;
061  private MimeTypeParameterList parameters;
062
063  /**
064   * Constructor for an <code>application/*</code> content type.
065   */
066  public MimeType()
067  {
068    primaryType = "application";
069    subType = "*";
070    parameters = new MimeTypeParameterList();
071  }
072
073  /**
074   * Constructor that parses a raw String.
075   * @param rawdata the MIME type string
076   */
077  public MimeType(String rawdata)
078    throws MimeTypeParseException
079  {
080    parse(rawdata);
081  }
082
083  /**
084   * Constructor for a new MIME type with the given primary and sub types
085   * and an empty parameter list.
086   * @param primary the primary type
087   * @param sub the subtype
088   */
089  public MimeType(String primary, String sub)
090    throws MimeTypeParseException
091  {
092    checkValidity(primary, "Primary type is invalid");
093    checkValidity(sub, "Sub type is invalid");
094    primaryType = primary.toLowerCase();
095    subType = sub.toLowerCase();
096    parameters = new MimeTypeParameterList();
097  }
098
099  /**
100   * Returns the primary type.
101   */
102  public String getPrimaryType()
103  {
104    return primaryType;
105  }
106
107  /**
108   * Sets the primary type.
109   * @param primary the new primary type
110   */
111  public void setPrimaryType(String primary)
112    throws MimeTypeParseException
113  {
114    checkValidity(primary, "Primary type is invalid");
115    primaryType = primary.toLowerCase();
116  }
117
118  /**
119   * Returns the subtype.
120   */
121  public String getSubType()
122  {
123    return subType;
124  }
125
126  /**
127   * Sets the subtype.
128   * @param sub the new subtype
129   */
130  public void setSubType(String sub)
131    throws MimeTypeParseException
132  {
133    checkValidity(sub, "Sub type is invalid");
134    subType = sub.toLowerCase();
135  }
136
137  /**
138   * Returns the MIME parameters.
139   */
140  public MimeTypeParameterList getParameters()
141  {
142    return parameters;
143  }
144
145  /**
146   * Returns the parameter value for the specified name.
147   * @param name the parameter name
148   */
149  public String getParameter(String name)
150  {
151    return parameters.get(name);
152  }
153
154  /**
155   * Sets the parameter value for the specified name.
156   * @param name the parameter name
157   * @param value the new value
158   */
159  public void setParameter(String name, String value)
160  {
161    parameters.set(name, value);
162  }
163
164  /**
165   * Removes the parameter value for the specified name.
166   * @param name the parameter name
167   */
168  public void removeParameter(String name)
169  {
170    parameters.remove(name);
171  }
172
173  /**
174   * Returns the complete string representation of this MIME type.
175   */
176  public String toString()
177  {
178    return new CPStringBuilder(primaryType)
179      .append('/')
180      .append(subType)
181      .append(parameters.toString())
182      .toString();
183  }
184
185  /**
186   * Returns the string representation of this MIME type without
187   * parameters.
188   */
189  public String getBaseType()
190  {
191    return new CPStringBuilder(primaryType)
192      .append('/')
193      .append(subType)
194      .toString();
195  }
196
197  /**
198   * Returns true if the primary and subtype of this MIME type are the
199   * same as in the given MIME type.
200   */
201  public boolean match(MimeType type)
202  {
203    String primary2 = type.getPrimaryType();
204    String sub2 = type.getSubType();
205    return primaryType.equals(primary2) && (subType.equals(sub2) ||
206                                            "*".equals(subType) ||
207                                            "*".equals(sub2));
208  }
209
210  /**
211   * Returns true if the primary and subtype of this MIME type are the
212   * same as in the given MIME type string.
213   */
214  public boolean match(String rawdata)
215    throws MimeTypeParseException
216  {
217    return match(new MimeType(rawdata));
218  }
219
220  public void writeExternal(ObjectOutput out)
221    throws IOException
222  {
223    out.writeUTF(toString());
224    out.flush();
225  }
226
227  public void readExternal(ObjectInput in)
228    throws IOException, ClassNotFoundException
229  {
230    try
231      {
232        parse(in.readUTF());
233      }
234    catch (MimeTypeParseException e)
235      {
236        throw new IOException(e.getMessage());
237      }
238  }
239
240  private void parse(String rawdata)
241    throws MimeTypeParseException
242  {
243    int si = rawdata.indexOf('/');
244    int pi = rawdata.indexOf(';');
245    if (si == -1)
246      {
247        throw new MimeTypeParseException("Unable to find a sub type.");
248      }
249    if (pi == -1)
250      {
251        primaryType = rawdata.substring(0, si).toLowerCase().trim();
252        subType = rawdata.substring(si + 1).toLowerCase().trim();
253        parameters = new MimeTypeParameterList();
254      }
255    else if (si < pi)
256      {
257        primaryType = rawdata.substring(0, si).toLowerCase().trim();
258        subType = rawdata.substring(si + 1, pi).toLowerCase().trim();
259        parameters = new MimeTypeParameterList(rawdata.substring(pi));
260      }
261    else
262      {
263        throw new MimeTypeParseException("Unable to find a sub type.");
264      }
265    checkValidity(primaryType, "Primary type is invalid");
266    checkValidity(subType, "Sub type is invalid");
267  }
268
269  static void checkValidity(String token, String message)
270    throws MimeTypeParseException
271  {
272    int len = token.length();
273    if (len == 0)
274      {
275        throw new MimeTypeParseException(message, token);
276      }
277    for (int i = 0; i < len; i++)
278      {
279        char c = token.charAt(i);
280        if (!isValidChar(c))
281          {
282            throw new MimeTypeParseException(message, token);
283          }
284      }
285  }
286
287  static boolean isValidChar(char c)
288  {
289    return c > ' ' && c <= '~' && TSPECIALS.indexOf(c) == -1;
290  }
291
292}