100 private String[] myPieces;
101
102 /**
103 * String value for this MIME type. Computed when needed and cached.
104 */
105 private transient String myStringValue = null;
106
107 /**
108 * Parameter map entry set. Computed when needed and cached.
109 */
110 private transient ParameterMapEntrySet myEntrySet = null;
111
112 /**
113 * Parameter map. Computed when needed and cached.
114 */
115 private transient ParameterMap myParameterMap = null;
116
117 /**
118 * Parameter map entry.
119 */
120 private class ParameterMapEntry implements Map.Entry {
121 private int myIndex;
122 public ParameterMapEntry(int theIndex) {
123 myIndex = theIndex;
124 }
125 public Object getKey(){
126 return myPieces[myIndex];
127 }
128 public Object getValue(){
129 return myPieces[myIndex+1];
130 }
131 public Object setValue (Object value) {
132 throw new UnsupportedOperationException();
133 }
134 public boolean equals(Object o) {
135 return (o != null &&
136 o instanceof Map.Entry &&
137 getKey().equals (((Map.Entry) o).getKey()) &&
138 getValue().equals(((Map.Entry) o).getValue()));
139 }
140 public int hashCode() {
141 return getKey().hashCode() ^ getValue().hashCode();
142 }
143 }
144
145 /**
146 * Parameter map entry set iterator.
147 */
148 private class ParameterMapEntrySetIterator implements Iterator {
149 private int myIndex = 2;
150 public boolean hasNext() {
151 return myIndex < myPieces.length;
152 }
153 public Object next() {
154 if (hasNext()) {
155 ParameterMapEntry result = new ParameterMapEntry (myIndex);
156 myIndex += 2;
157 return result;
158 } else {
159 throw new NoSuchElementException();
160 }
161 }
162 public void remove() {
163 throw new UnsupportedOperationException();
164 }
165 }
166
167 /**
168 * Parameter map entry set.
169 */
170 private class ParameterMapEntrySet extends AbstractSet {
171 public Iterator iterator() {
172 return new ParameterMapEntrySetIterator();
173 }
174 public int size() {
175 return (myPieces.length - 2) / 2;
176 }
177 }
178
179 /**
180 * Parameter map.
181 */
182 private class ParameterMap extends AbstractMap {
183 public Set entrySet() {
184 if (myEntrySet == null) {
185 myEntrySet = new ParameterMapEntrySet();
186 }
187 return myEntrySet;
188 }
189 }
190
191 /**
192 * Construct a new MIME type object from the given string. The given
193 * string is converted into canonical form and stored internally.
194 *
195 * @param s MIME media type string.
196 *
197 * @exception NullPointerException
198 * (unchecked exception) Thrown if <CODE>s</CODE> is null.
199 * @exception IllegalArgumentException
200 * (unchecked exception) Thrown if <CODE>s</CODE> does not obey the
201 * syntax for a MIME media type string.
202 */
203 public MimeType(String s) {
217 */
218 public String getMediaType() {
219 return myPieces[0];
220 }
221
222 /**
223 * Returns this MIME type object's media subtype.
224 */
225 public String getMediaSubtype() {
226 return myPieces[1];
227 }
228
229 /**
230 * Returns an unmodifiable map view of the parameters in this MIME type
231 * object. Each entry in the parameter map view consists of a parameter
232 * name String (key) mapping to a parameter value String. If this MIME
233 * type object has no parameters, an empty map is returned.
234 *
235 * @return Parameter map for this MIME type object.
236 */
237 public Map getParameterMap() {
238 if (myParameterMap == null) {
239 myParameterMap = new ParameterMap();
240 }
241 return myParameterMap;
242 }
243
244 /**
245 * Converts this MIME type object to a string.
246 *
247 * @return MIME type string based on the canonical form. Each parameter
248 * value is enclosed in quotes.
249 */
250 public String toString() {
251 return getStringValue();
252 }
253
254 /**
255 * Returns a hash code for this MIME type object.
256 */
257 public int hashCode() {
531 * <UL>
532 * <LI> If the media type is text, the value of a charset parameter is
533 * converted to lowercase.
534 * </UL>
535 *
536 * @param s MIME media type string.
537 *
538 * @exception NullPointerException
539 * (unchecked exception) Thrown if <CODE>s</CODE> is null.
540 * @exception IllegalArgumentException
541 * (unchecked exception) Thrown if <CODE>s</CODE> does not obey the
542 * syntax for a MIME media type string.
543 */
544 private void parse(String s) {
545 // Initialize.
546 if (s == null) {
547 throw new NullPointerException();
548 }
549 LexicalAnalyzer theLexer = new LexicalAnalyzer (s);
550 int theLexemeType;
551 Vector thePieces = new Vector();
552 boolean mediaTypeIsText = false;
553 boolean parameterNameIsCharset = false;
554
555 // Parse media type.
556 if (theLexer.getLexemeType() == TOKEN_LEXEME) {
557 String mt = toUnicodeLowerCase (theLexer.getLexeme());
558 thePieces.add (mt);
559 theLexer.nextLexeme();
560 mediaTypeIsText = mt.equals ("text");
561 } else {
562 throw new IllegalArgumentException();
563 }
564 // Parse slash.
565 if (theLexer.getLexemeType() == TSPECIAL_LEXEME &&
566 theLexer.getLexemeFirstCharacter() == '/') {
567 theLexer.nextLexeme();
568 } else {
569 throw new IllegalArgumentException();
570 }
571 if (theLexer.getLexemeType() == TOKEN_LEXEME) {
606 pv);
607 theLexer.nextLexeme();
608 } else if (theLexer.getLexemeType() == QUOTED_STRING_LEXEME) {
609 String pv = removeBackslashes (theLexer.getLexeme());
610 thePieces.add(mediaTypeIsText && parameterNameIsCharset ?
611 toUnicodeLowerCase (pv) :
612 pv);
613 theLexer.nextLexeme();
614 } else {
615 throw new IllegalArgumentException();
616 }
617 }
618
619 // Make sure we've consumed everything.
620 if (theLexer.getLexemeType() != EOF_LEXEME) {
621 throw new IllegalArgumentException();
622 }
623
624 // Save the pieces. Parameters are not in ascending order yet.
625 int n = thePieces.size();
626 myPieces = (String[]) thePieces.toArray (new String [n]);
627
628 // Sort the parameters into ascending order using an insertion sort.
629 int i, j;
630 String temp;
631 for (i = 4; i < n; i += 2) {
632 j = 2;
633 while (j < i && myPieces[j].compareTo (myPieces[i]) <= 0) {
634 j += 2;
635 }
636 while (j < i) {
637 temp = myPieces[j];
638 myPieces[j] = myPieces[i];
639 myPieces[i] = temp;
640 temp = myPieces[j+1];
641 myPieces[j+1] = myPieces[i+1];
642 myPieces[i+1] = temp;
643 j += 2;
644 }
645 }
646 }
|
100 private String[] myPieces;
101
102 /**
103 * String value for this MIME type. Computed when needed and cached.
104 */
105 private transient String myStringValue = null;
106
107 /**
108 * Parameter map entry set. Computed when needed and cached.
109 */
110 private transient ParameterMapEntrySet myEntrySet = null;
111
112 /**
113 * Parameter map. Computed when needed and cached.
114 */
115 private transient ParameterMap myParameterMap = null;
116
117 /**
118 * Parameter map entry.
119 */
120 private class ParameterMapEntry implements Map.Entry<String, String> {
121 private int myIndex;
122 public ParameterMapEntry(int theIndex) {
123 myIndex = theIndex;
124 }
125 public String getKey(){
126 return myPieces[myIndex];
127 }
128 public String getValue(){
129 return myPieces[myIndex+1];
130 }
131 public String setValue (String value) {
132 throw new UnsupportedOperationException();
133 }
134 public boolean equals(Object o) {
135 return (o != null &&
136 o instanceof Map.Entry &&
137 getKey().equals (((Map.Entry) o).getKey()) &&
138 getValue().equals(((Map.Entry) o).getValue()));
139 }
140 public int hashCode() {
141 return getKey().hashCode() ^ getValue().hashCode();
142 }
143 }
144
145 /**
146 * Parameter map entry set iterator.
147 */
148 private class ParameterMapEntrySetIterator implements Iterator<Map.Entry<String, String>> {
149 private int myIndex = 2;
150 public boolean hasNext() {
151 return myIndex < myPieces.length;
152 }
153 public Map.Entry<String, String> next() {
154 if (hasNext()) {
155 ParameterMapEntry result = new ParameterMapEntry (myIndex);
156 myIndex += 2;
157 return result;
158 } else {
159 throw new NoSuchElementException();
160 }
161 }
162 public void remove() {
163 throw new UnsupportedOperationException();
164 }
165 }
166
167 /**
168 * Parameter map entry set.
169 */
170 private class ParameterMapEntrySet extends AbstractSet<Map.Entry<String, String>> {
171 public Iterator<Map.Entry<String, String>> iterator() {
172 return new ParameterMapEntrySetIterator();
173 }
174 public int size() {
175 return (myPieces.length - 2) / 2;
176 }
177 }
178
179 /**
180 * Parameter map.
181 */
182 private class ParameterMap extends AbstractMap<String, String> {
183 public Set<Map.Entry<String, String>> entrySet() {
184 if (myEntrySet == null) {
185 myEntrySet = new ParameterMapEntrySet();
186 }
187 return myEntrySet;
188 }
189 }
190
191 /**
192 * Construct a new MIME type object from the given string. The given
193 * string is converted into canonical form and stored internally.
194 *
195 * @param s MIME media type string.
196 *
197 * @exception NullPointerException
198 * (unchecked exception) Thrown if <CODE>s</CODE> is null.
199 * @exception IllegalArgumentException
200 * (unchecked exception) Thrown if <CODE>s</CODE> does not obey the
201 * syntax for a MIME media type string.
202 */
203 public MimeType(String s) {
217 */
218 public String getMediaType() {
219 return myPieces[0];
220 }
221
222 /**
223 * Returns this MIME type object's media subtype.
224 */
225 public String getMediaSubtype() {
226 return myPieces[1];
227 }
228
229 /**
230 * Returns an unmodifiable map view of the parameters in this MIME type
231 * object. Each entry in the parameter map view consists of a parameter
232 * name String (key) mapping to a parameter value String. If this MIME
233 * type object has no parameters, an empty map is returned.
234 *
235 * @return Parameter map for this MIME type object.
236 */
237 public Map<String, String> getParameterMap() {
238 if (myParameterMap == null) {
239 myParameterMap = new ParameterMap();
240 }
241 return myParameterMap;
242 }
243
244 /**
245 * Converts this MIME type object to a string.
246 *
247 * @return MIME type string based on the canonical form. Each parameter
248 * value is enclosed in quotes.
249 */
250 public String toString() {
251 return getStringValue();
252 }
253
254 /**
255 * Returns a hash code for this MIME type object.
256 */
257 public int hashCode() {
531 * <UL>
532 * <LI> If the media type is text, the value of a charset parameter is
533 * converted to lowercase.
534 * </UL>
535 *
536 * @param s MIME media type string.
537 *
538 * @exception NullPointerException
539 * (unchecked exception) Thrown if <CODE>s</CODE> is null.
540 * @exception IllegalArgumentException
541 * (unchecked exception) Thrown if <CODE>s</CODE> does not obey the
542 * syntax for a MIME media type string.
543 */
544 private void parse(String s) {
545 // Initialize.
546 if (s == null) {
547 throw new NullPointerException();
548 }
549 LexicalAnalyzer theLexer = new LexicalAnalyzer (s);
550 int theLexemeType;
551 Vector<String> thePieces = new Vector<>();
552 boolean mediaTypeIsText = false;
553 boolean parameterNameIsCharset = false;
554
555 // Parse media type.
556 if (theLexer.getLexemeType() == TOKEN_LEXEME) {
557 String mt = toUnicodeLowerCase (theLexer.getLexeme());
558 thePieces.add (mt);
559 theLexer.nextLexeme();
560 mediaTypeIsText = mt.equals ("text");
561 } else {
562 throw new IllegalArgumentException();
563 }
564 // Parse slash.
565 if (theLexer.getLexemeType() == TSPECIAL_LEXEME &&
566 theLexer.getLexemeFirstCharacter() == '/') {
567 theLexer.nextLexeme();
568 } else {
569 throw new IllegalArgumentException();
570 }
571 if (theLexer.getLexemeType() == TOKEN_LEXEME) {
606 pv);
607 theLexer.nextLexeme();
608 } else if (theLexer.getLexemeType() == QUOTED_STRING_LEXEME) {
609 String pv = removeBackslashes (theLexer.getLexeme());
610 thePieces.add(mediaTypeIsText && parameterNameIsCharset ?
611 toUnicodeLowerCase (pv) :
612 pv);
613 theLexer.nextLexeme();
614 } else {
615 throw new IllegalArgumentException();
616 }
617 }
618
619 // Make sure we've consumed everything.
620 if (theLexer.getLexemeType() != EOF_LEXEME) {
621 throw new IllegalArgumentException();
622 }
623
624 // Save the pieces. Parameters are not in ascending order yet.
625 int n = thePieces.size();
626 myPieces = thePieces.toArray (new String [n]);
627
628 // Sort the parameters into ascending order using an insertion sort.
629 int i, j;
630 String temp;
631 for (i = 4; i < n; i += 2) {
632 j = 2;
633 while (j < i && myPieces[j].compareTo (myPieces[i]) <= 0) {
634 j += 2;
635 }
636 while (j < i) {
637 temp = myPieces[j];
638 myPieces[j] = myPieces[i];
639 myPieces[i] = temp;
640 temp = myPieces[j+1];
641 myPieces[j+1] = myPieces[i+1];
642 myPieces[i+1] = temp;
643 j += 2;
644 }
645 }
646 }
|