1 /* -------------------------------------------------------------------
2 * Java source file for the class MIMEHeader
3 *
4 * Copyright (c), 2002, Masahiro Takatsuka.
5 * All Rights Researved.
6 *
7 * Original Author: Masahiro Takatsuka (masa@jbeans.net)
8 * $Author: takatsukam $
9 *
10 * $Date: 2003/07/25 04:51:47 $
11 *
12 * $Id: MIMEHeader.java,v 1.1.1.1 2003/07/25 04:51:47 takatsukam Exp $
13 *
14 * Reference: Document no:
15 * ___ ___
16 *
17 * To Do:
18 * ___
19 *
20 ------------------------------------------------------------------- */
21
22 /* --------------------------- Package ---------------------------- */
23 package net.jbeans.util.jar;
24
25 /* ------------------ Import classes (packages) ------------------- *//package-summary/html">color="#329900"> ------------------ Import classes (packages) ------------------- *//package-summary.html">color="#329900">/* ------------------ Import classes (packages) ------------------- *//package-summary.html">color="#329900"> ------------------ Import classes (packages) ------------------- */
26 import java.io.*;
27
28 /*====================================================================
29 Implementation of class MIMEHeader
30 ====================================================================*/
31 /***
32 * An RFC 844 or MIME message header. Includes methods for parsing headers
33 * from incoming streams, fetching values, setting values, and printing
34 * headers. Key values of null are legal: they indicate lines in the header
35 * that don't have a valid key, but do have a value (this isn't legal
36 * according to the standard, but lines like this are everywhere).
37 *
38 * @version $Revision: 1.1.1.1 $
39 * @author Masahiro Takatsuka (masa@jbeans.net)
40 */
41
42 final class MIMEHeader {
43 private String[] keys;
44 private String[] values;
45 private int nkeys;
46
47 MIMEHeader () {
48 grow();
49 }
50
51 MIMEHeader (InputStream is) throws java.io.IOException {
52 parseHeader(is);
53 }
54
55 /***
56 * Find the value that corresponds to this key.
57 * It finds only the first occurrence of the key.
58 * @param k the key to find.
59 * @return null if not found.
60 */
61 final String findValue(String k) {
62 if (k == null) {
63 for (int i = this.nkeys; --i >= 0;)
64 if (this.keys[i] == null)
65 return this.values[i];
66 } else
67 for (int i = this.nkeys; --i >= 0;) {
68 if (k.equalsIgnoreCase(this.keys[i]))
69 return this.values[i];
70 }
71 return null;
72 }
73
74 final String getKey(int n) {
75 if (n < 0 || n >= this.nkeys) return null;
76 return this.keys[n];
77 }
78
79 final String getValue(int n) {
80 if (n < 0 || n >= this.nkeys) return null;
81 return this.values[n];
82 }
83
84 /*** Find the next value that corresponds to this key.
85 * It finds the first value that follows v. To iterate
86 * over all the values of a key use:
87 * <pre>
88 * for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
89 * ...
90 * }
91 * </pre>
92 */
93 final String findNextValue(String k, String v) {
94 boolean foundV = false;
95 if (k == null) {
96 for (int i = this.nkeys; --i >= 0;)
97 if (this.keys[i] == null)
98 if (foundV)
99 return this.values[i];
100 else if (this.values[i] == v)
101 foundV = true;
102 } else
103 for (int i = this.nkeys; --i >= 0;)
104 if (k.equalsIgnoreCase(this.keys[i]))
105 if (foundV)
106 return this.values[i];
107 else if (this.values[i] == v)
108 foundV = true;
109 return null;
110 }
111
112 /*** Prints the key-value pairs represented by this
113 header. Also prints the RFC required blank line
114 at the end. Omits pairs with a null key. */
115 final void print(PrintWriter p) {
116 for (int i = 0; i < this.nkeys; i++)
117 if (this.keys[i] != null)
118 p.print(this.keys[i] +
119 (this.values[i] != null ? ": "+this.values[i]: "") + "\r\n");
120 p.print("\r\n");
121 p.flush();
122 }
123
124 /*** Adds a key value pair to the end of the
125 header. Duplicates are allowed */
126 final void add(String k, String v) {
127 grow();
128 this.keys[this.nkeys] = k;
129 this.values[this.nkeys] = v;
130 this.nkeys++;
131 }
132
133 /*** Prepends a key value pair to the beginning of the
134 header. Duplicates are allowed */
135 final void prepend(String k, String v) {
136 grow();
137 for (int i = this.nkeys; i > 0; i--) {
138 this.keys[i] = this.keys[i-1];
139 this.values[i] = this.values[i-1];
140 }
141 this.keys[0] = k;
142 this.values[0] = v;
143 this.nkeys++;
144 }
145
146 /*** Overwrite the previous key/val pair at location 'i'
147 * with the new k/v. If the index didn't exist before
148 * the key/val is simply tacked onto the end.
149 */
150 final void set(int i, String k, String v) {
151 grow();
152 if (i < 0) {
153 return;
154 } else if (i > this.nkeys) {
155 add(k, v);
156 } else {
157 this.keys[i] = k;
158 this.values[i] = v;
159 }
160 }
161
162
163 /*** grow the key/value arrays as needed */
164 void grow() {
165 if (this.keys == null || this.nkeys >= this.keys.length) {
166 String[] nk = new String[this.nkeys + 4];
167 String[] nv = new String[this.nkeys + 4];
168 if (this.keys != null)
169 System.arraycopy(this.keys, 0, nk, 0, this.nkeys);
170 if (this.values != null)
171 System.arraycopy(this.values, 0, nv, 0, this.nkeys);
172 this.keys = nk;
173 this.values = nv;
174 }
175 }
176
177 /*** Sets the value of a key. If the key already
178 exists in the header, it's value will be
179 changed. Otherwise a new key/value pair will
180 be added to the end of the header. */
181 final void set(String k, String v) {
182 for (int i = this.nkeys; --i >= 0;)
183 if (k.equalsIgnoreCase(this.keys[i])) {
184 this.values[i] = v;
185 return;
186 }
187 add(k, v);
188 }
189
190 /*** Convert a message-id string to canonical form (strips off
191 leading and trailing <>s) */
192 final static String canonicalID(String id) {
193 if (id == null)
194 return "";
195 int st = 0;
196 int len = id.length();
197 boolean substr = false;
198 int c;
199 while (st < len && ((c = id.charAt(st)) == '<' ||
200 c <= ' ')) {
201 st++;
202 substr = true;
203 }
204 while (st < len && ((c = id.charAt(len - 1)) == '>' ||
205 c <= ' ')) {
206 len--;
207 substr = true;
208 }
209 return substr ? id.substring(st, len) : id;
210 }
211
212 /*** Parse a MIME header from an input stream. */
213 final void parseHeader(InputStream is) throws java.io.IOException {
214 this.nkeys = 0;
215 if (is == null)
216 return;
217 char s[] = new char[10];
218 int firstc = is.read();
219 while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
220 int len = 0;
221 int keyend = -1;
222 int c;
223 boolean inKey = firstc > ' ';
224 s[len++] = (char) firstc;
225 parseloop:{
226 parseloop2: while ((c = is.read()) >= 0) {
227 switch (c) {
228 case ':':
229 if (inKey && len > 0)
230 keyend = len;
231 inKey = false;
232 break;
233 case '\t':
234 c = ' ';
235 case ' ':
236 inKey = false;
237 break;
238 case '\r':
239 case '\n':
240 firstc = is.read();
241 if (c == '\r' && firstc == '\n') {
242 firstc = is.read();
243 if (firstc == '\r')
244 firstc = is.read();
245 }
246 if (firstc == '\n' || firstc == '\r' || firstc > ' ')
247 break parseloop;
248 /* continuation */
249 continue parseloop2;
250 }
251 if (len >= s.length) {
252 char ns[] = new char[s.length * 2];
253 System.arraycopy(s, 0, ns, 0, len);
254 s = ns;
255 }
256 s[len++] = (char) c;
257 }
258 firstc = -1;
259 }
260 while (len > 0 && s[len - 1] <= ' ')
261 len--;
262 String k;
263 if (keyend <= 0) {
264 k = null;
265 keyend = 0;
266 } else {
267 k = String.copyValueOf(s, 0, keyend);
268 if (keyend < len && s[keyend] == ':')
269 keyend++;
270 while (keyend < len && s[keyend] <= ' ')
271 keyend++;
272 }
273 String v;
274 if (keyend >= len)
275 v = new String();
276 else
277 v = String.copyValueOf(s, keyend, len - keyend);
278 add(k, v);
279 }
280 }
281
282 public final String toString() {
283 String result = super.toString();
284 for (int i = 0; i < this.keys.length; i++) {
285 result += "{"+this.keys[i]+": "+this.values[i]+"}";
286 }
287 return result;
288 }
289 }
This page was automatically generated by Maven