001    /* MimeType.java -- A MIME type as defined in RFC2046 and RFC2047.
002       Copyright (C) 2004 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.activation;
039    
040    import gnu.java.lang.CPStringBuilder;
041    
042    import java.io.Externalizable;
043    import java.io.IOException;
044    import java.io.ObjectInput;
045    import 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     */
053    public 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    }
293